[med-svn] [libsdsl] 01/02: Imported Upstream version 2.0.3+dfsg
Andreas Tille
tille at debian.org
Fri Apr 8 15:23:44 UTC 2016
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository libsdsl.
commit 7a2024b13f8a4636c46af6e2182deac90747f0d2
Author: Andreas Tille <tille at debian.org>
Date: Fri Apr 8 17:09:13 2016 +0200
Imported Upstream version 2.0.3+dfsg
---
.gitignore | 1 +
CMakeLists.txt | 77 +
CMakeModules/AppendCompilerFlags.cmake | 38 +
CMakeModules/CheckSSE4_2.cmake | 24 +
CMakeModules/cmake_uninstall.cmake.in | 36 +
COPYING | 16 +
Make.helper.cmake | 26 +
README.md | 280 +
VERSION | 1 +
benchmark/Make.download | 12 +
benchmark/Make.helper | 18 +
benchmark/README.md | 59 +
benchmark/basic_functions.R | 176 +
benchmark/data/.gitignore | 3 +
benchmark/document_retrieval/Makefile | 316 +
benchmark/document_retrieval/README.md | 100 +
benchmark/document_retrieval/bin/.gitignore | 2 +
benchmark/document_retrieval/dic.config | 9 +
benchmark/document_retrieval/dic/.gitignore | 2 +
benchmark/document_retrieval/index.config | 12 +
benchmark/document_retrieval/index_int.config | 10 +
benchmark/document_retrieval/indexes/.gitignore | 2 +
benchmark/document_retrieval/info/.gitignore | 2 +
benchmark/document_retrieval/pattern/.gitignore | 2 +
benchmark/document_retrieval/pattern_length.config | 19 +
.../document_retrieval/pattern_length_int.config | 10 +
benchmark/document_retrieval/results/.gitignore | 2 +
benchmark/document_retrieval/src/build_idx.cpp | 34 +
.../document_retrieval/src/doc_list_index.hpp | 22 +
.../src/doc_list_index_greedy.hpp | 238 +
.../src/doc_list_index_qprobing.hpp | 124 +
.../document_retrieval/src/doc_list_index_sada.hpp | 410 +
.../document_retrieval/src/doc_list_index_sort.hpp | 185 +
benchmark/document_retrieval/src/gen_pattern.cpp | 82 +
benchmark/document_retrieval/src/query_idx.cpp | 94 +
benchmark/document_retrieval/src/size_of_idx.cpp | 30 +
.../document_retrieval/src/word_pat2char_pat.cpp | 46 +
benchmark/document_retrieval/test_case.config | 8 +
benchmark/document_retrieval/test_case_int.config | 6 +
benchmark/document_retrieval/visualize/.gitignore | 11 +
benchmark/document_retrieval/visualize/Makefile | 28 +
.../document_retrieval/visualize/doc_re_time.tex | 61 +
.../visualize/index-filter.config | 10 +
.../visualize/index-filter_int.config | 10 +
benchmark/document_retrieval/visualize/runtime.R | 171 +
benchmark/indexing_count/Makefile | 134 +
benchmark/indexing_count/README.md | 82 +
benchmark/indexing_count/bin/.gitignore | 5 +
benchmark/indexing_count/compile_options.config | 10 +
benchmark/indexing_count/index.config | 14 +
benchmark/indexing_count/indexes/.gitignore | 5 +
benchmark/indexing_count/info/.gitignore | 5 +
benchmark/indexing_count/pattern/.gitignore | 5 +
benchmark/indexing_count/results/.gitignore | 2 +
benchmark/indexing_count/src/build_index_sdsl.cpp | 23 +
benchmark/indexing_count/src/genpatterns.c | 214 +
benchmark/indexing_count/src/info.cpp | 21 +
benchmark/indexing_count/src/interface.h | 96 +
benchmark/indexing_count/src/run_queries_sdsl.cpp | 285 +
benchmark/indexing_count/test_case.config | 16 +
benchmark/indexing_count/visualize/.gitignore | 7 +
benchmark/indexing_count/visualize/Makefile | 19 +
.../indexing_count/visualize/count-footer.tex | 1 +
.../indexing_count/visualize/count-header.tex | 6 +
benchmark/indexing_count/visualize/count.R | 130 +
.../indexing_count/visualize/index-filter.config | 10 +
benchmark/indexing_extract/Makefile | 159 +
benchmark/indexing_extract/README.md | 99 +
benchmark/indexing_extract/bin/.gitignore | 2 +
benchmark/indexing_extract/index.config | 12 +
benchmark/indexing_extract/indexes/.gitignore | 2 +
benchmark/indexing_extract/info/.gitignore | 2 +
benchmark/indexing_extract/intervals/.gitignore | 2 +
benchmark/indexing_extract/results/.gitignore | 2 +
benchmark/indexing_extract/sample.config | 12 +
.../indexing_extract/src/build_index_sdsl.cpp | 23 +
benchmark/indexing_extract/src/genintervals.c | 133 +
benchmark/indexing_extract/src/info.cpp | 19 +
benchmark/indexing_extract/src/interface.h | 96 +
.../indexing_extract/src/run_queries_sdsl.cpp | 330 +
benchmark/indexing_extract/test_case.config | 10 +
benchmark/indexing_extract/visualize/.gitignore | 6 +
benchmark/indexing_extract/visualize/Makefile | 16 +
benchmark/indexing_extract/visualize/extract.R | 76 +
benchmark/indexing_extract/visualize/extract.tex | 23 +
.../indexing_extract/visualize/index-filter.config | 11 +
benchmark/indexing_locate/Makefile | 159 +
benchmark/indexing_locate/README.md | 97 +
benchmark/indexing_locate/bin/.gitignore | 2 +
benchmark/indexing_locate/index.config | 12 +
benchmark/indexing_locate/indexes/.gitignore | 5 +
benchmark/indexing_locate/info/.gitignore | 5 +
benchmark/indexing_locate/pattern/.gitignore | 2 +
benchmark/indexing_locate/results/.gitignore | 2 +
benchmark/indexing_locate/sample.config | 12 +
benchmark/indexing_locate/src/build_index_sdsl.cpp | 23 +
benchmark/indexing_locate/src/info.cpp | 21 +
benchmark/indexing_locate/src/interface.h | 96 +
benchmark/indexing_locate/src/pattern_random.cpp | 67 +
benchmark/indexing_locate/src/run_queries_sdsl.cpp | 333 +
benchmark/indexing_locate/test_case.config | 10 +
benchmark/indexing_locate/visualize/.gitignore | 6 +
benchmark/indexing_locate/visualize/Makefile | 16 +
.../indexing_locate/visualize/index-filter.config | 11 +
benchmark/indexing_locate/visualize/locate.R | 76 +
benchmark/indexing_locate/visualize/locate.tex | 23 +
benchmark/lcp/.gitignore | 11 +
benchmark/lcp/Makefile | 67 +
benchmark/lcp/README.md | 53 +
benchmark/lcp/bin/.gitignore | 2 +
benchmark/lcp/compile_options.config | 2 +
benchmark/lcp/lcp.config | 14 +
benchmark/lcp/results/.gitignore | 2 +
benchmark/lcp/src/.gitignore | 4 +
benchmark/lcp/src/create_lcp.cpp | 34 +
benchmark/lcp/src/create_sa_bwt.cpp | 71 +
benchmark/lcp/test_case.config | 16 +
benchmark/lcp/visualize/.gitignore | 6 +
benchmark/lcp/visualize/Makefile | 17 +
benchmark/lcp/visualize/lcp-footer.tex | 1 +
benchmark/lcp/visualize/lcp-header.tex | 8 +
benchmark/lcp/visualize/lcp.R | 77 +
benchmark/rrr_vector/Makefile | 81 +
benchmark/rrr_vector/README.md | 68 +
benchmark/rrr_vector/bin/.gitignore | 2 +
benchmark/rrr_vector/block_size.config | 27 +
benchmark/rrr_vector/compile_options.config | 6 +
benchmark/rrr_vector/results/.gitignore | 2 +
.../rrr_vector/src/generate_rnd_bitvector.cpp | 47 +
benchmark/rrr_vector/src/rrr_time_and_space.cpp | 103 +
benchmark/rrr_vector/test_case.config | 10 +
benchmark/rrr_vector/visualize/.gitignore | 6 +
benchmark/rrr_vector/visualize/Makefile | 17 +
benchmark/rrr_vector/visualize/rrr-footer.tex | 1 +
benchmark/rrr_vector/visualize/rrr-header.tex | 6 +
benchmark/rrr_vector/visualize/rrr.R | 171 +
benchmark/self_delimiting_codes/Makefile | 67 +
benchmark/self_delimiting_codes/README.md | 55 +
benchmark/self_delimiting_codes/bin/.gitignore | 2 +
.../self_delimiting_codes/compile_options.config | 2 +
benchmark/self_delimiting_codes/results/.gitignore | 2 +
.../self_delimiting_codes/src/sdc_benchmark.cpp | 239 +
benchmark/self_delimiting_codes/test_case.config | 19 +
benchmark/self_delimiting_codes/vectors.config | 18 +
benchmark/self_delimiting_codes/visualize/Makefile | 31 +
.../visualize/self_delimiting_codes.tex | 91 +
.../self_delimiting_codes/visualize/testcase.tex | 63 +
benchmark/tmp/.gitignore | 2 +
benchmark/wavelet_trees/Makefile | 83 +
benchmark/wavelet_trees/README.md | 59 +
benchmark/wavelet_trees/bin/.gitignore | 2 +
benchmark/wavelet_trees/compile_options.config | 2 +
benchmark/wavelet_trees/results/.gitignore | 2 +
benchmark/wavelet_trees/src/gen_bwt.cpp | 50 +
benchmark/wavelet_trees/src/wt_time_and_space.cpp | 288 +
benchmark/wavelet_trees/test_case.config | 32 +
benchmark/wavelet_trees/visualize/.gitignore | 6 +
benchmark/wavelet_trees/visualize/Makefile | 17 +
benchmark/wavelet_trees/visualize/wt-footer.tex | 1 +
benchmark/wavelet_trees/visualize/wt-header.tex | 10 +
benchmark/wavelet_trees/visualize/wt.R | 198 +
benchmark/wavelet_trees/wt.config | 66 +
build/.gitignore | 4 +
build/build.sh | 8 +
build/clean.sh | 7 +
examples/.gitignore | 4 +
examples/Makefile | 16 +
examples/bit-vector.cpp | 46 +
examples/c++11-initializer-list.cpp | 24 +
examples/construct-in-memory.cpp | 53 +
examples/csa-alphabet-strategy.cpp | 49 +
examples/cst-bfs-iterator.cpp | 28 +
examples/cst-node-child-iterator.cpp | 33 +
examples/fm-index.cpp | 87 +
examples/fm-rmq-index.cpp | 143 +
examples/hugepages.cpp | 44 +
examples/int-vector-buffer-iterator.cpp | 22 +
examples/int-vector-buffer.cpp | 61 +
examples/int-vector-entry.cpp | 40 +
examples/int-vector-mapper.cpp | 88 +
examples/intersect.cpp | 21 +
examples/k2_treap_in_mem.cpp | 53 +
examples/louds-tree.cpp | 55 +
examples/memory-visualization.cpp | 50 +
examples/node_iterator.cpp | 39 +
examples/range-minimum-queries.cpp | 51 +
examples/sa-construct-space-efficient.cpp | 43 +
examples/sa-int-construct-from-file.cpp | 44 +
examples/sd_vector_benchmark.cpp | 122 +
examples/storage-visualization.cpp | 26 +
examples/store_to_file.cpp | 44 +
examples/text-statistics.cpp | 41 +
examples/uint64-array2int_vector.cpp | 75 +
examples/write_structure.cpp | 19 +
external/CMakeLists.txt | 4 +
external/gtest-1.6.0/.gitignore | 5 +
external/gtest-1.6.0/CHANGES | 153 +
external/gtest-1.6.0/CMakeLists.txt | 255 +
external/gtest-1.6.0/CONTRIBUTORS | 37 +
external/gtest-1.6.0/LICENSE | 28 +
external/gtest-1.6.0/Makefile.am | 305 +
external/gtest-1.6.0/README | 435 ++
external/gtest-1.6.0/build-aux/.keep | 0
external/gtest-1.6.0/build/.gitignore | 2 +
external/gtest-1.6.0/cmake/internal_utils.cmake | 227 +
external/gtest-1.6.0/codegear/gtest.cbproj | 138 +
external/gtest-1.6.0/codegear/gtest.groupproj | 54 +
external/gtest-1.6.0/codegear/gtest_all.cc | 38 +
external/gtest-1.6.0/codegear/gtest_link.cc | 40 +
external/gtest-1.6.0/codegear/gtest_main.cbproj | 82 +
.../gtest-1.6.0/codegear/gtest_unittest.cbproj | 88 +
external/gtest-1.6.0/configure.ac | 68 +
external/gtest-1.6.0/include/CMakeLists.txt | 2 +
external/gtest-1.6.0/include/gtest/CMakeLists.txt | 8 +
.../gtest-1.6.0/include/gtest/gtest-death-test.h | 298 +
external/gtest-1.6.0/include/gtest/gtest-message.h | 255 +
.../gtest-1.6.0/include/gtest/gtest-param-test.h | 1494 ++++
.../include/gtest/gtest-param-test.h.pump | 487 ++
.../gtest-1.6.0/include/gtest/gtest-printers.h | 910 +++
external/gtest-1.6.0/include/gtest/gtest-spi.h | 236 +
.../gtest-1.6.0/include/gtest/gtest-test-part.h | 185 +
.../gtest-1.6.0/include/gtest/gtest-typed-test.h | 263 +
external/gtest-1.6.0/include/gtest/gtest.h | 2319 ++++++
.../gtest-1.6.0/include/gtest/gtest_pred_impl.h | 363 +
external/gtest-1.6.0/include/gtest/gtest_prod.h | 58 +
.../include/gtest/internal/CMakeLists.txt | 7 +
.../gtest/internal/gtest-death-test-internal.h | 326 +
.../include/gtest/internal/gtest-filepath.h | 209 +
.../include/gtest/internal/gtest-internal.h | 1172 +++
.../include/gtest/internal/gtest-linked_ptr.h | 240 +
.../gtest/internal/gtest-param-util-generated.h | 5270 +++++++++++++
.../internal/gtest-param-util-generated.h.pump | 301 +
.../include/gtest/internal/gtest-param-util.h | 635 ++
.../include/gtest/internal/gtest-port.h | 1995 +++++
.../include/gtest/internal/gtest-string.h | 170 +
.../include/gtest/internal/gtest-tuple.h | 1051 +++
.../include/gtest/internal/gtest-tuple.h.pump | 339 +
.../include/gtest/internal/gtest-type-util.h | 3335 ++++++++
.../include/gtest/internal/gtest-type-util.h.pump | 297 +
external/gtest-1.6.0/m4/acx_pthread.m4 | 363 +
external/gtest-1.6.0/m4/gtest.m4 | 74 +
external/gtest-1.6.0/make/Makefile | 82 +
external/gtest-1.6.0/msvc/gtest-md.sln | 45 +
external/gtest-1.6.0/msvc/gtest-md.vcproj | 126 +
external/gtest-1.6.0/msvc/gtest.sln | 45 +
external/gtest-1.6.0/msvc/gtest.vcproj | 126 +
external/gtest-1.6.0/msvc/gtest_main-md.vcproj | 129 +
external/gtest-1.6.0/msvc/gtest_main.vcproj | 129 +
.../gtest-1.6.0/msvc/gtest_prod_test-md.vcproj | 164 +
external/gtest-1.6.0/msvc/gtest_prod_test.vcproj | 164 +
external/gtest-1.6.0/msvc/gtest_unittest-md.vcproj | 147 +
external/gtest-1.6.0/msvc/gtest_unittest.vcproj | 147 +
external/gtest-1.6.0/samples/prime_tables.h | 126 +
external/gtest-1.6.0/samples/sample1.cc | 70 +
external/gtest-1.6.0/samples/sample1.h | 43 +
external/gtest-1.6.0/samples/sample10_unittest.cc | 150 +
external/gtest-1.6.0/samples/sample1_unittest.cc | 159 +
external/gtest-1.6.0/samples/sample2.cc | 58 +
external/gtest-1.6.0/samples/sample2.h | 86 +
external/gtest-1.6.0/samples/sample2_unittest.cc | 113 +
external/gtest-1.6.0/samples/sample3-inl.h | 174 +
external/gtest-1.6.0/samples/sample3_unittest.cc | 155 +
external/gtest-1.6.0/samples/sample4.cc | 48 +
external/gtest-1.6.0/samples/sample4.h | 54 +
external/gtest-1.6.0/samples/sample4_unittest.cc | 46 +
external/gtest-1.6.0/samples/sample5_unittest.cc | 206 +
external/gtest-1.6.0/samples/sample6_unittest.cc | 234 +
external/gtest-1.6.0/samples/sample7_unittest.cc | 136 +
external/gtest-1.6.0/samples/sample8_unittest.cc | 178 +
external/gtest-1.6.0/samples/sample9_unittest.cc | 166 +
external/gtest-1.6.0/scripts/fuse_gtest_files.py | 250 +
.../gtest-1.6.0/scripts/gen_gtest_pred_impl.py | 730 ++
external/gtest-1.6.0/scripts/gtest-config.in | 274 +
external/gtest-1.6.0/scripts/pump.py | 855 +++
external/gtest-1.6.0/scripts/test/Makefile | 59 +
external/gtest-1.6.0/scripts/upload.py | 1387 ++++
external/gtest-1.6.0/scripts/upload_gtest.py | 78 +
external/gtest-1.6.0/src/gtest-all.cc | 48 +
external/gtest-1.6.0/src/gtest-death-test.cc | 1388 ++++
external/gtest-1.6.0/src/gtest-filepath.cc | 402 +
external/gtest-1.6.0/src/gtest-internal-inl.h | 1243 +++
external/gtest-1.6.0/src/gtest-port.cc | 850 +++
external/gtest-1.6.0/src/gtest-printers.cc | 388 +
external/gtest-1.6.0/src/gtest-test-part.cc | 120 +
external/gtest-1.6.0/src/gtest-typed-test.cc | 114 +
external/gtest-1.6.0/src/gtest.cc | 5253 +++++++++++++
external/gtest-1.6.0/src/gtest_main.cc | 39 +
.../gtest-1.6.0/test/gtest-death-test_ex_test.cc | 98 +
external/gtest-1.6.0/test/gtest-death-test_test.cc | 1467 ++++
external/gtest-1.6.0/test/gtest-filepath_test.cc | 753 ++
external/gtest-1.6.0/test/gtest-linked_ptr_test.cc | 159 +
external/gtest-1.6.0/test/gtest-listener_test.cc | 319 +
external/gtest-1.6.0/test/gtest-message_test.cc | 177 +
external/gtest-1.6.0/test/gtest-options_test.cc | 232 +
.../gtest-1.6.0/test/gtest-param-test2_test.cc | 65 +
external/gtest-1.6.0/test/gtest-param-test_test.cc | 965 +++
external/gtest-1.6.0/test/gtest-param-test_test.h | 59 +
external/gtest-1.6.0/test/gtest-port_test.cc | 1370 ++++
external/gtest-1.6.0/test/gtest-printers_test.cc | 1718 +++++
external/gtest-1.6.0/test/gtest-test-part_test.cc | 225 +
external/gtest-1.6.0/test/gtest-tuple_test.cc | 342 +
.../gtest-1.6.0/test/gtest-typed-test2_test.cc | 45 +
external/gtest-1.6.0/test/gtest-typed-test_test.cc | 384 +
external/gtest-1.6.0/test/gtest-typed-test_test.h | 69 +
.../gtest-1.6.0/test/gtest-unittest-api_test.cc | 350 +
external/gtest-1.6.0/test/gtest_all_test.cc | 47 +
.../test/gtest_break_on_failure_unittest.py | 218 +
.../test/gtest_break_on_failure_unittest_.cc | 92 +
.../test/gtest_catch_exceptions_test.py | 223 +
.../test/gtest_catch_exceptions_test_.cc | 332 +
external/gtest-1.6.0/test/gtest_color_test.py | 130 +
external/gtest-1.6.0/test/gtest_color_test_.cc | 73 +
external/gtest-1.6.0/test/gtest_env_var_test.py | 103 +
external/gtest-1.6.0/test/gtest_env_var_test_.cc | 130 +
.../gtest-1.6.0/test/gtest_environment_test.cc | 199 +
external/gtest-1.6.0/test/gtest_filter_unittest.py | 633 ++
.../gtest-1.6.0/test/gtest_filter_unittest_.cc | 162 +
external/gtest-1.6.0/test/gtest_help_test.py | 172 +
external/gtest-1.6.0/test/gtest_help_test_.cc | 47 +
.../gtest-1.6.0/test/gtest_list_tests_unittest.py | 207 +
.../gtest-1.6.0/test/gtest_list_tests_unittest_.cc | 182 +
external/gtest-1.6.0/test/gtest_main_unittest.cc | 47 +
.../gtest-1.6.0/test/gtest_no_test_unittest.cc | 57 +
external/gtest-1.6.0/test/gtest_output_test.py | 335 +
external/gtest-1.6.0/test/gtest_output_test_.cc | 1117 +++
.../test/gtest_output_test_golden_lin.txt | 720 ++
.../gtest-1.6.0/test/gtest_pred_impl_unittest.cc | 2613 +++++++
external/gtest-1.6.0/test/gtest_prod_test.cc | 59 +
external/gtest-1.6.0/test/gtest_repeat_test.cc | 268 +
external/gtest-1.6.0/test/gtest_shuffle_test.py | 325 +
external/gtest-1.6.0/test/gtest_shuffle_test_.cc | 106 +
.../gtest-1.6.0/test/gtest_sole_header_test.cc | 61 +
external/gtest-1.6.0/test/gtest_stress_test.cc | 276 +
external/gtest-1.6.0/test/gtest_test_utils.py | 305 +
.../test/gtest_throw_on_failure_ex_test.cc | 95 +
.../test/gtest_throw_on_failure_test.py | 171 +
.../test/gtest_throw_on_failure_test_.cc | 74 +
.../gtest-1.6.0/test/gtest_uninitialized_test.py | 70 +
.../gtest-1.6.0/test/gtest_uninitialized_test_.cc | 45 +
external/gtest-1.6.0/test/gtest_unittest.cc | 7951 ++++++++++++++++++++
.../gtest-1.6.0/test/gtest_xml_outfile1_test_.cc | 51 +
.../gtest-1.6.0/test/gtest_xml_outfile2_test_.cc | 51 +
.../gtest-1.6.0/test/gtest_xml_outfiles_test.py | 132 +
.../gtest-1.6.0/test/gtest_xml_output_unittest.py | 307 +
.../gtest-1.6.0/test/gtest_xml_output_unittest_.cc | 203 +
external/gtest-1.6.0/test/gtest_xml_test_utils.py | 194 +
external/gtest-1.6.0/test/production.cc | 36 +
external/gtest-1.6.0/test/production.h | 56 +
.../gtest-1.6.0/xcode/Config/DebugProject.xcconfig | 30 +
.../xcode/Config/FrameworkTarget.xcconfig | 17 +
external/gtest-1.6.0/xcode/Config/General.xcconfig | 41 +
.../xcode/Config/ReleaseProject.xcconfig | 32 +
.../xcode/Config/StaticLibraryTarget.xcconfig | 18 +
.../gtest-1.6.0/xcode/Config/TestTarget.xcconfig | 8 +
external/gtest-1.6.0/xcode/Resources/Info.plist | 30 +
.../xcode/Samples/FrameworkSample/Info.plist | 28 +
.../WidgetFramework.xcodeproj/project.pbxproj | 457 ++
.../xcode/Samples/FrameworkSample/runtests.sh | 62 +
.../xcode/Samples/FrameworkSample/widget.cc | 67 +
.../xcode/Samples/FrameworkSample/widget.h | 60 +
.../xcode/Samples/FrameworkSample/widget_test.cc | 70 +
external/gtest-1.6.0/xcode/Scripts/runtests.sh | 65 +
.../gtest-1.6.0/xcode/Scripts/versiongenerate.py | 100 +
.../xcode/gtest.xcodeproj/project.pbxproj | 1084 +++
extras/README.md | 26 +
extras/cheatsheet/.gitignore | 6 +
extras/cheatsheet/Makefile | 7 +
extras/cheatsheet/hyperendnotes.sty | 156 +
extras/cheatsheet/sdsl-cheatsheet.tex | 774 ++
extras/cheatsheet/viz.pdf | Bin 0 -> 22030 bytes
extras/literature.bib | 569 ++
extras/pre-commit | 86 +
extras/resources/space-vis.png | Bin 0 -> 51338 bytes
extras/sdsl.gdb | 70 +
extras/sdsl_definitions.sty | 13 +
include/CMakeLists.txt | 1 +
include/sdsl/.gitignore | 6 +
include/sdsl/CMakeLists.txt | 17 +
include/sdsl/bit_vector_il.hpp | 488 ++
include/sdsl/bit_vectors.hpp | 13 +
include/sdsl/bits.hpp | 624 ++
include/sdsl/bp_support.hpp | 41 +
include/sdsl/bp_support_algorithm.hpp | 304 +
include/sdsl/bp_support_g.hpp | 650 ++
include/sdsl/bp_support_gg.hpp | 545 ++
include/sdsl/bp_support_sada.hpp | 894 +++
include/sdsl/coder.hpp | 77 +
include/sdsl/coder_comma.hpp | 319 +
include/sdsl/coder_elias_delta.hpp | 255 +
include/sdsl/coder_elias_gamma.hpp | 252 +
include/sdsl/coder_fibonacci.hpp | 416 +
include/sdsl/config.hpp | 61 +
include/sdsl/construct.hpp | 208 +
include/sdsl/construct_bwt.hpp | 82 +
include/sdsl/construct_config.hpp | 19 +
include/sdsl/construct_isa.hpp | 38 +
include/sdsl/construct_lcp.hpp | 287 +
include/sdsl/construct_lcp_helper.hpp | 89 +
include/sdsl/construct_sa.hpp | 174 +
include/sdsl/construct_sa_se.hpp | 696 ++
include/sdsl/csa_alphabet_strategy.hpp | 563 ++
include/sdsl/csa_bitcompressed.hpp | 312 +
include/sdsl/csa_sada.hpp | 465 ++
include/sdsl/csa_sampling_strategy.hpp | 392 +
include/sdsl/csa_wt.hpp | 384 +
include/sdsl/cst_iterators.hpp | 343 +
include/sdsl/cst_sada.hpp | 796 ++
include/sdsl/cst_sct3.hpp | 1238 +++
include/sdsl/dac_vector.hpp | 382 +
include/sdsl/enc_vector.hpp | 352 +
include/sdsl/fast_cache.hpp | 39 +
include/sdsl/int_vector.hpp | 1446 ++++
include/sdsl/int_vector_buffer.hpp | 530 ++
include/sdsl/int_vector_io_wrappers.hpp | 190 +
include/sdsl/int_vector_mapper.hpp | 288 +
include/sdsl/inv_perm_support.hpp | 219 +
include/sdsl/io.hpp | 801 ++
include/sdsl/iterators.hpp | 153 +
include/sdsl/k2_treap.hpp | 447 ++
include/sdsl/k2_treap_algorithm.hpp | 412 +
include/sdsl/k2_treap_helper.hpp | 185 +
include/sdsl/lcp.hpp | 225 +
include/sdsl/lcp_bitcompressed.hpp | 134 +
include/sdsl/lcp_byte.hpp | 192 +
include/sdsl/lcp_dac.hpp | 42 +
include/sdsl/lcp_support_sada.hpp | 238 +
include/sdsl/lcp_support_tree.hpp | 157 +
include/sdsl/lcp_support_tree2.hpp | 290 +
include/sdsl/lcp_vlc.hpp | 143 +
include/sdsl/lcp_wt.hpp | 199 +
include/sdsl/louds_tree.hpp | 206 +
include/sdsl/memory_management.hpp | 343 +
include/sdsl/nearest_neighbour_dictionary.hpp | 270 +
include/sdsl/nn_dict_dynamic.hpp | 363 +
include/sdsl/qsufsort.hpp | 512 ++
include/sdsl/ram_filebuf.hpp | 56 +
include/sdsl/ram_fs.hpp | 81 +
include/sdsl/rank_support.hpp | 208 +
include/sdsl/rank_support_scan.hpp | 100 +
include/sdsl/rank_support_v.hpp | 162 +
include/sdsl/rank_support_v5.hpp | 169 +
include/sdsl/rmq_succinct_sada.hpp | 251 +
include/sdsl/rmq_succinct_sct.hpp | 179 +
include/sdsl/rmq_support.hpp | 50 +
include/sdsl/rmq_support_sparse_table.hpp | 190 +
include/sdsl/rrr_helper.hpp | 539 ++
include/sdsl/rrr_vector.hpp | 648 ++
include/sdsl/rrr_vector_15.hpp | 683 ++
include/sdsl/sd_vector.hpp | 677 ++
include/sdsl/sdsl_concepts.hpp | 50 +
include/sdsl/select_support.hpp | 251 +
include/sdsl/select_support_mcl.hpp | 508 ++
include/sdsl/select_support_scan.hpp | 104 +
include/sdsl/sfstream.hpp | 79 +
include/sdsl/sorted_int_stack.hpp | 183 +
include/sdsl/sorted_multi_stack_support.hpp | 190 +
include/sdsl/sorted_stack_support.hpp | 171 +
include/sdsl/structure_tree.hpp | 66 +
include/sdsl/suffix_array_algorithm.hpp | 517 ++
include/sdsl/suffix_array_helper.hpp | 653 ++
include/sdsl/suffix_arrays.hpp | 57 +
include/sdsl/suffix_tree_algorithm.hpp | 279 +
include/sdsl/suffix_tree_helper.hpp | 288 +
include/sdsl/suffix_trees.hpp | 81 +
include/sdsl/uint128_t.hpp | 36 +
include/sdsl/uint256_t.hpp | 255 +
include/sdsl/uintx_t.hpp | 16 +
include/sdsl/util.hpp | 609 ++
include/sdsl/vectors.hpp | 10 +
include/sdsl/vlc_vector.hpp | 281 +
include/sdsl/wavelet_trees.hpp | 81 +
include/sdsl/wm_int.hpp | 724 ++
include/sdsl/wt_algorithm.hpp | 600 ++
include/sdsl/wt_blcd.hpp | 132 +
include/sdsl/wt_gmr.hpp | 931 +++
include/sdsl/wt_helper.hpp | 632 ++
include/sdsl/wt_huff.hpp | 127 +
include/sdsl/wt_hutu.hpp | 607 ++
include/sdsl/wt_int.hpp | 906 +++
include/sdsl/wt_pc.hpp | 799 ++
include/sdsl/wt_rlmn.hpp | 438 ++
install.sh | 114 +
lib/CMakeLists.txt | 23 +
lib/bits.cpp | 562 ++
lib/bp_support_algorithm.cpp | 443 ++
lib/coder_elias_delta.cpp | 297 +
lib/coder_elias_gamma.cpp | 249 +
lib/coder_fibonacci.cpp | 109 +
lib/config.cpp | 23 +
lib/construct.cpp | 6 +
lib/construct_config.cpp | 8 +
lib/construct_isa.cpp | 26 +
lib/construct_lcp.cpp | 1094 +++
lib/construct_lcp_helper.cpp | 119 +
lib/construct_sa.cpp | 24 +
lib/construct_sa_se.cpp | 202 +
lib/csa_alphabet_strategy.cpp | 122 +
lib/int_vector.cpp | 26 +
lib/io.cpp | 114 +
lib/lcp_support_tree.cpp | 43 +
lib/louds_tree.cpp | 10 +
lib/memory_management.cpp | 648 ++
lib/nn_dict_dynamic.cpp | 13 +
lib/ram_filebuf.cpp | 155 +
lib/ram_fs.cpp | 135 +
lib/rrr_vector_15.cpp | 9 +
lib/sfstream.cpp | 290 +
lib/structure_tree.cpp | 266 +
lib/uint128_t.cpp | 19 +
lib/uint256_t.cpp | 17 +
lib/util.cpp | 145 +
lib/wt_helper.cpp | 35 +
test/.gitignore | 7 +
test/BitVectorGenerator.cpp | 67 +
test/BitVectorTest.config | 35 +
test/BitVectorTest.cpp | 126 +
test/BitsTest.cpp | 190 +
test/CoderTest.cpp | 106 +
test/CompileTest.cpp | 18 +
test/CsaByteTest.config | 7 +
test/CsaByteTest.cpp | 246 +
test/CsaIntTest.config | 9 +
test/CsaIntTest.cpp | 250 +
test/CstByteTest.config | 7 +
test/CstByteTest.cpp | 474 ++
test/CstHelper.hpp | 55 +
test/CstIntTest.config | 10 +
test/CstIntTest.cpp | 484 ++
test/IntVectorBufferTest.cpp | 694 ++
test/IntVectorGenerator.cpp | 46 +
test/IntVectorMapperTest.cpp | 288 +
test/IntVectorTest.cpp | 362 +
test/InvPermSupportTest.cpp | 135 +
test/K2TreapTest.config | 6 +
test/K2TreapTest.cpp | 274 +
test/LcpConstructTest.config | 7 +
test/LcpConstructTest.cpp | 117 +
test/Makefile | 299 +
test/NNDictDynamicTest.cpp | 155 +
test/README.md | 57 +
test/RMQTest.config | 7 +
test/RMQTest.cpp | 156 +
test/RankSupportTest.cpp | 90 +
test/ReplaceIntVectorValue.cpp | 31 +
test/SaConstructTest.config | 8 +
test/SaConstructTest.cpp | 102 +
test/SearchBidirectionalTest.config | 7 +
test/SearchBidirectionalTest.cpp | 153 +
test/SelectSupportTest.cpp | 79 +
test/SortedIntStackTest.cpp | 151 +
test/WtByteTest.config | 8 +
test/WtByteTest.cpp | 582 ++
test/WtIntTest.config | 8 +
test/WtIntTest.cpp | 865 +++
test/coverage/.gitignore | 5 +
test/coverage/README.md | 18 +
test/coverage/clean.sh | 7 +
test/coverage/run.sh | 26 +
test/download.config | 4 +
test/test_cases/.gitignore | 11 +
test/test_cases/100a.txt | 1 +
test/test_cases/README.md | 7 +
test/test_cases/abc_abc_abc.txt | Bin 0 -> 12 bytes
test/test_cases/abc_abc_abc2.txt | Bin 0 -> 12 bytes
test/test_cases/all_symbols.txt | Bin 0 -> 256 bytes
test/test_cases/empty.txt | 0
test/test_cases/example01.txt | 1 +
test/test_cases/keeper.int | Bin 0 -> 504 bytes
test/test_cases/one_byte.txt | 1 +
test/tmp/.gitignore | 2 +
tutorial/.gitignore | 1 +
tutorial/Makefile | 17 +
tutorial/cst-search.cpp | 90 +
tutorial/cst-traversal.cpp | 26 +
tutorial/csx-printf.cpp | 75 +
tutorial/document_listing/Makefile | 20 +
tutorial/document_listing/doc_list_index.cpp | 84 +
tutorial/document_listing/generate_collection.py | 35 +
tutorial/expl-01.cpp | 14 +
tutorial/expl-02.cpp | 18 +
tutorial/expl-03.cpp | 19 +
tutorial/expl-04.cpp | 15 +
tutorial/expl-05.cpp | 17 +
tutorial/expl-06.cpp | 14 +
tutorial/expl-07.cpp | 16 +
tutorial/expl-08.cpp | 22 +
tutorial/expl-09.cpp | 17 +
tutorial/expl-10.cpp | 17 +
tutorial/expl-11.cpp | 16 +
tutorial/expl-12.cpp | 21 +
tutorial/expl-13.cpp | 16 +
tutorial/expl-14.cpp | 18 +
tutorial/expl-15.cpp | 22 +
tutorial/expl-16.cpp | 17 +
tutorial/expl-17.cpp | 15 +
tutorial/expl-18.cpp | 19 +
tutorial/expl-19.cpp | 14 +
tutorial/expl-20.cpp | 14 +
tutorial/expl-21.cpp | 16 +
tutorial/expl-22.cpp | 17 +
tutorial/expl-23.cpp | 16 +
tutorial/expl-24.cpp | 17 +
tutorial/expl-25.cpp | 19 +
tutorial/expl-26.cpp | 15 +
tutorial/int-vector-buffer.cpp | 34 +
tutorial/rmq-example.cpp | 37 +
tutorial/use-a-wavelet-tree.cpp | 27 +
uninstall.sh | 37 +
608 files changed, 130252 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..658c4c6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+Make.helper
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..20b1377
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,77 @@
+cmake_minimum_required(VERSION 2.8.7)
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
+include(AppendCompilerFlags)
+
+## Project information ##
+project(sdsl CXX C)
+set(PROJECT_VENDOR "Simon Gog")
+set(PROJECT_CONTACT "simon.gog at gmail.com")
+set(PROJECT_URL "https://github.com/simongog/sdsl-lite")
+set(PROJECT_DESCRIPTION "SDSL: Succinct Data Structure Library")
+set(CMAKE_BUILD_TYPE "Release")
+
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" PROJECT_VERSION_FULL)
+string(REGEX REPLACE "[\n\r]" "" PROJECT_VERSION_FULL "${PROJECT_VERSION_FULL}")
+string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+$" "\\1" PROJECT_VERSION_MAJOR "${PROJECT_VERSION_FULL}")
+string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+$" "\\1" PROJECT_VERSION_MINOR "${PROJECT_VERSION_FULL}")
+string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)$" "\\1" PROJECT_VERSION_PATCH "${PROJECT_VERSION_FULL}")
+set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+math(EXPR LIBRARY_VERSION_MAJOR "1 + ${PROJECT_VERSION_MAJOR}")
+set(LIBRARY_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
+set(LIBRARY_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
+set(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}")
+set(LIBRARY_VERSION_FULL "${LIBRARY_VERSION}.${LIBRARY_VERSION_PATCH}")
+
+
+option(CODE_COVERAGE "Set ON to add code coverage compile options" OFF)
+
+# C++11 compiler Check
+if(NOT CMAKE_CXX_COMPILER_VERSION) # work around for cmake versions smaller than 2.8.10
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION)
+endif()
+if(CMAKE_CXX_COMPILER MATCHES ".*clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_COMPILER_IS_CLANGXX 1)
+endif()
+if( (CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.7) OR
+ (CMAKE_COMPILER_IS_CLANGXX AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.2))
+ message(FATAL_ERROR "Your C++ compiler does not support C++11. Please install g++ 4.7 (or greater) or clang 3.2 (or greater)")
+else()
+ message(STATUS "Compiler is recent enough to support C++11.")
+endif()
+
+if( CMAKE_COMPILER_IS_GNUCXX )
+ append_cxx_compiler_flags("-std=c++11 -Wall -Wextra -DNDEBUG" "GCC" CMAKE_CXX_FLAGS)
+ append_cxx_compiler_flags("-O3 -ffast-math -funroll-loops" "GCC" CMAKE_CXX_OPT_FLAGS)
+ if ( CODE_COVERAGE )
+ append_cxx_compiler_flags("-g -fprofile-arcs -ftest-coverage -lgcov" "GCC" CMAKE_CXX_FLAGS)
+ endif()
+else()
+ append_cxx_compiler_flags("-std=c++11 -DNDEBUG" "CLANG" CMAKE_CXX_FLAGS)
+ append_cxx_compiler_flags("-stdlib=libc++" "CLANG" CMAKE_CXX_FLAGS)
+ append_cxx_compiler_flags("-O3 -ffast-math -funroll-loops" "CLANG" CMAKE_CXX_OPT_FLAGS)
+endif()
+
+
+include(CheckSSE4_2)
+if( BUILTIN_POPCNT )
+ if( CMAKE_COMPILER_IS_GNUCXX )
+ append_cxx_compiler_flags("-msse4.2" "GCC" CMAKE_CXX_OPT_FLAGS)
+ else()
+ append_cxx_compiler_flags("-msse4.2" "CLANG" CMAKE_CXX_OPT_FLAGS)
+ endif()
+endif()
+
+add_subdirectory(external)
+add_subdirectory(include)
+add_subdirectory(lib)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Make.helper.cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Make.helper" @ONLY)
+
+## Add 'uninstall' target ##
+CONFIGURE_FILE(
+ "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+ADD_CUSTOM_TARGET(uninstall
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/CMakeModules/cmake_uninstall.cmake")
diff --git a/CMakeModules/AppendCompilerFlags.cmake b/CMakeModules/AppendCompilerFlags.cmake
new file mode 100644
index 0000000..58d3f99
--- /dev/null
+++ b/CMakeModules/AppendCompilerFlags.cmake
@@ -0,0 +1,38 @@
+include(CheckCSourceCompiles)
+include(CheckCXXSourceCompiles)
+
+macro(append_c_compiler_flags _flags _name _result)
+ set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}")
+ string(TOUPPER "${cname}" cname)
+ foreach(flag ${_flags})
+ string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}")
+ string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}")
+ string(TOUPPER "${flagname}" flagname)
+ set(have_flag "HAVE_${cname}_${flagname}")
+ set(CMAKE_REQUIRED_FLAGS "${flag}")
+ check_c_source_compiles("int main() { return 0; }" ${have_flag})
+ if(${have_flag})
+ set(${_result} "${${_result}} ${flag}")
+ endif(${have_flag})
+ endforeach(flag)
+ set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS})
+endmacro(append_c_compiler_flags)
+
+macro(append_cxx_compiler_flags _flags _name _result)
+ set(SAFE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+ string(REGEX REPLACE "[-+/ ]" "_" cname "${_name}")
+ string(TOUPPER "${cname}" cname)
+ foreach(flag ${_flags})
+ string(REGEX REPLACE "^[-+/ ]+(.*)[-+/ ]*$" "\\1" flagname "${flag}")
+ string(REGEX REPLACE "[-+/ ]" "_" flagname "${flagname}")
+ string(TOUPPER "${flagname}" flagname)
+ set(have_flag "HAVE_${cname}_${flagname}")
+ set(CMAKE_REQUIRED_FLAGS "${flag}")
+ check_cxx_source_compiles("int main() { return 0; }" ${have_flag})
+ if(${have_flag})
+ set(${_result} "${${_result}} ${flag}")
+ endif(${have_flag})
+ endforeach(flag)
+ set(CMAKE_REQUIRED_FLAGS ${SAFE_CMAKE_REQUIRED_FLAGS})
+endmacro(append_cxx_compiler_flags)
diff --git a/CMakeModules/CheckSSE4_2.cmake b/CMakeModules/CheckSSE4_2.cmake
new file mode 100644
index 0000000..ffc2599
--- /dev/null
+++ b/CMakeModules/CheckSSE4_2.cmake
@@ -0,0 +1,24 @@
+# Check if the CPU provides fast operations
+# for popcount, leftmost and rightmost bit
+
+set(BUILTIN_POPCNT 0)
+# Check if we are on a Linux system
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # Use /proc/cpuinfo to get the information
+ file(STRINGS "/proc/cpuinfo" _cpuinfo)
+ if(_cpuinfo MATCHES "(sse4_2)|(sse4a)")
+ set(BUILTIN_POPCNT 1)
+ endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+# handle windows
+# get_filename_component(_vendor_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;VendorIdentifier]" NAME CACHE)
+# get_filename_component(_cpu_id "[HKEY_LOCAL_MACHINE\\Hardware\\Description\\System\\CentralProcessor\\0;Identifier]" NAME CACHE)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+# handle MacOs
+execute_process(COMMAND sysctl -n machdep.cpu.features
+ OUTPUT_VARIABLE _cpuinfo OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(_cpuinfo MATCHES "SSE4.2")
+ set(BUILTIN_POPCNT 1)
+ endif()
+endif()
+
diff --git a/CMakeModules/cmake_uninstall.cmake.in b/CMakeModules/cmake_uninstall.cmake.in
new file mode 100644
index 0000000..8366a83
--- /dev/null
+++ b/CMakeModules/cmake_uninstall.cmake.in
@@ -0,0 +1,36 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+
+SET(NUM 0)
+FOREACH(file ${files})
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - found")
+ SET(UNINSTALL_CHECK_${NUM} 1)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - not found")
+ SET(UNINSTALL_CHECK_${NUM} 0)
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ MATH(EXPR NUM "1 + ${NUM}")
+ENDFOREACH(file)
+
+SET(NUM 0)
+FOREACH(file ${files})
+ IF(${UNINSTALL_CHECK_${NUM}})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ENDIF(${UNINSTALL_CHECK_${NUM}})
+ MATH(EXPR NUM "1 + ${NUM}")
+ENDFOREACH(file)
+
+FILE(REMOVE "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..808ed55
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,16 @@
+The sdsl copyright is as follows:
+
+Copyright (C) 2007-2014 Simon Gog All Right Reserved.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
diff --git a/Make.helper.cmake b/Make.helper.cmake
new file mode 100644
index 0000000..ca38376
--- /dev/null
+++ b/Make.helper.cmake
@@ -0,0 +1,26 @@
+LIB_DIR = @CMAKE_INSTALL_PREFIX@/lib
+INC_DIR = @CMAKE_INSTALL_PREFIX@/include
+MY_CXX_FLAGS=@CMAKE_CXX_FLAGS@ $(CODE_COVER)
+MY_CXX_OPT_FLAGS=@CMAKE_CXX_OPT_FLAGS@
+MY_CXX=@CMAKE_CXX_COMPILER@
+MY_CC=@CMAKE_C_COMPILER@
+
+# Returns $1-th .-separated part of string $2.
+dim = $(word $1, $(subst ., ,$2))
+
+# Returns value stored in column $3 for item with ID $2 in
+# config file $1
+config_select=$(shell cat $1 | grep -v "^\#" | grep "$2;" | cut -f $3 -d';' )
+
+# Returns value stored in column $3 for a line matching $2
+# in config file $1
+config_filter=$(shell cat $1 | grep -v "^\#" | fgrep "$2" | cut -f $3 -d';' )
+
+# Get all IDs from a config file $1
+config_ids=$(shell cat $1 | grep -v "^\#" | cut -f 1 -d';')
+
+# Get column $2 from a config file $1
+config_column=$(shell cat $1 | grep -v "^\#" | cut -f $2 -d';')
+
+# Get size of file $1 in bytes
+file_size=$(shell wc -c < $1 | tr -d ' ')
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c54c732
--- /dev/null
+++ b/README.md
@@ -0,0 +1,280 @@
+SDSL - Succinct Data Structure Library
+=========
+
+What is it?
+-----------
+
+The Succinct Data Structure Library (SDSL) is a powerful and flexible C++11
+library implementing succinct data structures. In total, the library contains
+the highlights of 40 [research publications][SDSLLIT]. Succinct data structures
+can represent an object (such as a bitvector or a tree) in space close the
+information-theoretic lower bound of the object while supporting operations
+of the original object efficiently. The theoretical time complexity of an
+operations performed on the classical data structure and the equivalent
+succinct data structure are (most of the time) identical.
+
+Why SDSL?
+--------
+
+Succinct data structures have very attractive theoretical properties. However,
+in practice implementing succinct data structures is non-trivial as they are
+often composed of complex operations on bitvectors. The SDSL Library provides
+high quality, open source implementations of many succinct data structures
+proposed in literature.
+
+Specifically, the aim of the library is to provide basic and complex succinct
+data structure which are
+
+ * Easy and intuitive to use (like the [STL][STL], which provides classical data structures),
+ * Faithful to the original theoretical results,
+ * Capable of handling large inputs (yes, we support 64-bit),
+ * Provide efficient construction of all implemented succinct data structures,
+ while at the same time enable good run-time performance.
+
+<a href="http://simongog.github.io/assets/data/space-vis.html" >
+<img align="right" src="extras/resources/space-vis.png?raw=true" />
+</a>
+
+In addition we provide additional functionality which can help you use succinct
+data structure to their full potential.
+
+ * Each data structure can easily be serialized and loaded to/from disk.
+ * We provide functionality which helps you analyze the storage requirements of any
+ SDSL based data structure (see right)
+ * We support features such as hugepages and tracking the memory usage of each
+ SDSL data structure.
+ * Complex structures can be configured by template parameters and therefore
+ easily be composed. There exists one simple method which constructs
+ all complex structures.
+ * We maintain an extensive collection of examples which help you use the different
+ features provided by the library.
+ * All data structures are tested for correctness using a unit-testing framework.
+ * We provide a large collection of supporting documentation consisting of examples,
+ [cheat sheet][SDSLCS], [tutorial slides and walk-through][TUT].
+
+The library contains many succinct data structures from the following categories:
+
+ * Bitvectors supporting Rank and Select
+ * Integer Vectors
+ * Wavelet Trees
+ * Compressed Suffix Arrays (CSA)
+ * Balanced Parentheses Representations
+ * Longest Common Prefix (LCP) Arrays
+ * Compressed Suffix Trees (CST)
+ * Range Minimum/Maximum Query (RMQ) Structures
+
+For a complete overview including theoretical bounds see the
+[cheat sheet][SDSLCS] or the
+[wiki](https://github.com/simongog/sdsl-lite/wiki/List-of-Implemented-Data-Structures).
+
+Documentation
+-------------
+
+We provide an extensive set of documentation describing all data structures
+and features provided by the library. Specifically we provide
+
+* A [cheat sheet][SDSLCS] which succinctly
+describes the usage of the library.
+* A set of [example](examples/) programs demonstrating how different features
+of the library are used.
+* A tutorial [presentation][TUT] with the [example code](tutorial/) using in the
+sides demonstrating all features of the library in a step-by-step walk-through.
+* [Unit Tests](test/) which contain small code snippets used to test each
+library feature.
+
+Requirements
+------------
+
+The SDSL library requires:
+
+* A modern, C++11 ready compiler such as `g++` version 4.7 or higher or `clang` version 3.2 or higher.
+* The [cmake][cmake] build system.
+* A 64-bit operating system. Either Mac OS X or Linux are currently supported.
+* For increased performance the processor of the system should support fast bit operations available in `SSE4.2`
+
+Installation
+------------
+
+To download and install the library use the following commands.
+
+```sh
+git clone https://github.com/simongog/sdsl-lite.git
+cd sdsl-lite
+./install.sh
+```
+
+This installs the sdsl library into the `include` and `lib` directories in your
+home directory. A different location prefix can be specified as a parameter of
+the `install.sh` script:
+
+```sh
+./install /usr/local/
+```
+
+To remove the library from your system use the provided uninstall script:
+
+```sh
+./uninstall.sh
+```
+
+Getting Started
+------------
+
+To get you started with the library you can start by compiling the following
+sample program which constructs a compressed suffix array (a FM-Index) over the
+text `mississippi!`, counts the number of occurrences of pattern `si` and
+stores the data structure, and a space usage visualization to the
+files `fm_index-file.sdsl` and `fm_index-file.sdsl.html`:
+
+```cpp
+#include <sdsl/suffix_arrays.hpp>
+#include <fstream>
+
+using namespace sdsl;
+
+int main() {
+ csa_wt<> fm_index;
+ construct_im(fm_index, "mississippi!", 1);
+ std::cout << "'si' occurs " << count(fm_index,"si") << " times.\n";
+ store_to_file(fm_index,"fm_index-file.sdsl");
+ std::ofstream out("fm_index-file.sdsl.html");
+ write_structure<HTML_FORMAT>(fm_index,out);
+}
+```
+
+To compile the program using `g++` run:
+
+```sh
+g++ -std=c++11 -O3 -DNDEBUG -I ~/include -L ~/lib program.cpp -o program -lsdsl -ldivsufsort -ldivsufsort64
+```
+
+Next we suggest you look at the comprehensive [tutorial][TUT] which describes
+all major features of the library or look at some of the provided [examples](examples).
+
+Test
+----
+
+Implementing succinct data structures can be tricky. To ensure that all data
+structures behave as expected, we created a large collection of unit tests
+which can be used to check the correctness of the library on your computer.
+The [test](./test) directory contains test code. We use [googletest][GTEST]
+framework and [make][MAKE] to run the tests. See the README file in the
+directory for details.
+
+To simply run all unit tests type
+
+```sh
+cd sdsl-lite/test
+make
+```
+
+Note: Running the tests requires several sample files to be downloaded from the web
+and can take up to 2 hours on slow machines.
+
+
+Benchmarks
+----------
+
+To ensure the library runs efficiently on your system we suggest you run our
+[benchmark suite](benchmark). The benchmark suite recreates a
+popular [experimental study](http://arxiv.org/abs/0712.3360) which you can
+directly compare to the results of your benchmark run.
+
+Bug Reporting
+------------
+
+While we use an extensive set of unit tests and test coverage tools you might
+still find bugs in the library. We encourage you to report any problems with
+the library via the [github issue tracking system](https://github.com/simongog/sdsl-lite/issues)
+of the project.
+
+The Latest Version
+------------------
+
+The latest version can be found on the SDSL github project page https://github.com/simongog/sdsl-lite .
+
+If you are running experiments in an academic settings we suggest you use the
+most recent [released](https://github.com/simongog/sdsl-lite/releases) version
+of the library. This allows others to reproduce your experiments exactly.
+
+Licensing
+---------
+
+The SDSL library is free software provided under the GNU General Public License
+(GPLv3). For more information see the [COPYING file][CF] in the library
+directory.
+
+We distribute this library freely to foster the use and development of advanced
+data structure. If you use the library in an academic setting please cite the
+following paper:
+
+ @inproceedings{gbmp2014sea,
+ title = {From Theory to Practice: Plug and Play with Succinct Data Structures},
+ author = {Gog, Simon and Beller, Timo and Moffat, Alistair and Petri, Matthias},
+ booktitle = {13th International Symposium on Experimental Algorithms, (SEA 2014)},
+ year = {2014},
+ pages = {326-337},
+ ee = {http://dx.doi.org/10.1007/978-3-319-07959-2_28}
+ }
+
+A preliminary version if available [here on arxiv][SEAPAPER].
+
+## External Resources used in SDSL
+
+We have included the code of two excellent suffix array
+construction algorithms.
+
+* Yuta Mori's incredible fast suffix [libdivsufsort][DIVSUF]
+ algorithm (version 2.0.1) for byte-alphabets.
+* An adapted version of [Jesper Larsson's][JESL] [implementation][QSUFIMPL] of
+ suffix array sorting on integer-alphabets (description of [Larsson and Sadakane][LS]).
+
+Additionally, we use the [googletest][GTEST] framework to provide unit tests.
+Our visualizations are implemented using the [d3js][d3js]-library.
+
+Authors
+--------
+
+The main contributors to the library are:
+
+* [Timo Beller](https://github.com/tb38)
+* [Simon Gog](https://github.com/simongog) (Creator)
+* [Matthias Petri](https://github.com/mpetri)
+
+This project further profited from excellent input of our students
+Markus Brenner, Alexander Diehm, and Maike Zwerger. Stefan
+Arnold helped us with tricky template questions. We are also grateful to
+[Travis Gagie](https://github.com/TravisGagie),
+Kalle Karhu,
+[Dominik Kempa](https://github.com/dkempa),
+[Bruce Kuo](https://github.com/bruce3557),
+[Shanika Kuruppu](https://github.com/skuruppu),
+and [Julio Vizcaino](https://github.com/garviz)
+for bug reports.
+
+Contribute
+----------
+
+Are you working on a new or improved implementation of a succinct data structure?
+We encourage you to contribute your implementation to the SDSL library to make
+your work accessible to the community within the existing library framework.
+Feel free to contact any of the authors or create an issue on the
+[issue tracking system](https://github.com/simongog/sdsl-lite/issues).
+
+
+[STL]: http://www.sgi.com/tech/stl/ "Standard Template Library"
+[pz]: http://pizzachili.di.unipi.it/ "Pizza&Chli"
+[d3js]: http://d3js.org "D3JS library"
+[cmake]: http://www.cmake.org/ "CMake tool"
+[MAKE]: http://www.gnu.org/software/make/ "GNU Make"
+[gcc]: http://gcc.gnu.org/ "GNU Compiler Collection"
+[DIVSUF]: http://code.google.com/p/libdivsufsort/ "libdivsufsort"
+[LS]: http://www.sciencedirect.com/science/article/pii/S0304397507005257 "Larson & Sadakane Algorithm"
+[GTEST]: https://code.google.com/p/googletest/ "Google C++ Testing Framework"
+[SDSLCS]: http://simongog.github.io/assets/data/sdsl-cheatsheet.pdf "SDSL Cheat Sheet"
+[SDSLLIT]: https://github.com/simongog/sdsl-lite/wiki/Literature "Succinct Data Structure Literature"
+[TUT]: http://simongog.github.io/assets/data/sdsl-slides/tutorial "Tutorial"
+[QSUFIMPL]: http://www.larsson.dogma.net/qsufsort.c "Original Qsufsort Implementation"
+[JESL]: http://www.itu.dk/people/jesl/ "Homepage of Jesper Larsson"
+[CF]: https://github.com/simongog/sdsl-lite/blob/master/COPYING "Licence"
+[SEAPAPER]: http://arxiv.org/pdf/1311.1249v1.pdf "SDSL paper"
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..38f77a6
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+2.0.1
diff --git a/benchmark/Make.download b/benchmark/Make.download
new file mode 100644
index 0000000..9d42845
--- /dev/null
+++ b/benchmark/Make.download
@@ -0,0 +1,12 @@
+../data/%:
+ $(eval URL:=$(firstword $(call config_filter,test_case.config,$@,4)))
+ @$(if $(URL),,\
+ $(error "No download link nor generation program specified for test case $@") )
+ @echo "Download input from $(URL) using curl"
+ $(eval DEST_DIR:=$(shell dirname $@))
+ cd $(DEST_DIR); curl -O $(URL)
+ $(eval FILE:=$(DEST_DIR)/$(notdir $(URL)))
+ @$(if $(filter-out ".gz",$(FILE)),\
+ echo "Extract file $(FILE) using gunzip";\
+ gunzip $(FILE))
+
diff --git a/benchmark/Make.helper b/benchmark/Make.helper
new file mode 100644
index 0000000..3e20a5f
--- /dev/null
+++ b/benchmark/Make.helper
@@ -0,0 +1,18 @@
+include ../../Make.helper
+
+../data/%.z.info:
+ $(eval TC:=../data/$*)
+ @echo "Get xz-compression ratio for $(TC)"
+ $(eval TC_XZ:=$(TC).xz)
+ $(shell xz -9 -z -k -c $(TC) > $(TC_XZ))
+ $(eval XZ_SIZE:=$(call file_size,$(TC_XZ)))
+ $(shell rm $(TC_XZ))
+ @echo "Get gzip-compression ratio for $(TC)"
+ $(eval TC_GZ:=$(TC).gz)
+ $(shell gzip -9 -c $(TC) > $(TC_GZ))
+ $(eval GZ_SIZE:=$(call file_size,$(TC_GZ)))
+ $(shell rm $(TC_GZ))
+ $(eval SIZE:=$(call file_size,$(TC)))
+ $(eval XZ_RATIO:=$(shell echo "scale=2;100*$(XZ_SIZE)/$(SIZE)" | bc -q))
+ $(eval GZ_RATIO:=$(shell echo "scale=2;100*$(GZ_SIZE)/$(SIZE)" | bc -q))
+ @echo "xz;$(XZ_RATIO);xz -9\ngzip;$(GZ_RATIO);gzip -9" > $@
diff --git a/benchmark/README.md b/benchmark/README.md
new file mode 100644
index 0000000..c331001
--- /dev/null
+++ b/benchmark/README.md
@@ -0,0 +1,59 @@
+# Benchmarks for sdsl data structures
+
+This directory contains a set of benchmarks for [sdsl][sdsl]
+data structures. Each benchmark is in its own subdirectory and
+so far we have:
+
+* [indexing_count](./indexing_count): Evaluates the performance
+ of count queries on different FM-Indexes/CSAs. Count query
+ means _How many times occurs my pattern P in the text T?_
+* [indexing_extract](./indexing_extract): Evaluates the performance
+ of extracting continues sequences of text out of FM-Indexes/CSAs.
+* [indexing_locate](./indexing_locate): Evaluates the performance
+ of _locate queries_ on different FM-Indexes/CSAs. Locate query
+ means _At which positions does pattern P occure in T?_
+* [rrr_vector](./rrr_vector): Evaluates the performance of
+ the ![H_0](http://latex.codecogs.com/gif.latex?H_0)-compressed
+ bitvector [rrr_vector](../include/sdsl/rrr_vector.hpp).
+ Operations `access`, `rank`, and `select` are benchmarked on
+ different inputs.
+* [wavelet_trees](./wavelet_trees): Evaluates the performance of wavelet trees.
+
+You can executed the benchmarks by calling `make timing`
+in the specific subdirectory.
+Test inputs will be automatically generated or downloaded
+from internet sources, such as the excellent [Pizza&Chili][pz]
+website, and stored in the [data](./data) directory.
+
+Directory [tmp](./tmp) is used to store temporary files (like
+plain suffix arrays) which are used to generate compressed
+structures.
+
+## Prerequisites
+
+The following tools, which are available as packages for Mac OS X and
+most Linux distributions, are required:
+
+ * [cURL][CURL] is required by the test input download script.
+ * [gzip][GZIP] is required to extract compressed files.
+
+## Literature
+
+The benchmark code originates from the following article and can be used
+to easily reproduce the results presented in the paper.
+
+
+Simon Gog, Matthias Petri: _Optimized Succinct Data Structures for Massive Data_. 2013.
+Accepted for publication in Software, Practice and Experience.
+[Preprint][PP]
+
+
+## Author
+
+Simon Gog (simon.gog at gmail.com)
+
+[sdsl]: https://github.com/simongog/sdsl "sdsl"
+[pz]: http://pizzachili.di.unipi.it "Pizza&Chili"
+[PP]: http://people.eng.unimelb.edu.au/sgog/optimized.pdf "Preprint"
+[CURL]: http://curl.haxx.se/ "cURL"
+[GZIP]: http://www.gnu.org/software/gzip/ "Gzip Compressor"
diff --git a/benchmark/basic_functions.R b/benchmark/basic_functions.R
new file mode 100644
index 0000000..053d25e
--- /dev/null
+++ b/benchmark/basic_functions.R
@@ -0,0 +1,176 @@
+# Read a file called file_name and create a data frame the following way
+# (1) Parse all the lines of the form
+# '# key = value'
+# (2) Each unique key gets a column
+data_frame_from_key_value_pairs <- function(file_name){
+ lines <- readLines(file_name)
+ lines <- lines[grep("^#.*=.*",lines)]
+ d <- gsub("^#","",gsub("[[:space:]]","",unlist(strsplit(lines,split="="))))
+ keys <- unique(d[seq(1,length(d),2)])
+ keynr <- length(keys)
+ dd <- d[seq(2,length(d),2)]
+ dim(dd) <- c( keynr, length(dd)/keynr )
+ data <- data.frame(t(dd))
+ names(data) <- keys
+
+ for (col in keys){
+ t <- as.character(data[[col]])
+ suppressWarnings( tt <- as.numeric(t) )
+ if ( length( tt[is.na(tt)] ) == 0 ){ # if there are not NA in tt
+ data[[col]] <- tt
+ }
+ }
+ data
+}
+
+# Takes a vector v=(v1,v2,v3,....)
+# and returns a vector which repeats
+# each element x times. So for two we get
+# (v1,v1,v2,v2,v3,v3....)
+expand_vec <- function( v, x ){
+ v <- rep(v,x)
+ dim(v) <- c(length(v)/x,x)
+ v <- t(v)
+ dim(v) <- c(1,nrow(v)*ncol(v))
+ v
+}
+
+# Takes a vector v=(v1,v2,v3,....)
+# and returns a vector which appends x-1
+# NA after each value. So for x=2 we get
+# (v1,NA,v2,NA,v3,NA....)
+expand_vec_by_NA <- function( v, x ){
+ v <- c(v, rep(NA,length(v)*(x-1)))
+ dim(v) <- c(length(v)/x,x)
+ v <- t(v)
+ dim(v) <- c(1,nrow(v)*ncol(v))
+ v
+}
+
+format_str_fixed_width <- function(x, width=4){
+ sx <- as.character(x)
+ if ( nchar(sx) < width ){
+ for (i in 1:(width-nchar(sx))){
+ sx <- paste("\\D",sx, sep="")
+ }
+ }
+ sx
+}
+
+# Check if package is installed
+# found at: http://r.789695.n4.nabble.com/test-if-a-package-is-installed-td1750671.html#a1750674
+is.installed <- function(mypkg) is.element(mypkg, installed.packages()[,1])
+
+
+sanitize_column <- function(column){
+ column <- gsub("_","\\\\_",column)
+ column <- gsub(" >",">",column)
+ column <- gsub("<","{\\\\textless}",column)
+ column <- gsub(">","{\\\\textgreater}",column)
+ column <- gsub(",",", ",column)
+}
+
+# tranforms a vector of index ids to a vector which contains the
+# corresponding latex names.
+# Note: each id should only appear once in the input vector
+mapids <- function(ids, mapit){
+ as.character(unlist(mapit[ids]))
+}
+
+id2latex <- function(config_file, latexcol, idcol=1){
+ index_info <- read.csv(config_file, sep=";",header=F, comment.char="#")
+ res <- data.frame( t(as.character(index_info[[latexcol]])), stringsAsFactors=F )
+ names(res) <- as.character(index_info[[idcol]])
+ res
+}
+
+idAndValue <- function(config_file, valuecol, idcol=1){
+ res <- read.csv(config_file, sep=";",header=F, comment.char="#")
+ res[c(idcol, valuecol)]
+}
+
+readConfig <- function(config_file, mycolnames){
+ config <- read.csv(config_file, sep=";",header=F, comment.char="#",stringsAsFactors=F)
+ rownames(config) <- config[[1]]
+ colnames(config) <- mycolnames
+ config
+}
+
+# Creates a LaTeX table containing index names and sdsl type
+# config_file The index.config storing the type information
+# index_ids Filter the index.config entires with this index ids
+# id_col Column `id_col` contains the IDs
+# name_col Column `name_col` contains the latex names
+# type_col Column `type_col` contains the type
+typeInfoTable <- function(config_file, index_ids, id_col=1, name_col=3, type_col=2){
+ x <- read.csv(config_file, sep=";", header=F, comment.char="#",stringsAsFactors=F)
+ rownames(x) <- x[[id_col]]
+ x <- x[index_ids,] # filter
+ sdsl_type <- sanitize_column(x[[type_col]])
+ sdsl_name <- x[[name_col]]
+ res <- "
+ \\renewcommand{\\arraystretch}{1.3}
+ \\begin{tabular}{@{}llp{10cm}@{}}
+ \\toprule
+ Identifier&&sdsl type\\\\ \\cmidrule{1-1}\\cmidrule{3-3}"
+ res <- paste(res, paste(sdsl_name,"&&\\footnotesize\\RaggedRight\\texttt{",sdsl_type,"}\\\\",sep="",collapse=" "))
+ res <- paste(res,"
+ \\bottomrule
+ \\end{tabular}")
+}
+
+# returns x concatenated with x reversed
+x_for_polygon <- function(x){
+ c( x, rev(x) )
+}
+
+# return y concatenated with rep(0, length(y))
+y_for_polygon <- function(y){
+ c( y, rep(0, length(y)) )
+}
+
+# ncols Number of columns in the figure
+# nrows Number of rows in the figure
+multi_figure_style <- function(nrows, ncols){
+ par(mfrow=c(nrows, ncols))
+
+ par(las=1) # axis labels always horizontal
+ par(yaxs="i") # don't add +- 4% to the yaxis
+ par(xaxs="i") # don't add +- 4% to the xaxis
+
+
+ # distance (x1,x2,x3) of axis parts from the axis. x1=axis labels or titles
+ # x2=tick marks, x3=tick marks symbol
+ par(mgp=c(2,0.5,0))
+
+ # length of tick mark as a fraction of the height of a line of text, default=-0.5
+ par(tcl=-0.2)
+
+ par(oma=c(2.5,2.7,0,0.2)) # outer margin (bottom,left,top,right)
+ par(mar=c(1,1,1.5,0.5)) # inner margin (bottom,left,top,right)
+
+}
+
+# Draw the heading of diagrams
+# text Text which should be displayed in the heading
+draw_figure_heading <- function(text){
+ # scale Y
+ SY <- function(val){ if( par("ylog") ){ 10^val } else { val } }
+ SX <- function(val){ if( par("xlog") ){ 10^val } else { val } }
+
+ rect(xleft=SX(par("usr")[1]), xright=SX(par("usr")[2]),
+ ybottom=SY(par("usr")[4]), ytop=SY(par("usr")[4]*1.1) ,xpd=NA,
+ col="grey80", border="grey80" )
+ text(labels=text,y=SY(par("usr")[4]*1.02), adj=c(0.5, 0),x=SX((par("usr")[1]+par("usr")[2])/2),xpd=NA,cex=1.4)
+}
+
+print_info <- function(){
+ Sys.info("release")
+ Sys.info("sysname")
+ Sys.info("version")
+ Sys.info("nodename")
+ Sys.info("machine")
+ Sys.info("login")
+ Sys.info("user")
+ Sys.info("effective_user")
+}
diff --git a/benchmark/data/.gitignore b/benchmark/data/.gitignore
new file mode 100644
index 0000000..61d1e36
--- /dev/null
+++ b/benchmark/data/.gitignore
@@ -0,0 +1,3 @@
+*
+!get_corpus.sh
+!.gitignore
diff --git a/benchmark/document_retrieval/Makefile b/benchmark/document_retrieval/Makefile
new file mode 100644
index 0000000..b996925
--- /dev/null
+++ b/benchmark/document_retrieval/Makefile
@@ -0,0 +1,316 @@
+include ../Make.helper
+CXX_FLAGS = $(MY_CXX_FLAGS) $(MY_CXX_OPT_FLAGS) -I$(INC_DIR) -L$(LIB_DIR)
+LIBS = -lsdsl -ldivsufsort -ldivsufsort64
+SRC_DIR = src
+TMP_DIR = ../tmp
+PAT_DIR = pattern
+BIN_DIR = bin
+
+TC_PATHS:=$(call config_column,test_case.config,2)
+TC_PATHS_INT:=$(call config_column,test_case_int.config,2)
+TC_DICT_PATHS:=$(call config_column,dic.config,2)
+TC_IDS:=$(call config_ids,test_case.config)
+TC_IDS_INT:=$(call config_ids,test_case_int.config)
+IDX_IDS:=$(call config_ids,index.config)
+IDX_IDS_INT:=$(call config_ids,index_int.config)
+PAT_LENS:=$(call config_column,pattern_length.config,1)
+PAT_LENS_INT:=$(call config_column,pattern_length_int.config,1)
+
+RESULT_FILE=results/all.txt
+RESULT_FILE_INT=results/all_int.txt
+
+QUERY_EXECS = $(foreach IDX_ID,$(IDX_IDS),$(BIN_DIR)/query_idx_$(IDX_ID))
+QUERY_EXECS_INT = $(foreach IDX_ID,$(IDX_IDS_INT),$(BIN_DIR)/query_int_idx_$(IDX_ID))
+BUILD_EXECS = $(foreach IDX_ID,$(IDX_IDS),$(BIN_DIR)/build_idx_$(IDX_ID))
+BUILD_EXECS_INT = $(foreach IDX_ID,$(IDX_IDS_INT),$(BIN_DIR)/build_int_idx_$(IDX_ID))
+SIZES_EXECS = $(foreach IDX_ID,$(IDX_IDS),$(BIN_DIR)/size_of_idx_$(IDX_ID))
+SIZES_EXECS_INT = $(foreach IDX_ID,$(IDX_IDS_INT),$(BIN_DIR)/size_of_int_idx_$(IDX_ID))
+PATTERNS = $(foreach TC_ID,$(TC_IDS),\
+ $(foreach PAT_LEN,$(PAT_LENS),$(PAT_DIR)/$(TC_ID).$(PAT_LEN).pattern))
+PATTERNS_INT = $(foreach TC_ID,$(TC_IDS_INT),\
+ $(foreach PAT_LEN,$(PAT_LENS_INT),$(PAT_DIR)/$(TC_ID).$(PAT_LEN).pattern.int))
+INDEXES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),indexes/$(TC_ID).$(IDX_ID).byte))
+INDEXES_INT = $(foreach IDX_ID,$(IDX_IDS_INT),\
+ $(foreach TC_ID,$(TC_IDS_INT),indexes/$(TC_ID).$(IDX_ID).int))
+SIZES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),info/$(TC_ID).$(IDX_ID).size))
+SIZES_INT = $(foreach IDX_ID,$(IDX_IDS_INT),\
+ $(foreach TC_ID,$(TC_IDS_INT),info/$(TC_ID).$(IDX_ID).size.int))
+HTML = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),info/$(TC_ID).$(IDX_ID).byte.html))
+HTML_INT = $(foreach IDX_ID,$(IDX_IDS_INT),\
+ $(foreach TC_ID,$(TC_IDS_INT),info/$(TC_ID).$(IDX_ID).int.html))
+TIME_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach PAT_LEN,$(PAT_LENS),results/$(TC_ID).$(IDX_ID).$(PAT_LEN).byte)))
+TIME_FILES_INT = $(foreach IDX_ID,$(IDX_IDS_INT),\
+ $(foreach TC_ID,$(TC_IDS_INT),\
+ $(foreach PAT_LEN,$(PAT_LENS_INT),results/$(TC_ID).$(IDX_ID).$(PAT_LEN).int)))
+COMP_FILES = $(addsuffix .z.info,$(TC_PATHS) $(TC_PATHS_INT))
+
+HELPER_BINS = $(BIN_DIR)/gen_pattern $(BIN_DIR)/gen_pattern_int \
+ $(BIN_DIR)/word_pat2char_pat
+
+all: $(BUILD_EXECS) $(BUILD_EXECS_INT) \
+ $(QUERY_EXECS) $(QUERY_EXECS_INT) \
+ $(SIZES_EXECS) $(SIZES_EXECS_INT) \
+ $(HELPER_BINS)
+
+info: $(SIZES_EXECS) $(SIZES_EXECS_INT) $(SIZES) \
+ $(SIZES_INT) $(HTML_INT) $(HTML) \
+ info/sizes.txt \
+ info/sizes_int.txt
+
+info/sizes.txt: $(SIZES)
+ @cat $(SIZES) > $@
+
+info/sizes_int.txt: $(SIZES)
+ @cat $(SIZES_INT) > $@
+
+indexes: $(INDEXES) $(INDEXES_INT)
+
+input: $(TC_PATHS) $(TC_PATHS_INT) $(TC_DICT_PATHS)
+
+pattern: input $(PATTERNS) $(BIN_DIR)/gen_pattern $(PATTERNS_INT) $(BIN_DIR)/gen_pattern_int
+
+compression: input $(COMP_FILES)
+
+timing: input indexes pattern $(TIME_FILES) $(TIME_FILES_INT) compression info
+ @cat $(TIME_FILES) > $(RESULT_FILE)
+ @cat $(TIME_FILES_INT) > $(RESULT_FILE_INT)
+ @cd visualize; make
+
+# results/[TC_ID].[IDX_ID].[PAT_LEN].byte
+results/%.byte: $(BUILD_EXECS) $(QUERY_EXECS) $(INDEXES) $(PATTERNS)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval PAT_LEN:=$(call dim,3,$*))
+ $(eval TC_NAME:=$(call config_select,test_case.config,$(TC_ID),3))
+ @echo "# TC_ID = $(TC_ID)" > $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# test_case = $(TC_NAME)" >> $@
+ @echo "Run timing for $(IDX_ID) on $(TC_ID) with patterns of length $(PAT_LEN)"
+ @$(BIN_DIR)/query_idx_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID).byte \
+ $(PAT_DIR)/$(TC_ID).$(PAT_LEN).pattern >> $@
+
+# results/[TC_ID].[IDX_ID].[PAT_LEN].byte
+results/%.int: $(BUILD_EXECS) $(QUERY_EXECS_INT) $(INDEXES_INT) $(PATTERNS_INT)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval PAT_LEN:=$(call dim,3,$*))
+ $(eval TC_NAME:=$(call config_select,test_case_int.config,$(TC_ID),3))
+ @echo "# TC_ID = $(TC_ID)" > $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# test_case = $(TC_NAME)" >> $@
+ @echo "Run timing for $(IDX_ID) on $(TC_ID) with patterns of length $(PAT_LEN)"
+ @$(BIN_DIR)/query_int_idx_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID).int \
+ $(PAT_DIR)/$(TC_ID).$(PAT_LEN).pattern.int >> $@
+
+
+
+# indexes/[TC_ID].[IDX_ID].byte
+indexes/%.byte: $(BUILD_EXECS)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ @echo "Building index $(IDX_ID) on $(TC)"
+ @$(BIN_DIR)/build_idx_$(IDX_ID) $(TC) $(TMP_DIR) $@
+
+# indexes/[TC_ID].[IDX_ID].int
+indexes/%.int: $(BUILD_EXECS_INT)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case_int.config,$(TC_ID),2))
+ @echo "Building index $(IDX_ID) on $(TC)"
+ @$(BIN_DIR)/build_int_idx_$(IDX_ID) $(TC) $(TMP_DIR) $@
+
+# info/[TC_ID].[IDX_ID]
+info/%.size: $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ $(eval SIZE:=$(call file_size,$(TC)))
+ @echo "# TC_ID = $(TC_ID)" > $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# text_size = $(SIZE)" >> $@
+ @echo "Get size of index for $(IDX_ID) on $(TC_ID)"
+ @$(BIN_DIR)/size_of_idx_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID).byte >> $@
+
+# info/[TC_ID].[IDX_ID]
+info/%.size.int: $(INDEXES_INT)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case_int.config,$(TC_ID),2))
+ $(eval SIZE:=$(call file_size,$(TC)))
+ @echo "# TC_ID = $(TC_ID)" > $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# text_size = $(SIZE)" >> $@
+ @echo "Get size of index for $(IDX_ID) on $(TC_ID)"
+ @$(BIN_DIR)/size_of_int_idx_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID).int >> $@
+
+# info/[TC_ID].[IDX_ID]
+info/%.byte.html: $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ $(eval SIZE:=$(call file_size,$(TC)))
+ @echo "# TC_ID = $(TC_ID)" > $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# text_size = $(SIZE)" >> $@
+ @echo "Get html of index for $(IDX_ID) on $(TC_ID)"
+ @$(BIN_DIR)/size_of_idx_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID).byte $@
+
+# info/[TC_ID].[IDX_ID]
+info/%.int.html: $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case_int.config,$(TC_ID),2))
+ $(eval SIZE:=$(call file_size,$(TC)))
+ @echo "# TC_ID = $(TC_ID)" > $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# text_size = $(SIZE)" >> $@
+ @echo "Get html of index for $(IDX_ID) on $(TC_ID)"
+ @$(BIN_DIR)/size_of_int_idx_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID).int $@
+
+
+
+# $(PAT_DIR)/[TC_ID].[PAT_LEN].pattern.int
+$(PAT_DIR)/%.pattern.int: $(BIN_DIR)/gen_pattern_int $(BIN_DIR)/word_pat2char_pat
+ @echo $*
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval PAT_LEN:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case_int.config,$(TC_ID),2))
+ $(BIN_DIR)/gen_pattern_int $(TC) $(TMP_DIR)/$(TC_ID).pat.csa $(TMP_DIR) $(PAT_LEN) 200 $@
+ $(eval DIC_PATH:=$(call config_select,dic.config,$(TC_ID),2))
+ $(BIN_DIR)/word_pat2char_pat $@ $(DIC_PATH) > $@.txt
+
+# $(PAT_DIR)/[TC_ID].[PAT_LEN].pattern
+$(PAT_DIR)/%.pattern: $(BIN_DIR)/gen_pattern
+ @echo $*
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval PAT_LEN:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ $(BIN_DIR)/gen_pattern $(TC) $(TMP_DIR)/$(TC_ID).pat.csa $(TMP_DIR) $(PAT_LEN) 200 $@
+
+$(BIN_DIR)/gen_pattern: $(SRC_DIR)/gen_pattern.cpp
+ @echo "Build pattern generation program"
+ $(MY_CXX) $(CXX_FLAGS) $(SRC_DIR)/gen_pattern.cpp \
+ -L$(LIB_DIR) -I$(INC_DIR) -o $@ $(LIBS)
+
+$(BIN_DIR)/gen_pattern_int: $(SRC_DIR)/gen_pattern.cpp
+ @echo "Build pattern generation program"
+ $(MY_CXX) $(CXX_FLAGS) $(SRC_DIR)/gen_pattern.cpp \
+ -DINT_ALPHABET \
+ -L$(LIB_DIR) -I$(INC_DIR) -o $@ $(LIBS)
+
+$(BIN_DIR)/size_of_idx_%: $(SRC_DIR)/size_of_idx.cpp
+ $(eval IDX_TYPE:=$(call config_select,index.config,$*,2))
+ @echo "Build size info program"
+ $(MY_CXX) $(CXX_FLAGS) $(SRC_DIR)/size_of_idx.cpp \
+ -DIDX_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) -I$(INC_DIR) -o $@ $(LIBS)
+
+$(BIN_DIR)/size_of_int_idx_%: $(SRC_DIR)/size_of_idx.cpp
+ $(eval IDX_TYPE:=$(call config_select,index_int.config,$*,2))
+ @echo "Build size info program"
+ $(MY_CXX) $(CXX_FLAGS) $(SRC_DIR)/size_of_idx.cpp \
+ -DIDX_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) -I$(INC_DIR) -o $@ $(LIBS)
+
+# $(BIN_DIR)/build_idx_[IDX_ID]
+$(BIN_DIR)/build_idx_%: $(SRC_DIR)/build_idx.cpp index.config
+ $(eval IDX_TYPE:=$(call config_select,index.config,$*,2))
+ @echo "Compiling build_idx_$*"
+ $(MY_CXX) $(CXX_FLAGS) \
+ -DIDX_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/build_idx.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# $(BIN_DIR)/build_idx_[IDX_ID]
+$(BIN_DIR)/build_int_idx_%: $(SRC_DIR)/build_idx.cpp index_int.config
+ $(eval IDX_TYPE:=$(call config_select,index_int.config,$*,2))
+ @echo "Compiling build_int_idx_$*"
+ $(MY_CXX) $(CXX_FLAGS) \
+ -DIDX_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/build_idx.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the count experiment. $(BIN_DIR)/query_idx_[IDX_ID]
+$(BIN_DIR)/query_idx_%: $(SRC_DIR)/query_idx.cpp index.config
+ $(eval IDX_TYPE:=$(call config_select,index.config,$*,2))
+ @echo "Compiling query_idx_$*"
+ $(MY_CXX) $(CXX_FLAGS) \
+ -DIDX_ID=\"$*\" -DIDX_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/query_idx.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the count experiment. $(BIN_DIR)/query_idx_[IDX_ID]
+$(BIN_DIR)/query_int_idx_%: $(SRC_DIR)/query_idx.cpp index_int.config
+ $(eval IDX_TYPE:=$(call config_select,index_int.config,$*,2))
+ @echo "Compiling query_int_idx_$*"
+ $(MY_CXX) $(CXX_FLAGS) \
+ -DIDX_ID=\"$*\" -DIDX_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/query_idx.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+$(BIN_DIR)/word_pat2char_pat: $(SRC_DIR)/word_pat2char_pat.cpp
+ @echo "Compiling word_pat2char_pat.cpp"
+ $(MY_CXX) $(CXX_FLAGS) \
+ $(SRC_DIR)/word_pat2char_pat.cpp \
+ -o $@
+
+
+
+dic/%:
+ $(eval URL:=$(call config_filter,dic.config,$@,4))
+ @$(if $(URL),,\
+ $(error "No download link for dictionary $@") )
+ @echo "Download dictionary from $(URL) using curl"
+ $(eval DEST_DIR:=$(shell dirname $@))
+ cd $(DEST_DIR); curl -O $(URL)
+ $(eval FILE:=$(DEST_DIR)/$(notdir $(URL)))
+ @$(if $(filter-out ".gz",$(FILE)),\
+ echo "Extract file $(FILE) using gunzip";\
+ gunzip $(FILE))
+
+../data/%.int.sdsl:
+ $(eval URL:=$(call config_filter,test_case_int.config,$@,4))
+ @$(if $(URL),,\
+ $(error "No download link nor generation program specified for test case $@") )
+ @echo "Download input from $(URL) using curl"
+ $(eval DEST_DIR:=$(shell dirname $@))
+ cd $(DEST_DIR); curl -O $(URL)
+ $(eval FILE:=$(DEST_DIR)/$(notdir $(URL)))
+ @$(if $(filter-out ".gz",$(FILE)),\
+ echo "Extract file $(FILE) using gunzip";\
+ gunzip $(FILE))
+
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ rm -f $(QUERY_EXECS) $(SIZES_EXECS) $(BUILD_EXECS) \
+ $(QUERY_EXECS_INT) $(SIZES_EXECS_INT) $(BUILD_EXECS_INT) \
+ $(HELPER_BINS)
+
+clean: clean-build
+ @echo "Remove info files and indexes"
+ rm -f $(INDEXES) $(INDEXES_INT)
+
+cleanresults:
+ @echo "Remove result files and pattern"
+ rm -f $(TIME_FILES) \
+ $(RESULT_FILE) \
+ $(TIME_FILES_INT) \
+ $(RESULT_FILE_INT) \
+ $(SIZES) $(SIZES_INT) \
+ $(HTML) $(HTML_INT)
+ rm -f $(PATTERNS) $(PATTERNS_INT)
+
+cleanall: clean cleanresults
+ @echo "Remove all generated files."
+ rm -f $(TMP_DIR)/*
+ rm -f $(PAT_DIR)/*
+ cd visualize; make clean
diff --git a/benchmark/document_retrieval/README.md b/benchmark/document_retrieval/README.md
new file mode 100644
index 0000000..d5dca78
--- /dev/null
+++ b/benchmark/document_retrieval/README.md
@@ -0,0 +1,100 @@
+# Benchmarking top-k search on simple document search implementations
+
+## Methodology
+
+The benchmark setup is close to the one used in the ESA 2010 article
+of Culpepper, Navarro, Puglisi and Turpin.
+
+Explored dimensions:
+
+ * text type
+ * instance size (just adjust the `test_case.config` file for this)
+ * index implementations
+ - [Sadakane's method](src/doc_list_index_sada.hpp)
+ - [Wavelet tree greedy traversal](src/doc_list_index_greedy.hpp)
+ - [Wavelet tree quantile probing](src/doc_list_index_qprobing.hpp)
+
+## Directory structure
+ * [bin](./bin): Contains the executables of the project.
+ - `build_*` index build executables
+ - `gen_pattern*` executable to generate pattern sets
+ - `query_*` index query executables
+ - `size_of_*` generate size and space breakdowns
+ * [dic](./dic): Contains dictionaries for integer inputs.
+ * [indexes](./indexes): Contains the generated indexes.
+ * [info](./info): Contains space breakdowns.
+ * [pattern](./pattern): Contains generated pattern.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which generates
+ a report.
+
+## Test data
+ * ENWIKISML was generated by
+ - downloading a dump of a prefix of the English wikipedia (at the 5th of August 2013)
+ - applying the `WikiExtractor.py` program Version 2.5
+ from Giuesppe Attardi and Antonio Fuschetto (Univserity of Pisa).
+ - Removing the `<doc id="*">`-tag and replacing the `</doc>`
+ take by `\1`
+ * ENWIKIBIG was generated the same way but for the complete
+ English wikipedia (retrieved at the 8th of July 2013).
+ * The integer version, ENWIKISMLINT and ENWIKIBIGINT, were
+ generated from ENWIKISML and ENWIKIBIG by
+ - applying the [stanford-parser.jar][SP] from the NL group
+ at Stanford to tokenize the input (options
+ `untokenizable=allKeep,normalizeParentheses=false,normalizeOtherBrackets=false`)
+ - assign the document seperator the ID `1`, and the ID of the other
+ tokens is their rank in the reverse sorting of frequency (starting at `2`).
+ - The resulting sequence of integers is stored in a bit-compressed
+ `int_vector`.
+ - The generated dictionaries containing on each line
+ a `(word, ID, occurrences)`-tuple.
+ * PROTEINS is the concatenation of 143,244 Human and Mouse
+ proteins sequences from the swissport database.
+ * Availability: ENWIKIBIG (character and integer version)
+ are available on request. The other files are downloaded
+ automatically during the execution of the benchmark.
+
+## Prerequisites
+ * For the visualization you need the following software:
+ - [R][RPJ] with package `tikzDevice`. You can install the
+ package by calling
+ `install.packages("filehash", repos="http://cran.r-project.org")`
+ and
+ `install.packages("tikzDevice", repos="http://R-Forge.R-project.org")`
+ in `R`.
+ - Compressors [xz][XZ] and [gzip][GZIP] are used to get
+ compression baselines.
+
+ - [pdflatex][LT] to generate the pdf reports.
+
+## Usage
+
+ Command `make timing` will download the small test cases, compile executables,
+ build the indexes, run the queries, and generate a report. The
+ benchmark run 5 minutes and 40 seconds (without downloading the files)
+ and generated [this report on my machine][RES].
+
+## Customization of the benchmark
+ The project contains several configuration files:
+
+ * [index.config](./index.config): Specify character
+ based indexes' ID, sdsl-class and LaTeX-name for the report.
+ * [index_int.config](./index_int.config): Specify word
+ based indexes' ID, sdsl-class and LaTeX-name for the report.
+ * [test_case.config](./test_case.config): Specify character based collections'
+ ID, path, LaTeX-name for the report, and download URL.
+ * [test_case_int.config](./test_case_int.config): Specify word based collections'
+ ID, path, LaTeX-name for the report, and download URL.
+ * [pattern_length.config](./pattern_length.config): Specify the
+ lengths of queried pattern for character based indexes.
+ * [pattern_length_int.config](./pattern_length_int.config): Specify
+ lengths of queried pattern for word based indexes.
+
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[RPJ]: http://www.r-project.org/ "R"
+[XZ]: http://tukaani.org/xz/ "XZ Compressor"
+[GZIP]: http://www.gnu.org/software/gzip/ "Gzip Compressor"
+[SP]: http://nlp.stanford.edu/software/tokenizer.shtml
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/doc_re_time.pdf "doc_re_time.pdf"
diff --git a/benchmark/document_retrieval/bin/.gitignore b/benchmark/document_retrieval/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/document_retrieval/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/document_retrieval/dic.config b/benchmark/document_retrieval/dic.config
new file mode 100644
index 0000000..8e867a1
--- /dev/null
+++ b/benchmark/document_retrieval/dic.config
@@ -0,0 +1,9 @@
+# Configuration file for dictionary files
+# for integer based inputs
+#
+# (1) Identifier for test integer test file
+# (has to exist in test_case_int.config)
+# (2) Path to dictionary
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENWIKISMLINT;dic/enwiki-20130805-pages-articles1.dic;enwiki-dic;http://people.eng.unimelb.edu.au/sgog/data/enwiki-20130805-pages-articles1.dic.gz
diff --git a/benchmark/document_retrieval/dic/.gitignore b/benchmark/document_retrieval/dic/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/document_retrieval/dic/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/document_retrieval/index.config b/benchmark/document_retrieval/index.config
new file mode 100644
index 0000000..e70ef85
--- /dev/null
+++ b/benchmark/document_retrieval/index.config
@@ -0,0 +1,12 @@
+# This file specified sdsl index structures that are used in the benchmark.
+#
+# Each index is specified by a triple: INDEX_ID;SDSL_TYPE;INDEX_LATEX_NAME
+# * INDEX_ID : An identifier for the index. Only letters and underscores
+# are allowed in INDEX_ID.
+# * TYPE : Corresponding type.
+# * LATEX_NAME: LaTeX name for output in the benchmark report.
+GREEDY;doc_list_index_greedy<>;GREEDY
+#GREEDY-RRR;doc_list_index_greedy<csa_wt<wt_huff<rrr_vector<63>>,1000000,1000000>,wt_int<rrr_vector<63>>>;GREEDY-RRR
+#QPROBING;doc_list_index_qprobing<>;QPROBING
+SADA;doc_list_index_sada<csa_sada<enc_vector<>, 32, 1000000, text_order_sa_sampling<sd_vector<>>>>;SADA
+SORT;doc_list_index_sort<>;SORT
diff --git a/benchmark/document_retrieval/index_int.config b/benchmark/document_retrieval/index_int.config
new file mode 100644
index 0000000..1476560
--- /dev/null
+++ b/benchmark/document_retrieval/index_int.config
@@ -0,0 +1,10 @@
+# This file specified sdsl index structures that are used in the benchmark.
+#
+# Each index is specified by a triple: INDEX_ID;SDSL_TYPE;INDEX_LATEX_NAME
+# * INDEX_ID : An identifier for the index. Only letters and underscores
+# are allowed in INDEX_ID.
+# * TYPE : Corresponding type.
+# * LATEX_NAME: LaTeX name for output in the benchmark report.
+GREEDYINT;doc_list_index_greedy<csa_wt<wt_int<rrr_vector<63>>,1000000,1000000>>;GREEDY-I
+SADAINT;doc_list_index_sada<csa_sada_int<enc_vector<>, 32, 1000000, text_order_sa_sampling<sd_vector<>>>>;SADA-I
+SORTINT;doc_list_index_sort<csa_sada_int<enc_vector<>, 32, 1000000, text_order_sa_sampling<sd_vector<>>>>;SORT-I
diff --git a/benchmark/document_retrieval/indexes/.gitignore b/benchmark/document_retrieval/indexes/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/document_retrieval/indexes/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/document_retrieval/info/.gitignore b/benchmark/document_retrieval/info/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/document_retrieval/info/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/document_retrieval/pattern/.gitignore b/benchmark/document_retrieval/pattern/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/document_retrieval/pattern/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/document_retrieval/pattern_length.config b/benchmark/document_retrieval/pattern_length.config
new file mode 100644
index 0000000..ba46a87
--- /dev/null
+++ b/benchmark/document_retrieval/pattern_length.config
@@ -0,0 +1,19 @@
+# pattern length
+3;
+4;
+5;
+6;
+7;
+8;
+9;
+10;
+11;
+12;
+13;
+14;
+15;
+16;
+17;
+18;
+19;
+20;
diff --git a/benchmark/document_retrieval/pattern_length_int.config b/benchmark/document_retrieval/pattern_length_int.config
new file mode 100644
index 0000000..e185d0a
--- /dev/null
+++ b/benchmark/document_retrieval/pattern_length_int.config
@@ -0,0 +1,10 @@
+# pattern length
+2;
+3;
+4;
+5;
+6;
+7;
+8;
+9;
+10;
diff --git a/benchmark/document_retrieval/results/.gitignore b/benchmark/document_retrieval/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/document_retrieval/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/document_retrieval/src/build_idx.cpp b/benchmark/document_retrieval/src/build_idx.cpp
new file mode 100644
index 0000000..1bb5a75
--- /dev/null
+++ b/benchmark/document_retrieval/src/build_idx.cpp
@@ -0,0 +1,34 @@
+#include "doc_list_index.hpp"
+#include <iostream>
+#include <chrono>
+#include <algorithm>
+
+using namespace std;
+using namespace sdsl;
+
+using idx_type = IDX_TYPE;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 4) {
+ cout << "Usage: " << argv[0] << " collection_file tmp_dir index_file" << endl;
+ cout << " Generates an index and stores result in index_file" << endl;
+ cout << " Temporary files are stored in tmp_dir." << endl;
+ return 1;
+ }
+ string collection_file = argv[1];
+ string id = util::basename(collection_file);
+ string tmp_dir = argv[2];
+ string idx_file = argv[3];
+
+ using timer = std::chrono::high_resolution_clock;
+ auto start = timer::now();
+
+ idx_type idx;
+ cache_config cconfig(false, tmp_dir, id);
+ construct(idx, collection_file, cconfig, idx_type::WIDTH==8 ? 1 : 0);
+ auto stop = timer::now();
+ auto elapsed = stop-start;
+ std::cout << "construction time = " << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << std::endl;
+ store_to_file(idx, idx_file);
+}
diff --git a/benchmark/document_retrieval/src/doc_list_index.hpp b/benchmark/document_retrieval/src/doc_list_index.hpp
new file mode 100644
index 0000000..a5a7bcd
--- /dev/null
+++ b/benchmark/document_retrieval/src/doc_list_index.hpp
@@ -0,0 +1,22 @@
+#ifndef DOC_LIST_INDEX
+#define DOC_LIST_INDEX
+
+#include <sdsl/construct.hpp>
+#include <string>
+
+struct doc_list_tag {};
+
+template<class t_index>
+void
+construct(t_index& idx, const std::string& file, sdsl::cache_config& config, uint8_t num_bytes, doc_list_tag)
+{
+ t_index tmp_idx(file, config, num_bytes);
+ idx.swap(tmp_idx);
+}
+
+#include "doc_list_index_sada.hpp"
+#include "doc_list_index_greedy.hpp"
+#include "doc_list_index_qprobing.hpp"
+#include "doc_list_index_sort.hpp"
+
+#endif
diff --git a/benchmark/document_retrieval/src/doc_list_index_greedy.hpp b/benchmark/document_retrieval/src/doc_list_index_greedy.hpp
new file mode 100644
index 0000000..65ee861
--- /dev/null
+++ b/benchmark/document_retrieval/src/doc_list_index_greedy.hpp
@@ -0,0 +1,238 @@
+/*!
+ * This file contains a document listing class, which implements
+ * strategy GREEDY in the article:
+ * J. S. Culpepper, G. Navarro, S. J. Puglisi and A. Turpin:
+ * ,,Top-k Ranked Document Search in General Text Databases''
+ * Proceedings Part II of the 18th Annual European Symposium on
+ * Algorithms (ESA 2010)
+ */
+#ifndef DOCUMENT_LISING_GREEDY_INCLUDED
+#define DOCUMENT_LISING_GREEDY_INCLUDED
+
+#include <sdsl/suffix_arrays.hpp>
+#include <sdsl/rmq_support.hpp>
+#include <string>
+#include <vector>
+#include <fstream>
+#include <list>
+#include <utility>
+#include "doc_list_index.hpp"
+
+using std::vector;
+
+namespace sdsl
+{
+
+template<
+class t_csa = csa_wt<wt_huff<rrr_vector<63>>, 1000000, 1000000>,
+ class t_wtd = wt_int<bit_vector,rank_support_v5<1>,select_support_scan<1>,select_support_scan<0>>,
+ typename t_csa::char_type t_doc_delim = 1
+ >
+ class doc_list_index_greedy
+ {
+ public:
+ using size_type = typename t_wtd::size_type;
+ using value_type = typename t_wtd::value_type;
+
+ typedef t_csa csa_type;
+ typedef t_wtd wtd_type;
+ typedef std::vector<std::pair<size_type,size_type>> list_type;
+ typedef doc_list_tag index_category;
+
+ enum { WIDTH = t_csa::alphabet_category::WIDTH };
+
+ class result : public list_type
+ {
+ private:
+ size_type m_sp, m_ep;
+ public:
+ // Number of occurrences
+size_type count() {
+ return m_ep-m_sp+1;
+}
+
+// Constructors for an empty result and for a result in the interval [sp, ep]:
+result(size_type sp, size_type ep,list_type&& l) : list_type(l), m_sp(sp), m_ep(ep) {}
+result() : m_sp(1), m_ep(0) {}
+result(size_type sp, size_type ep) : m_sp(sp), m_ep(ep) {}
+result& operator=(const result& res) {
+ if (this != &res) {
+ list_type::operator=(res);
+ m_sp = res.m_sp;
+ m_ep = res.m_ep;
+ }
+ return *this;
+}
+
+ };
+
+
+struct wt_range_t {
+ using node_type = typename wtd_type::node_type;
+
+ node_type v;
+ range_type r;
+
+size_t size() const {
+ return r.second - r.first + 1;
+}
+
+bool operator<(const wt_range_t& x) const {
+ if (x.size() != size())
+ return size() < x.size();
+ return v.sym > x.v.sym;
+}
+
+wt_range_t() {}
+wt_range_t(const node_type& _v, const range_type& _r):
+ v(_v), r(_r) {}
+};
+
+
+protected:
+size_type m_doc_cnt; // number of documents in the collection
+csa_type m_csa_full; // CSA built from the collection text
+wtd_type m_wtd; // wtd build from the collection text
+public:
+
+//! Default constructor
+doc_list_index_greedy() { }
+
+doc_list_index_greedy(std::string file_name, sdsl::cache_config& cconfig, uint8_t num_bytes) {
+ construct(m_csa_full, file_name, cconfig, num_bytes);
+
+ const char* KEY_TEXT = key_text_trait<WIDTH>::KEY_TEXT;
+ std::string text_file = cache_file_name(KEY_TEXT, cconfig);
+
+ bit_vector doc_border;
+ construct_doc_border(text_file,doc_border);
+ bit_vector::rank_1_type doc_border_rank(&doc_border);
+ m_doc_cnt = doc_border_rank(doc_border.size());
+
+ int_vector_buffer<0> sa_buf(cache_file_name(conf::KEY_SA, cconfig));
+ {
+ int_vector<> D;
+ construct_D_array(sa_buf, doc_border_rank, m_doc_cnt, D);
+ std::string d_file = cache_file_name("DARRAY", cconfig);
+ store_to_file(D, d_file);
+ util::clear(D);
+ construct(m_wtd, d_file);
+ sdsl::remove(d_file);
+ }
+}
+
+size_type doc_cnt()const {
+ return m_wtd.sigma-1; // subtract one, since zero does not count
+}
+
+size_type word_cnt()const {
+ return m_wtd.size()-doc_cnt();
+}
+
+size_type serialize(std::ostream& out, structure_tree_node* v=NULL, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_doc_cnt, out, child, "doc_cnt");
+ written_bytes += m_csa_full.serialize(out, child, "csa_full");
+ written_bytes += m_wtd.serialize(out, child, "wtd");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+void load(std::istream& in) {
+ read_member(m_doc_cnt, in);
+ m_csa_full.load(in);
+ m_wtd.load(in);
+}
+
+void swap(doc_list_index_greedy& dr) {
+ if (this != &dr) {
+ std::swap(m_doc_cnt, dr.m_doc_cnt);
+ m_csa_full.swap(dr.m_csa_full);
+ m_wtd.swap(dr.m_wtd);
+ }
+}
+
+//! Search for the k documents which contain the search term most frequent
+template<class t_pat_iter>
+size_type search(t_pat_iter begin, t_pat_iter end, result& res, size_t k) const {
+ size_type sp=1, ep=0;
+ if (0 == backward_search(m_csa_full, 0, m_csa_full.size()-1, begin, end, sp, ep)) {
+ res = result();
+ return 0;
+ } else {
+ auto tmp_res = topk_greedy(sp, ep, k);
+ res = result(sp, ep, std::move(tmp_res));
+ return ep-sp+1;
+ }
+}
+
+private:
+//! Construct the doc_border bitvector by streaming the text file
+void
+construct_doc_border(const std::string& text_file, bit_vector& doc_border) {
+ int_vector_buffer<WIDTH> text_buf(text_file);
+ doc_border = bit_vector(text_buf.size(), 0);
+ for (size_type i = 0; i < text_buf.size(); ++i) {
+ if (t_doc_delim == text_buf[i]) {
+ doc_border[i] = 1;
+ }
+ }
+}
+
+void
+construct_D_array(int_vector_buffer<0>& sa_buf,
+ bit_vector::rank_1_type& doc_border_rank,
+ const size_type doc_cnt,
+int_vector<>& D) {
+ D = int_vector<>(sa_buf.size(), 0, bits::hi(doc_cnt+1)+1);
+ for (size_type i = 0; i < sa_buf.size(); ++i) {
+ uint64_t d = doc_border_rank(sa_buf[i]+1);
+ D[i] = d;
+ }
+}
+
+//! Returns the top k most frequent documents in D[lb..rb]
+/*!
+ * \param lb Left array border in D.
+ * \param rb Right array border in D.
+ * \param k The number of documents to return.
+ * \returns the top-k items in ascending order.
+ */
+std::vector< std::pair<value_type,size_type> >
+topk_greedy(size_type lb, size_type rb, size_type k) const {
+ std::vector< std::pair<value_type,size_type> > results;
+ std::priority_queue<wt_range_t> heap;
+
+ heap.emplace(wt_range_t(m_wtd.root(), {lb, rb}));
+
+ while (! heap.empty()) {
+ wt_range_t e = heap.top(); heap.pop();
+ if (m_wtd.is_leaf(e.v)) {
+ results.emplace_back(e.v.sym, e.size());
+ if (results.size()==k) {
+ break;
+ }
+ continue;
+ }
+
+ auto child = m_wtd.expand(e.v);
+ auto child_ranges = m_wtd.expand(e.v, e.r);
+ auto left_range = std::get<0>(child_ranges);
+ auto right_range = std::get<1>(child_ranges);
+
+ if (!empty(left_range)) {
+ heap.emplace(wt_range_t(std::get<0>(child), left_range));
+ }
+ if (!empty(right_range)) {
+ heap.emplace(wt_range_t(std::get<1>(child), right_range));
+ }
+ }
+ return results;
+};
+
+ };
+
+} // end namespace
+
+#endif
diff --git a/benchmark/document_retrieval/src/doc_list_index_qprobing.hpp b/benchmark/document_retrieval/src/doc_list_index_qprobing.hpp
new file mode 100644
index 0000000..47c7332
--- /dev/null
+++ b/benchmark/document_retrieval/src/doc_list_index_qprobing.hpp
@@ -0,0 +1,124 @@
+/*!
+ * This file contains a document listing class, which implements
+ * strategy QUANTILE in the article:
+ * J. S. Culpepper, G. Navarro, S. J. Puglisi and A. Turpin:
+ * ,,Top-k Ranked Document Search in General Text Databases''
+ * Proceedings Part II of the 18th Annual European Symposium on
+ * Algorithms (ESA 2010)
+ */
+#ifndef DOCUMENT_LISING_QPROBING_INCLUDED
+#define DOCUMENT_LISING_QPROBING_INCLUDED
+
+#include "doc_list_index_greedy.hpp"
+#include <string>
+#include <vector>
+#include <fstream>
+#include <list>
+#include <utility>
+
+using std::vector;
+
+namespace sdsl
+{
+
+template<
+class t_csa = csa_wt<wt_huff<rrr_vector<63>>, 1000000, 1000000>,
+ class t_wtd = wt_int<bit_vector,rank_support_v5<1>,select_support_scan<1>,select_support_scan<0>>,
+ typename t_csa::char_type t_doc_delim = 1
+ >
+ class doc_list_index_qprobing : public doc_list_index_greedy<t_csa, t_wtd, t_doc_delim>
+ {
+ private:
+ using base_type = doc_list_index_greedy<t_csa, t_wtd, t_doc_delim>;
+ using base_type::m_csa_full;
+ using base_type::m_wtd;
+
+ public:
+ using size_type = typename base_type::size_type;
+ using value_type = typename t_wtd::value_type;
+ using result = typename base_type::result;
+
+doc_list_index_qprobing() : base_type() {}
+doc_list_index_qprobing(std::string file_name, sdsl::cache_config& cconfig, uint8_t num_bytes) : base_type(file_name, cconfig, num_bytes) {}
+
+//! Search for the k documents which contains the search term most frequent
+template<class t_pat_iter>
+size_type search(t_pat_iter begin, t_pat_iter end, result& res, size_t k) const {
+ size_type sp=1, ep=0;
+ if (0 == backward_search(m_csa_full, 0, m_csa_full.size()-1, begin, end, sp, ep)) {
+ res = result();
+ return 0;
+ } else {
+ auto tmp_res = topk_qprobing(sp, ep ,k);
+ res = result(sp, ep, std::move(tmp_res));
+ return ep-sp+1;
+ }
+}
+
+//! Returns the top-k most frequent documents in m_wtd[lb..rb]
+/*!
+ * \param lb left array bound in T
+ * \param rb right array bound in T
+ * \param k the number of documents to return
+ * \returns the top-k items in ascending order.
+ */
+std::vector< std::pair<value_type,size_type> >
+topk_qprobing(size_type lb, size_type rb,size_type k) const {
+ using p_t = std::pair<value_type,size_type>;
+ std::vector<p_t> results;
+ auto comp = [](p_t& a,p_t& b) { return a.second > b.second; };
+ std::priority_queue<p_t,std::vector<p_t>,decltype(comp)> heap(comp);
+ bit_vector seen(1ULL << m_wtd.max_level); // TODO: better idea?
+
+ /* we start probing using the largest power smaller than len */
+ size_type len = rb-lb+1;
+ size_type power2greaterlen = 1 << (bits::hi(len)+1);
+ size_type probe_interval = power2greaterlen >> 1;
+
+ /* we probe the smallest elem (pos 0 in sorted array) only once */
+ auto qf = quantile_freq(m_wtd,lb,rb,0);
+ heap.push(qf);
+ seen[qf.first] = 1;
+
+ qf = quantile_freq(m_wtd,lb,rb,probe_interval);
+ if (!seen[qf.first]) heap.push(qf);
+ seen[qf.first] = 1;
+
+ while (probe_interval > 1) {
+ size_type probe_pos = probe_interval >> 1;
+ while (probe_pos < len) {
+ qf = quantile_freq(m_wtd,lb,rb,probe_pos);
+ if (!seen[qf.first]) { /* not in heap */
+ if (heap.size()<k) {
+ heap.push(qf);
+ seen[qf.first] = 1;
+ } else {
+ /* throw out the smallest and add the new one */
+ if (heap.top().second < qf.second) {
+ heap.pop();
+ heap.push(qf);
+ seen[qf.first] = 1;
+ }
+ }
+ }
+ probe_pos += probe_interval;
+ }
+ probe_interval >>= 1;
+ /* we have enough or can't find anything better */
+ if (heap.size() == k && probe_interval-1 <= heap.top().second) break;
+ }
+ /* populate results */
+ while (!heap.empty()) {
+ results.emplace(results.begin() , heap.top());
+ heap.pop();
+ }
+ return results;
+};
+
+
+
+ };
+
+} // end namespace
+
+#endif
diff --git a/benchmark/document_retrieval/src/doc_list_index_sada.hpp b/benchmark/document_retrieval/src/doc_list_index_sada.hpp
new file mode 100644
index 0000000..645d98f
--- /dev/null
+++ b/benchmark/document_retrieval/src/doc_list_index_sada.hpp
@@ -0,0 +1,410 @@
+/*! How to code a parametrizable document listing data structure
+ *
+ * This file contains a document listing class implemented as
+ * suggested in Kunihiko Sadakane's article:
+ * ,,Succinct Data Structures for Flexible Text Retrieval Systems''
+ * Journal of Discrete Algorithms, 2007.
+ *
+ */
+#ifndef DOCUMENT_LISING_SADA_INCLUDED
+#define DOCUMENT_LISING_SADA_INCLUDED
+
+#include <sdsl/suffix_arrays.hpp>
+#include <sdsl/rmq_support.hpp>
+#include <string>
+#include <vector>
+#include <fstream>
+#include <list>
+#include <utility>
+#include "doc_list_index.hpp"
+
+using std::vector;
+
+namespace sdsl
+{
+
+template<uint8_t t_width>
+struct sa_trait {
+ typedef uint64_t value_type;
+ typedef std::vector<value_type> vec_type;
+ enum { num_bytes = 0 };
+ template <class t_sa>
+ static void calc_sa(t_sa& sa, vec_type& text) {
+ qsufsort::construct_sa(sa, text);
+ }
+};
+
+template<>
+struct sa_trait<8> {
+ typedef uint8_t value_type;
+ typedef std::vector<value_type> vec_type;
+ enum { num_bytes = 1 };
+ template <class t_sa>
+ static void calc_sa(t_sa& sa, vec_type& text) {
+ algorithm::calculate_sa(text.data(), text.size(), sa);
+ }
+};
+
+
+template<
+class t_csa_full = csa_wt<wt_huff<rrr_vector<63>>, 30, 1000000, text_order_sa_sampling<> >,
+ class t_range_min = rmq_succinct_sct<true>,
+ class t_range_max = rmq_succinct_sct<false>,
+ class t_doc_border = sd_vector<>,
+ class t_doc_border_rank = typename t_doc_border::rank_1_type,
+ class t_doc_border_select = typename t_doc_border::select_1_type,
+ typename t_csa_full::char_type t_doc_delim = 1
+ >
+ class doc_list_index_sada
+ {
+ public:
+ typedef t_csa_full csa_full_type;
+ typedef t_range_min range_min_type;
+ typedef t_range_max range_max_type;
+ typedef t_doc_border doc_border_type;
+ typedef t_doc_border_rank doc_border_rank_type;
+ typedef t_doc_border_select doc_border_select_type;
+ typedef int_vector<>::size_type size_type;
+ typedef std::vector<std::pair<size_type,size_type>> list_type;
+ typedef doc_list_tag index_category;
+
+ enum { WIDTH = t_csa_full::alphabet_category::WIDTH };
+
+ typedef sa_trait<WIDTH> sa_tt;
+
+ class result : public list_type
+ {
+ private:
+ size_type m_sp, m_ep;
+ public:
+ // Number of occurrences
+size_type count() {
+ return m_ep-m_sp+1;
+}
+
+// Constructors for an empty result and for a result in the interval [sp, ep]:
+result() : m_sp(1), m_ep(0) {}
+result(size_type sp, size_type ep) : m_sp(sp), m_ep(ep) {}
+result& operator=(const result& res) {
+ if (this != &res) {
+ list_type::operator=(res);
+ m_sp = res.m_sp;
+ m_ep = res.m_ep;
+ }
+ return *this;
+}
+
+ };
+
+
+private:
+size_type m_doc_cnt; // number of documents in the collection
+csa_full_type m_csa_full; // CSA build from the collection text
+vector<int_vector<>> m_doc_isa; // array of inverse SAs. m_doc_isa[i] contains the ISA of document i
+range_min_type m_rminq; // range minimum data structure build over an array Cprev
+range_max_type m_rmaxq; // range maximum data structure build over an array Cnext
+doc_border_type m_doc_border; // bitvector indicating the positions of the separators in the collection text
+doc_border_rank_type m_doc_border_rank; // rank data structure on m_doc_border
+doc_border_select_type m_doc_border_select; // select data structure on m_doc_border
+size_type m_doc_max_len; // maximal length of a document in the collection
+mutable bit_vector m_doc_rmin_marked; // helper bitvector for search process
+mutable bit_vector m_doc_rmax_marked; // helper bitvector for search process
+
+public:
+
+//! Default constructor
+doc_list_index_sada() { }
+
+doc_list_index_sada(std::string file_name, sdsl::cache_config& cconfig, uint8_t num_bytes) {
+ construct(m_csa_full, file_name, cconfig, num_bytes);
+
+ const char* KEY_TEXT = key_text_trait<WIDTH>::KEY_TEXT;
+ std::string text_file = cache_file_name(KEY_TEXT, cconfig);
+
+ construct_doc_border(text_file, m_doc_border, m_doc_max_len);
+ m_doc_border_rank = doc_border_rank_type(&m_doc_border);
+ m_doc_border_select = doc_border_select_type(&m_doc_border);
+ m_doc_cnt = m_doc_border_rank(m_doc_border.size());
+
+ construct_doc_isa(text_file, m_doc_cnt, m_doc_max_len, m_doc_isa);
+
+ int_vector_buffer<0> sa_buf(cache_file_name(conf::KEY_SA, cconfig));
+ {
+ int_vector<> D;
+ construct_D_array(sa_buf, m_doc_border_rank, m_doc_cnt, D);
+ {
+ int_vector<> Cprev;
+ construct_Cprev_array(D, m_doc_cnt, Cprev);
+ range_min_type rminq(&Cprev);
+ m_rminq = rminq;
+ }
+ {
+ int_vector<> Cnext;
+ construct_Cnext_array(D, m_doc_cnt, Cnext);
+ range_max_type rmaxq(&Cnext);
+ m_rmaxq = rmaxq;
+ }
+ }
+ m_doc_rmin_marked = bit_vector(m_doc_cnt, 0);
+ m_doc_rmax_marked = bit_vector(m_doc_cnt, 0);
+}
+
+size_type doc_cnt()const {
+ return m_doc_cnt;
+}
+
+size_type word_cnt()const {
+ return m_csa_full.size()-doc_cnt();
+}
+
+size_type serialize(std::ostream& out, structure_tree_node* v=NULL, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_doc_cnt, out, child, "doc_cnt");
+ written_bytes += m_csa_full.serialize(out, child, "csa_full");
+ written_bytes += serialize_vector(m_doc_isa, out, child, "doc_isa");
+ written_bytes += m_rminq.serialize(out, child, "rminq");
+ written_bytes += m_rmaxq.serialize(out, child, "rmaxq");
+ written_bytes += m_doc_border.serialize(out, child, "doc_border");
+ written_bytes += m_doc_border_rank.serialize(out, child, "doc_border_rank");
+ written_bytes += m_doc_border_select.serialize(out, child, "doc_border_select");
+ written_bytes += write_member(m_doc_max_len, out, child, "doc_max_len");
+ // helper bitvector m_doc_rmin_marked and m_doc_rmax_marked are not serialize
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+void load(std::istream& in) {
+ read_member(m_doc_cnt, in);
+ m_csa_full.load(in);
+ m_doc_isa.resize(m_doc_cnt);
+ load_vector(m_doc_isa, in);
+ m_rminq.load(in);
+ m_rmaxq.load(in);
+ m_doc_border.load(in);
+ m_doc_border_rank.load(in);
+ m_doc_border_rank.set_vector(&m_doc_border);
+ m_doc_border_select.load(in);
+ m_doc_border_select.set_vector(&m_doc_border);
+ read_member(m_doc_max_len, in);
+ // also initialize the helper bitvectors
+ m_doc_rmin_marked = bit_vector(m_doc_cnt);
+ m_doc_rmax_marked = bit_vector(m_doc_cnt);
+}
+
+void swap(doc_list_index_sada& dr) {
+ if (this != &dr) {
+ std::swap(m_doc_cnt, dr.m_doc_cnt);
+ m_csa_full.swap(dr.m_csa_full);
+ m_doc_isa.swap(dr.m_doc_isa);
+ m_rminq.swap(dr.m_rminq);
+ m_rmaxq.swap(dr.m_rmaxq);
+ m_doc_border.swap(dr.m_doc_border);
+ util::swap_support(m_doc_border_rank, dr.m_doc_border_rank,
+ &m_doc_border, &(dr.m_doc_border));
+ util::swap_support(m_doc_border_select, dr.m_doc_border_select,
+ &m_doc_border, &(dr.m_doc_border));
+ std::swap(m_doc_max_len, dr.m_doc_max_len);
+ m_doc_rmin_marked.swap(dr.m_doc_rmin_marked);
+ m_doc_rmax_marked.swap(dr.m_doc_rmax_marked);
+ }
+}
+
+//! Search for the k documents which contains the search term most frequent
+template<class t_pat_iter>
+size_t
+search(t_pat_iter begin,
+ t_pat_iter end,
+ result& res,
+size_t k) const {
+ size_type sp=1, ep=0;
+ if (0 == backward_search(m_csa_full, 0, m_csa_full.size()-1, begin, end, sp, ep)) {
+ res = result();
+ return 0;
+ } else {
+ res = result(sp, ep);
+ compute_tf_idf(sp, ep, res);
+ size_t kprime = std::min(res.size(), k);
+ auto comp = [](std::pair<size_type,size_type>& a,std::pair<size_type,size_type>& b) {
+ return (a.second != b.second) ? a.second > b.second : a.first < b.first;
+ };
+ partial_sort(res.begin(),res.begin()+kprime, res.end(), comp);
+ res.resize(kprime);
+ return ep-sp+1;
+ }
+}
+
+private:
+void compute_tf_idf(const size_type& sp, const size_type& ep, result& res)const {
+ vector<size_type> suffixes;
+ get_lex_smallest_suffixes(sp, ep, suffixes);
+ get_lex_largest_suffixes(sp, ep, suffixes);
+ sort(suffixes.begin(), suffixes.end());
+
+ for (size_type i=0; i < suffixes.size(); i+=2) {
+ size_type suffix_1 = suffixes[i];
+ size_type suffix_2 = suffixes[i+1];
+ size_type doc = m_doc_border_rank(suffix_1+1);
+ m_doc_rmin_marked[doc] = 0; // reset marking, which was set in get_lex_smallest_suffixes
+ m_doc_rmax_marked[doc] = 0; // get_lex_largest_suffixes
+
+ if (suffix_1 == suffix_2) { // if pattern occurs exactly once
+ res.push_back( {doc,1}); // add the #occurrence
+ } else {
+ size_type doc_begin = doc ? m_doc_border_select(doc) + 1 : 0;
+ size_type doc_sp = m_doc_isa[doc][ suffix_1 - doc_begin ];
+ size_type doc_ep = m_doc_isa[doc][ suffix_2 - doc_begin ];
+ if (doc_sp > doc_ep) {
+ std::swap(doc_sp, doc_ep);
+ }
+ res.push_back( {doc, doc_ep - doc_sp + 1});
+ }
+ }
+}
+
+void get_lex_smallest_suffixes(size_type sp, size_type ep, vector<size_type>& suffixes) const {
+ using lex_range_t = std::pair<size_type,size_type>;
+ std::stack<lex_range_t> stack;
+ stack.emplace(sp,ep);
+ while (!stack.empty()) {
+ auto range = stack.top();
+ stack.pop();
+ size_type rsp = std::get<0>(range);
+ size_type rep = std::get<1>(range);
+ if (rsp <= rep) {
+ size_type min_idx = m_rminq(rsp,rep);
+ size_type suffix = m_csa_full[min_idx];
+ size_type doc = m_doc_border_rank(suffix+1);
+
+ if (!m_doc_rmin_marked[doc]) {
+ suffixes.push_back(suffix);
+ m_doc_rmin_marked[doc] = 1;
+ stack.emplace(min_idx+1,rep);
+ stack.emplace(rsp,min_idx-1); // min_idx != 0, since `\0` is appended to string
+ }
+ }
+ }
+}
+
+void get_lex_largest_suffixes(size_type sp, size_type ep, vector<size_type>& suffixes) const {
+ using lex_range_t = std::pair<size_type,size_type>;
+ std::stack<lex_range_t> stack;
+ stack.emplace(sp,ep);
+ while (!stack.empty()) {
+ auto range = stack.top();
+ stack.pop();
+ size_type rsp = std::get<0>(range);
+ size_type rep = std::get<1>(range);
+ if (rsp <= rep) {
+ size_type max_idx = m_rmaxq(rsp,rep);
+ size_type suffix = m_csa_full[max_idx];
+ size_type doc = m_doc_border_rank(suffix+1);
+
+ if (!m_doc_rmax_marked[doc]) {
+ suffixes.push_back(suffix);
+ m_doc_rmax_marked[doc] = 1;
+ stack.emplace(rsp,max_idx - 1); // max_idx != 0, since `\0` is appended to string
+ stack.emplace(max_idx+1,rep);
+ }
+ }
+ }
+}
+
+//! Construct the doc_border bitvector by streaming the text file
+void
+construct_doc_border(const std::string& text_file,
+ doc_border_type& doc_border,
+size_type& doc_max_len) {
+ int_vector_buffer<WIDTH> text_buf(text_file);
+ bit_vector tmp_doc_border(text_buf.size(), 0); // create temporary uncompressed vector
+ doc_max_len = 0;
+ size_type len = 0;
+ for (size_type i = 0; i < text_buf.size(); ++i) {
+ if (t_doc_delim == text_buf[i]) {
+ tmp_doc_border[i] = 1;
+ doc_max_len = std::max(doc_max_len, len);
+ len = 0;
+ } else {
+ ++len;
+ }
+ }
+ doc_border = doc_border_type(tmp_doc_border);
+}
+
+void
+construct_doc_isa(const std::string& text_file,
+ const size_type doc_cnt,
+ SDSL_UNUSED const size_type doc_max_len,
+vector<int_vector<> >& doc_isa) {
+ doc_isa.resize(doc_cnt);
+ typename sa_tt::vec_type doc_buffer;
+ int_vector_buffer<WIDTH> text_buf(text_file);
+ size_type doc_id = 0;
+ for (size_type i = 0; i < text_buf.size(); ++i) {
+ if (t_doc_delim == text_buf[i]) {
+ if (doc_buffer.size() > 0) {
+ doc_buffer.push_back(0);
+ construct_doc_isa(doc_buffer, doc_isa[doc_id]);
+ ++doc_id;
+ }
+ doc_buffer.clear();
+ } else {
+ doc_buffer.push_back(text_buf[i]);
+ }
+ }
+}
+
+void
+construct_doc_isa(typename sa_tt::vec_type& doc_buffer,
+int_vector<>& doc_isa) {
+ int_vector<> sa(doc_buffer.size(), 0, bits::hi(doc_buffer.size())+1);
+ sa_tt::calc_sa(sa, doc_buffer);
+ util::bit_compress(sa);
+ doc_isa = sa;
+ for (size_type i = 0; i < doc_buffer.size(); ++i) {
+ doc_isa[sa[i]] = i;
+ }
+}
+
+void
+construct_D_array(int_vector_buffer<0>& sa_buf,
+ const doc_border_rank_type& doc_border_rank,
+ const size_type doc_cnt,
+int_vector<>& D) {
+ D = int_vector<>(sa_buf.size(), 0, bits::hi(doc_cnt+1)+1);
+ for (size_type i = 0; i < sa_buf.size(); ++i) {
+ D[i] = doc_border_rank(sa_buf[i]+1);
+ }
+}
+
+
+void
+construct_Cprev_array(const int_vector<>& D,
+ size_type doc_cnt,
+int_vector<>& Cprev) {
+ Cprev = int_vector<>(D.size(), 0, bits::hi(D.size())+1);
+ int_vector<> last_occ(doc_cnt+1, 0, bits::hi(D.size())+1);
+ for (size_type i = 0; i < D.size(); ++i) {
+ size_type doc = D[i];
+ Cprev[i] = last_occ[doc];
+ last_occ[doc] = i;
+ }
+}
+
+void
+construct_Cnext_array(const int_vector<>& D,
+ size_type doc_cnt,
+int_vector<>& Cnext) {
+ Cnext = int_vector<>(D.size(), 0, bits::hi(D.size())+1);
+ int_vector<> last_occ(doc_cnt+1, D.size(), bits::hi(D.size())+1);
+ for (size_type i = 0, j = D.size()-1; i < D.size(); ++i, --j) {
+ size_type doc = D[j];
+ Cnext[j] = last_occ[doc];
+ last_occ[doc] = j;
+ }
+}
+ };
+
+} // end namespace
+
+#endif
diff --git a/benchmark/document_retrieval/src/doc_list_index_sort.hpp b/benchmark/document_retrieval/src/doc_list_index_sort.hpp
new file mode 100644
index 0000000..90e6943
--- /dev/null
+++ b/benchmark/document_retrieval/src/doc_list_index_sort.hpp
@@ -0,0 +1,185 @@
+/*!
+ * this file contains a simple SORT baseline
+ */
+#ifndef DOCUMENT_LISING_SORT
+#define DOCUMENT_LISING_SORT
+
+#include <sdsl/suffix_arrays.hpp>
+#include <sdsl/rmq_support.hpp>
+#include <string>
+#include <vector>
+#include <fstream>
+#include <list>
+#include <utility>
+#include "doc_list_index.hpp"
+
+using std::vector;
+
+namespace sdsl
+{
+
+template<
+class t_csa = csa_wt<wt_huff<rrr_vector<63>>, 1000000, 1000000>,
+ typename t_csa::char_type t_doc_delim = 1
+ >
+class doc_list_index_sort
+{
+ public:
+ typedef t_csa csa_type;
+ typedef int_vector<> d_type;
+ typedef int_vector<>::size_type size_type;
+ typedef std::vector<std::pair<size_type,size_type>> list_type;
+ typedef doc_list_tag index_category;
+
+ enum { WIDTH = t_csa::alphabet_category::WIDTH };
+
+ class result : public list_type
+ {
+ private:
+ size_type m_sp, m_ep;
+ public:
+ // Number of occurrences
+ size_type count() {
+ return m_ep-m_sp+1;
+ }
+
+ result(size_type sp, size_type ep,list_type&& l) : list_type(l), m_sp(1), m_ep(0) {}
+ result() : m_sp(1), m_ep(0) {}
+ result(size_type sp, size_type ep) : m_sp(sp), m_ep(ep) {}
+ result& operator=(const result& res) {
+ if (this != &res) {
+ list_type::operator=(res);
+ m_sp = res.m_sp;
+ m_ep = res.m_ep;
+ }
+ return *this;
+ }
+ };
+
+ protected:
+ size_type m_doc_cnt; // number of documents in the collection
+ csa_type m_csa_full; // CSA built from the collection text
+ d_type m_d; // wtd build from the collection text
+ public:
+
+ //! Default constructor
+ doc_list_index_sort() { }
+
+ doc_list_index_sort(std::string file_name, sdsl::cache_config& cconfig, uint8_t num_bytes) {
+ construct(m_csa_full, file_name, cconfig, num_bytes);
+
+ const char* KEY_TEXT = key_text_trait<WIDTH>::KEY_TEXT;
+ std::string text_file = cache_file_name(KEY_TEXT, cconfig);
+
+ bit_vector doc_border;
+ construct_doc_border(text_file,doc_border);
+ bit_vector::rank_1_type doc_border_rank(&doc_border);
+ m_doc_cnt = doc_border_rank(doc_border.size());
+
+ int_vector_buffer<0> sa_buf(cache_file_name(conf::KEY_SA, cconfig));
+ construct_D_array(sa_buf, doc_border_rank, m_doc_cnt, m_d);
+ }
+
+ size_type doc_cnt()const {
+ return m_doc_cnt; // subtract one, since zero does not count
+ }
+
+ size_type word_cnt()const {
+ return m_d.size()-doc_cnt();
+ }
+
+ size_type sigma()const {
+ return m_csa_full.sigma;
+ }
+
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=NULL, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_doc_cnt, out, child, "doc_cnt");
+ written_bytes += m_csa_full.serialize(out, child, "csa_full");
+ written_bytes += m_d.serialize(out, child, "D");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ read_member(m_doc_cnt, in);
+ m_csa_full.load(in);
+ m_d.load(in);
+ }
+
+ void swap(doc_list_index_sort& dr) {
+ if (this != &dr) {
+ std::swap(m_doc_cnt, dr.m_doc_cnt);
+ m_csa_full.swap(dr.m_csa_full);
+ m_d.swap(dr.m_d);
+ }
+ }
+
+ //! Search for the k documents which contain the search term most frequent
+ template<class t_pat_iter>
+ size_type search(t_pat_iter begin, t_pat_iter end, result& res, size_t k) const {
+ size_type sp=1, ep=0;
+ if (0 == backward_search(m_csa_full, 0, m_csa_full.size()-1, begin, end, sp, ep)) {
+ res = result();
+ return 0;
+ } else {
+ res = result(sp, ep);
+ size_t n = ep-sp+1;
+ std::vector<uint64_t> tmp(n);
+ std::copy(m_d.begin()+sp,m_d.begin()+ep+1,tmp.begin());
+ std::sort(tmp.begin(),tmp.end());
+ size_t last = tmp[0];
+ size_t f_dt = 1;
+ for (size_t i=1; i<n; i++) {
+ if (tmp[i] != last) {
+ res.emplace_back(last,f_dt);
+ last = tmp[i];
+ f_dt = 1;
+ } else {
+ f_dt++;
+ }
+ }
+ res.emplace_back(last,f_dt);
+ if (res.size() < k) k = res.size();
+ static auto freq_cmp = [](const std::pair<size_type,size_type>& a,
+ const std::pair<size_type,size_type>& b) {
+ return a.second > b.second;
+ };
+ std::partial_sort(res.begin(),res.begin()+k,res.end(),freq_cmp);
+ res.resize(k);
+
+ return ep-sp+1;
+ }
+ }
+
+ private:
+ //! Construct the doc_border bitvector by streaming the text file
+ void
+ construct_doc_border(const std::string& text_file, bit_vector& doc_border) {
+ int_vector_buffer<WIDTH> text_buf(text_file);
+ doc_border = bit_vector(text_buf.size(), 0);
+ for (size_type i = 0; i < text_buf.size(); ++i) {
+ if (t_doc_delim == text_buf[i]) {
+ doc_border[i] = 1;
+ }
+ }
+ }
+
+ void
+ construct_D_array(int_vector_buffer<0>& sa_buf,
+ bit_vector::rank_1_type& doc_border_rank,
+ const size_type doc_cnt,
+ int_vector<>& D) {
+ D = int_vector<>(sa_buf.size(), 0, bits::hi(doc_cnt+1)+1);
+ for (size_type i = 0; i < sa_buf.size(); ++i) {
+ uint64_t d = doc_border_rank(sa_buf[i]+1);
+ D[i] = d;
+ }
+ }
+};
+
+} // end namespace
+
+#endif
diff --git a/benchmark/document_retrieval/src/gen_pattern.cpp b/benchmark/document_retrieval/src/gen_pattern.cpp
new file mode 100644
index 0000000..e0b3608
--- /dev/null
+++ b/benchmark/document_retrieval/src/gen_pattern.cpp
@@ -0,0 +1,82 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <chrono>
+#include <algorithm>
+#include <random>
+
+using namespace std;
+using namespace sdsl;
+
+#ifndef INT_ALPHABET
+using csa_t = csa_wt<wt_huff<rrr_vector<63>>>;
+uint8_t num_bytes = 1;
+#else
+using csa_t = csa_wt<wt_int<rrr_vector<63>>>;
+uint8_t num_bytes = 0;
+#endif
+
+int main(int argc, char* argv[])
+{
+ if (argc < 7) {
+ cout << "Usage: " << argv[0] << " collection_file collection_csa tmp_dir pattern_length pattern_number pattern_file" << endl;
+ cout << " Generates an index and stores result in index_file" << endl;
+ cout << " Temporary files are stored in tmp_dir." << endl;
+ return 1;
+ }
+ string collection_file = argv[1];
+ string id = util::basename(collection_file);
+ string collection_csa = argv[2];
+ string tmp_dir = argv[3];
+ uint64_t pat_len = stoull(argv[4]);
+ uint64_t pat_num = stoull(argv[5]);
+ string pattern_file = argv[6];
+
+ csa_t csa;
+ cache_config cconfig(false, tmp_dir, id);
+ if (!load_from_file(csa, collection_csa)) {
+ if (num_bytes == 0) {
+ int_vector<> v;
+ load_from_file(v, collection_file);
+ std::cout<<"v.size()="<<v.size()<<std::endl;
+ }
+ construct(csa, collection_file, cconfig, num_bytes);
+ std::cout<<util::demangle2(typeid(csa_t).name())<<std::endl;
+ store_to_file(csa, collection_csa);
+ }
+
+ // if pat_len < size of CSA - separators - sentinel
+ if (pat_len+1 > csa.size() - csa.bwt.rank(csa.size(), 1)) {
+ std::cerr<<"pat_len > " << " length of the documents" << std::endl;
+ return 1;
+ }
+
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, csa.size()-pat_len);
+ auto dice = bind(distribution, rng);
+
+ ofstream out(pattern_file);
+ if (!out) {
+ std::cerr<<"Could not open file "<<pattern_file<<" for output"<<std::endl;
+ return 1;
+ }
+
+ uint64_t pat_cnt=0;
+ while (pat_cnt < pat_num) {
+ uint64_t pos = dice();
+ auto pat = extract(csa, pos, pos+pat_len-1);
+ bool valid = true;
+ for (uint64_t i=0; valid and i < pat.size(); ++i) {
+ // if pattern includes separator or newline in byte sequence
+ if (pat[i] == 1 or (num_bytes == 1 and pat[i]=='\n')) {
+ valid = false;
+ }
+ }
+ if (valid) {
+ if (csa_t::alphabet_category::WIDTH == 0 or
+ count(csa, pat.begin(), pat.end()) >= 5) {
+ out << pat << "\n";
+ ++pat_cnt;
+ }
+ }
+ }
+}
diff --git a/benchmark/document_retrieval/src/query_idx.cpp b/benchmark/document_retrieval/src/query_idx.cpp
new file mode 100644
index 0000000..c2d1f3d
--- /dev/null
+++ b/benchmark/document_retrieval/src/query_idx.cpp
@@ -0,0 +1,94 @@
+#include "doc_list_index.hpp"
+#include <iostream>
+#include <chrono>
+#include <algorithm>
+#include <sstream>
+
+using namespace std;
+using namespace sdsl;
+
+using idx_type = IDX_TYPE;
+
+const size_t buf_size=1024*128;
+char buffer[buf_size];
+
+template<uint8_t t_width>
+struct myline {
+ static string parse(char* str) {
+ return string(str);
+ }
+};
+
+template<>
+struct myline<0> {
+ static vector<uint64_t> parse(char* str) {
+ vector<uint64_t> res;
+ stringstream ss(str);
+ uint64_t x;
+ while (ss >> x) {
+ res.push_back(x);
+ }
+ return res;
+ }
+};
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3) {
+ cout << "Usage: " << argv[0] << " index_file pattern_file" << endl;
+ cout << " Process all queries with the index." << endl;
+ return 1;
+ }
+ string index_file = string(argv[1]);
+ string pattern_file = string(argv[2]);
+ idx_type idx;
+
+ using timer = std::chrono::high_resolution_clock;
+
+ std::cout<<"# index_file = "<<index_file<<endl;
+ if (!load_from_file(idx, index_file)) {
+ std::cerr << "Could not load index file" << std::endl;
+ return 1;
+ }
+ std::cout<<"# pattern_file = "<<pattern_file<<endl;
+ std::cout<<"# doc_cnt = "<<idx.doc_cnt()<<endl;
+ std::cout<<"# word_cnt = "<<idx.word_cnt()<<endl;
+ ifstream in(pattern_file);
+ if (!in) {
+ std::cerr << "Could not load pattern file" << std::endl;
+ return 1;
+ }
+
+ using timer = std::chrono::high_resolution_clock;
+ size_t q_len = 0;
+ size_t q_cnt = 0;
+ size_t sum = 0;
+ size_t sum_fdt = 0;
+ bool tle = false; // flag: time limit exceeded
+ auto start = timer::now();
+ while (!tle and in.getline(buffer, buf_size)) {
+ auto q_start = timer::now();
+ typename idx_type::result res;
+ auto query = myline<idx_type::WIDTH>::parse(buffer);
+ q_len += query.size();
+ ++q_cnt;
+ size_t x = idx.search(query.begin(), query.end(), res, 10);
+ sum += x;
+for (auto& r : res) {
+ sum_fdt += r.second;
+ }
+ auto q_time = timer::now()-q_start;
+ // single query should not take more then 5 seconds
+ if (std::chrono::duration_cast<std::chrono::seconds>(q_time).count() > 5) {
+ tle = true;
+ }
+ }
+ auto stop = timer::now();
+ auto elapsed = stop-start;
+ std::cout<<"# TLE = " << tle << endl;
+ std::cout<<"# query_len = "<<q_len/q_cnt<<endl;
+ std::cout<<"# queries = " <<q_cnt <<endl;
+ std::cout<<"# time_per_query = "<<std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()/q_cnt <<endl;
+ std::cout<<"# check_sum = "<<sum<<endl;
+ std::cout<<"# check_sum_fdt = "<<sum_fdt<<endl;
+}
diff --git a/benchmark/document_retrieval/src/size_of_idx.cpp b/benchmark/document_retrieval/src/size_of_idx.cpp
new file mode 100644
index 0000000..937ed1e
--- /dev/null
+++ b/benchmark/document_retrieval/src/size_of_idx.cpp
@@ -0,0 +1,30 @@
+#include "doc_list_index.hpp"
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace sdsl;
+
+using idx_type = IDX_TYPE;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " index_file [html_file]" << endl;
+ return 1;
+ }
+ string index_file = string(argv[1]);
+ idx_type idx;
+
+ if (!load_from_file(idx, index_file)) {
+ std::cerr << "Could not load index file" << std::endl;
+ return 1;
+ }
+ if (argc > 2) {
+ ofstream out(argv[2]);
+ write_structure<HTML_FORMAT>(idx, out);
+ } else {
+ cout<<"# index_file = "<<index_file<<endl;
+ cout << "# size = " << size_in_bytes(idx) << endl;
+ }
+}
diff --git a/benchmark/document_retrieval/src/word_pat2char_pat.cpp b/benchmark/document_retrieval/src/word_pat2char_pat.cpp
new file mode 100644
index 0000000..94f01fe
--- /dev/null
+++ b/benchmark/document_retrieval/src/word_pat2char_pat.cpp
@@ -0,0 +1,46 @@
+#include <iostream>
+#include <map>
+#include <string>
+#include <cstdint>
+#include <fstream>
+#include <string>
+#include <sstream>
+
+using namespace std;
+
+const size_t buf_size=1024*128;
+char buffer[buf_size];
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3) {
+ cout << "Usage: " << argv[0] << " patten-file .dic-file" << endl;
+ return 1;
+ }
+ ifstream dic_in(argv[2]);
+ if (!dic_in) {
+ cout << "Could not open dictionary file '" << argv[2] << "'" << endl;
+ return 1;
+ }
+ ifstream pat_in(argv[1]);
+ if (!pat_in) {
+ cout << "Could not open pattern file '" << argv[1] << "'" << endl;
+ return 1;
+ }
+ std::map<uint64_t, string> i2w;
+ string word;
+ while (dic_in >> word) {
+ uint64_t nr, occ;
+ dic_in >> nr >> occ;
+ i2w[nr] = word;
+ }
+ while (pat_in.getline(buffer, buf_size)) {
+ stringstream ss;
+ ss << string(buffer);
+ uint64_t w;
+ while (ss >> w) {
+ cout << i2w[w] << " ";
+ }
+ cout << "\n";
+ }
+}
diff --git a/benchmark/document_retrieval/test_case.config b/benchmark/document_retrieval/test_case.config
new file mode 100644
index 0000000..3765705
--- /dev/null
+++ b/benchmark/document_retrieval/test_case.config
@@ -0,0 +1,8 @@
+# Configuration for test files
+# (1) Identifier for test file
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENWIKISML;../data/enwiki-20130805-pages-articles1.txt;enwiki-sml;http://people.eng.unimelb.edu.au/sgog/data/enwiki-20130805-pages-articles1.txt.gz
+PROTEINS;../data/proteins.txt;proteins;http://people.eng.unimelb.edu.au/sgog/data/proteins.txt.gz
+#WSJ;../data/wsj.char.100MB;WSJ
diff --git a/benchmark/document_retrieval/test_case_int.config b/benchmark/document_retrieval/test_case_int.config
new file mode 100644
index 0000000..3f4b992
--- /dev/null
+++ b/benchmark/document_retrieval/test_case_int.config
@@ -0,0 +1,6 @@
+# Configuration for integer test files
+# (1) Identifier for test file
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENWIKISMLINT;../data/enwiki-20130805-pages-articles1.int.sdsl;enwiki-sml-int;http://people.eng.unimelb.edu.au/sgog/data/enwiki-20130805-pages-articles1.int.sdsl.gz
diff --git a/benchmark/document_retrieval/visualize/.gitignore b/benchmark/document_retrieval/visualize/.gitignore
new file mode 100644
index 0000000..a1a6e0d
--- /dev/null
+++ b/benchmark/document_retrieval/visualize/.gitignore
@@ -0,0 +1,11 @@
+doc_re_time.aux
+doc_re_time.log
+doc_re_time.pdf
+fig-runtime.tex
+fig-runtime_int.tex
+tbl-indexes.tex
+tbl-indexes_int.tex
+tbl-sizes_int.tex
+tbl-sizes.tex
+LaTeX.log
+R.log
diff --git a/benchmark/document_retrieval/visualize/Makefile b/benchmark/document_retrieval/visualize/Makefile
new file mode 100644
index 0000000..82973d7
--- /dev/null
+++ b/benchmark/document_retrieval/visualize/Makefile
@@ -0,0 +1,28 @@
+include ../../../Make.helper
+CONFIG_FILES=../index.config ../test_case.config ../pattern_length.config \
+ ../index_int.config ../test_case_int.config ../pattern_length_int.config
+
+all: doc_re_time.pdf
+
+doc_re_time.pdf: doc_re_time.tex \
+ fig-runtime.tex fig-runtime_int.tex \
+ tbl-sizes.tex tbl-sizes_int.tex \
+ tbl-indexes.tex tbl-indexes_int.tex \
+ tbl-collections.tex tbl-collections_int.tex
+ @echo "Use pdflatex to generate doc_re_time.pdf"
+ @pdflatex doc_re_time.tex >> LaTeX.log 2>&1
+
+#tbl-locate.tex fig-locate.tex: ../../basic_functions.R locate.R $(CONFIG_FILES) ../results/all.txt
+# @echo "Use R to generate tbl-locate.tex and fig-locate.tex"
+fig-runtime.tex fig-runtime_int.tex tbl-indexes.tex tbl-indexes_int.tex tbl-sizes.tex tbl-sizes_int.tex tbl-collections.tex tbl-collections_int.tex: ../../basic_functions.R runtime.R \
+ $(CONFIG_FILES) ../results/all.txt \
+ ../info/sizes.txt ../info/sizes_int.txt
+ @R --vanilla < runtime.R > R.log 2>&1
+
+clean:
+ rm -f doc_re_time.pdf doc_re_time.aux \
+ fig-runtime.tex tbl-indexes.tex \
+ fig-runtime_int.tex tbl-indexes_int.tex \
+ tbl-sizes.tex tbl-sizes_int.tex \
+ tbl-collections.tex tbl-collections_int.tex \
+ doc_re_time.log R.log LaTeX.log
diff --git a/benchmark/document_retrieval/visualize/doc_re_time.tex b/benchmark/document_retrieval/visualize/doc_re_time.tex
new file mode 100644
index 0000000..d530fb9
--- /dev/null
+++ b/benchmark/document_retrieval/visualize/doc_re_time.tex
@@ -0,0 +1,61 @@
+\documentclass[9pt,a4paper]{scrartcl}
+\usepackage{array}
+\usepackage{booktabs}
+\usepackage{ragged2e}
+\usepackage{tikz}
+
+\begin{document}
+\pagestyle{empty}
+
+\begin{table}
+\centering
+\input{tbl-collections.tex}
+\caption{Statistics of the character based collections.}
+\end{table}
+
+\begin{figure}
+\input{fig-runtime.tex}
+\caption{Average query time to find the top-$10$ documents (frequency measure)
+for different pattern length using character based indexes. For each query length, $200$ pattern were
+queried.}
+\end{figure}
+
+\begin{table}
+\centering
+\input{tbl-indexes.tex}
+\caption{Class definition of character indexes used in the experiment.}
+\end{table}
+
+\begin{table}
+\centering
+\input{tbl-sizes.tex}
+\caption{Size of character indexes.}
+\end{table}
+
+\begin{table}
+\centering
+\input{tbl-collections_int.tex}
+\caption{Statistics of the word based collections.}
+\end{table}
+
+\begin{figure}
+\input{fig-runtime_int.tex}
+\caption{Average query time to find the top-$10$ documents (frequency measure)
+for different pattern length using word bases indexes. For each query length, $200$ pattern were
+queried.}
+\end{figure}
+
+
+\begin{table}
+\centering
+\input{tbl-indexes_int.tex}
+\caption{Class definition of word indexes used in the experiment.}
+\end{table}
+
+\begin{table}
+\centering
+\input{tbl-sizes_int.tex}
+\caption{Size of word indexes.}
+\end{table}
+
+\end{document}
diff --git a/benchmark/document_retrieval/visualize/index-filter.config b/benchmark/document_retrieval/visualize/index-filter.config
new file mode 100644
index 0000000..5466d68
--- /dev/null
+++ b/benchmark/document_retrieval/visualize/index-filter.config
@@ -0,0 +1,10 @@
+# Use this file to specify which indexes are listed in the report doc_re_time.pdf
+# and how they look like in the report.
+#
+# List all the index ids which should be included in the report. Note that
+# the listed index ids must also be present in the file `../index.config`.
+# Eeach INDEX_ID should be listed on a separate line followed by the style:
+# [pch];[lty];[col] (point type, line type, and color).
+GREEDY;1;solid;black
+QPROBING; 2;solid;blue
+SADA;3;solid;red
diff --git a/benchmark/document_retrieval/visualize/index-filter_int.config b/benchmark/document_retrieval/visualize/index-filter_int.config
new file mode 100644
index 0000000..9eef0a9
--- /dev/null
+++ b/benchmark/document_retrieval/visualize/index-filter_int.config
@@ -0,0 +1,10 @@
+# Use this file to specify which indexes are listed in the report doc_re_time.pdf
+# and how they look like in the report.
+#
+# List all the index ids which should be included in the report. Note that
+# the listed index ids must also be present in the file `../index_int.config`.
+# Eeach INDEX_ID should be listed on a separate line followed by the style:
+# [pch];[lty];[col] (point type, line type, and color).
+GREEDYINT;1;solid;black
+QPROBINGINT; 2;solid;blue
+SADAINT;3;solid;red
diff --git a/benchmark/document_retrieval/visualize/runtime.R b/benchmark/document_retrieval/visualize/runtime.R
new file mode 100644
index 0000000..6cf5973
--- /dev/null
+++ b/benchmark/document_retrieval/visualize/runtime.R
@@ -0,0 +1,171 @@
+require(tikzDevice)
+source("../../basic_functions.R")
+
+
+mypaste <- function(...){
+ paste(...,sep="")
+}
+
+my_format2 <- function(...){
+ format(..., nsmall=2,digits=2, big.mark=",")
+}
+
+process_data <- function(suf){
+
+# Files
+f_idxfilterconfig = mypaste("index-filter",suf,".config")
+f_idxconfig = mypaste("../index",suf,".config")
+f_tcconfig = mypaste("../test_case",suf,".config")
+f_results = mypaste("../results/all",suf,".txt")
+f_sizes = mypaste("../info/sizes",suf,".txt")
+f_fig_runtime = mypaste("fig-runtime",suf,".tex")
+f_tbl_indexes = mypaste("tbl-indexes",suf,".tex")
+f_tbl_sizes = mypaste("tbl-sizes",suf,".tex")
+f_tbl_collections = mypaste("tbl-collections",suf,".tex")
+
+# Load filter information
+config <- readConfig(f_idxfilterconfig,c("IDX_ID","PCH","LTY","COL"))
+# Load index and test case data
+idx_config <- readConfig(f_idxconfig,c("IDX_ID","SDSL_TYPE","LATEX-NAME"))
+tc_config <- readConfig(f_tcconfig,c("TC_ID","PATH","LATEX-NAME","URL"))
+
+# Load data
+raw <- data_frame_from_key_value_pairs(f_results)
+raw <- raw[c("TC_ID","IDX_ID","time_per_query","query_len","TLE","doc_cnt","word_cnt")]
+raw["time_per_query"] <- raw["time_per_query"]/1000.0
+
+# Filter indexes
+raw <- raw[raw[["IDX_ID"]]%in%config[["IDX_ID"]],]
+raw[["IDX_ID"]] <- factor(raw[["IDX_ID"]])
+
+# Split by TC_ID
+d <- split(raw,raw["TC_ID"])
+
+tikz(f_fig_runtime, width = 5.5, height = 6, standAlone = F)
+
+multi_figure_style( length(d)/2+1, 2 )
+count <- 0
+nr <- 0
+xlabnr <- (2*(length(d)/2)-1)
+
+for( tc_id in names(d) ){
+
+ plot( c(1e-9), c(1e-9), xlim=c(min(raw["query_len"]),max(raw["query_len"])),
+ ylim=c(0.01,1000),
+ ylab="", xlab="", xaxt="n", log="y" )
+ box(col="gray")
+ abline(h=c(seq(1,10)*0.1,seq(2,10)*1,seq(2,10)*10, seq(2,10)*100), col="lightgray")
+ grid(lty="solid")
+ if ( nr %% 2 == 0 ){
+ ylable <- "Time per query (milliseconds)"
+ axis( 2, at = axTicks(2) )
+ mtext(ylable, side=2, line=2, las=0)
+ }
+ axis( 1, at = axTicks(1), labels=(nr>=xlabnr) )
+ if ( nr >= xlabnr ){
+ xlable <- "Pattern length"
+ mtext(xlable, side=1, line=2, las=0)
+ }
+# Split by IDX_ID
+ dd <- split(d[[tc_id]],d[[tc_id]]["IDX_ID"])
+ for( idx_id in names(dd) ){
+ ddd <- dd[[idx_id]]
+ ddd <- subset(ddd, ddd[["TLE"]]==0)
+ lines(ddd[["query_len"]], ddd[["time_per_query"]],
+ lwd=1, type="b", pch=config[idx_id, "PCH"],
+ lty=config[idx_id, "LTY"],
+ col=config[idx_id, "COL"])
+ }
+
+ draw_figure_heading( sprintf("instance = \\textsc{%s}",tc_config[tc_id,"LATEX-NAME"]) )
+
+ nr <- nr+1
+
+ if ( nr == 1 ){ # plot legend
+ plot(NA, NA, xlim=c(0,1),ylim=c(0,1),ylab="", xlab="", bty="n", type="n", yaxt="n", xaxt="n")
+ idx_ids <- as.character(unique(raw[["IDX_ID"]]))
+ legend( "top", legend=idx_config[idx_ids,"LATEX-NAME"], pch=config[idx_ids,"PCH"], col=config[idx_ids,"COL"],
+ lty=config[idx_ids,"LTY"], bty="n", y.intersp=1.5, ncol=2, title="Index", cex=1.2)
+ nr <- nr+1
+ }
+
+}
+
+dev.off()
+
+sink(f_tbl_indexes)
+cat(typeInfoTable(f_idxconfig, config[["IDX_ID"]], 1, 3, 2))
+sink(NULL)
+
+sink(f_tbl_sizes)
+raw <- data_frame_from_key_value_pairs(f_sizes)
+# Filter indexes
+raw <- raw[raw[["IDX_ID"]]%in%config[["IDX_ID"]],]
+raw[["IDX_ID"]] <- factor(raw[["IDX_ID"]])
+
+d <- split(raw,raw[["IDX_ID"]])
+
+cat(paste("\\begin{tabular}{@{}l*{",length(names(d)) ,"}{rr@{\ }l}@{}}",sep=""))
+cat("\\toprule\n")
+cat(paste("Collection& & \\multicolumn{",length(names(d))*3-1,"}{c}{Index size in MiB (fraction of original collection)}\\\\\n",sep=""))
+cat(paste("\\cmidrule{1-1}\\cmidrule{3-",length(names(d))*3+1,"}\n",sep=""))
+for( idx_id in names(d) ){
+ cat(paste("&\\ &\\multicolumn{2}{c}{",idx_config[idx_id,"LATEX-NAME"],"}",sep=""))
+}
+cat("\\\\[2ex]\n")
+
+dd <- split(raw,raw[["TC_ID"]])
+
+for ( tc_id in names(dd) ){
+ cat("{\\sc ",tc_config[tc_id,"LATEX-NAME"],"}")
+ ddd <- split(dd[[tc_id]],dd[[tc_id]][["IDX_ID"]])
+ for ( idx_id in names(d) ){
+ row <- ddd[[idx_id]]
+ cat(paste("&&",my_format2(row["size"]/1024**2),"&",sprintf("(%.2f)",row["size"]/row["text_size"])))
+ }
+ cat("\\\\\n")
+}
+cat("\\bottomrule\n")
+cat("\\end{tabular}")
+
+sink(NULL)
+
+sink(f_tbl_collections)
+raw <- data_frame_from_key_value_pairs(f_results)
+
+cat(paste("\\begin{tabular}{@{}l*{5}{r}@{}}\n",sep=""))
+cat("\\toprule\n")
+elem = "Characters"
+if ( suf=="_int" ) {
+ elem = "Words"
+}
+cat(paste("Collection & ",elem," & Documents & ","Avg. doc. len.& gzip-compr.& xz-compr.\\\\[1ex]\n",sep=""))
+
+d <- split(raw,raw["TC_ID"])
+for ( tc_id in names(d) ){
+ zfile = paste("../",tc_config[tc_id,"PATH"],".z.info",sep="")
+ gzipcomp = NA
+ xzcomp = NA
+ if ( file.exists(zfile) ){
+ comp_info <- readConfig(zfile,c("NAME","RATIO","COMMAND"))
+ gzipcomp = my_format2(comp_info["gzip","RATIO"])
+ xzcomp = my_format2(comp_info["xz","RATIO"])
+ }
+ doc_cnt_i <- unique(d[[tc_id]][["doc_cnt"]])
+ word_cnt_i <- unique(d[[tc_id]][["word_cnt"]])
+ doc_cnt <- format(doc_cnt_i, big.mark=",")
+ word_cnt <- format(word_cnt_i, big.mark=",")
+ avg_doc_len <- my_format2(word_cnt_i/doc_cnt_i)
+ cat("{\\sc ",tc_config[tc_id,"LATEX-NAME"],"}")
+ cat("&",word_cnt,"&",doc_cnt,"&",avg_doc_len,"&",
+ gzipcomp, "&", xzcomp,"\\\\\n")
+}
+cat("\\bottomrule\n")
+cat("\\end{tabular}")
+sink(NULL)
+
+}
+
+
+process_data("")
+process_data("_int")
diff --git a/benchmark/indexing_count/Makefile b/benchmark/indexing_count/Makefile
new file mode 100644
index 0000000..9c03b96
--- /dev/null
+++ b/benchmark/indexing_count/Makefile
@@ -0,0 +1,134 @@
+include ../Make.helper
+CFLAGS = $(MY_CXX_FLAGS) # in compile_options.config
+LIBS = -lsdsl -ldivsufsort -ldivsufsort64
+SRC_DIR = src
+TMP_DIR = ../tmp
+PAT_DIR = pattern
+BIN_DIR = bin
+
+TC_PATHS:=$(call config_column,test_case.config,2)
+TC_IDS:=$(call config_ids,test_case.config)
+IDX_IDS:=$(call config_ids,index.config)
+COMPILE_IDS:=$(call config_ids,compile_options.config)
+
+RESULT_FILE=results/all.txt
+
+QUERY_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach COMPILE_ID,$(COMPILE_IDS),$(BIN_DIR)/query_idx_$(IDX_ID).$(COMPILE_ID)))
+BUILD_EXECS = $(foreach IDX_ID,$(IDX_IDS),$(BIN_DIR)/build_idx_$(IDX_ID))
+INFO_EXECS = $(foreach IDX_ID,$(IDX_IDS),$(BIN_DIR)/info_$(IDX_ID))
+PATTERNS = $(foreach TC_ID,$(TC_IDS),$(PAT_DIR)/$(TC_ID).pattern)
+INDEXES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),indexes/$(TC_ID).$(IDX_ID)))
+INFO_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),info/$(TC_ID).$(IDX_ID).html))
+TIME_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach COMPILE_ID,$(COMPILE_IDS),results/$(TC_ID).$(IDX_ID).$(COMPILE_ID))))
+COMP_FILES = $(addsuffix .z.info,$(TC_PATHS))
+
+all: $(BUILD_EXECS) $(QUERY_EXECS) $(INFO_EXECS)
+
+info: $(INFO_EXECS) $(INFO_FILES)
+
+indexes: $(INDEXES)
+
+input: $(TC_PATHS)
+
+pattern: input $(PATTERNS) $(BIN_DIR)/genpatterns
+
+compression: input $(COMP_FILES)
+
+timing: input $(INDEXES) pattern $(TIME_FILES) compression info
+ @cat $(TIME_FILES) > $(RESULT_FILE)
+ @cd visualize; make
+
+# results/[TC_ID].[IDX_ID].[COMPILE_ID]
+results/%: $(BUILD_EXECS) $(QUERY_EXECS) $(PATTERNS) $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval COMPILE_ID:=$(call dim,3,$*))
+ $(eval TC_NAME:=$(call config_select,test_case.config,$(TC_ID),3))
+ @echo "# TC_ID = $(TC_ID)" >> $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# COMPILE_ID = $(COMPILE_ID)" >> $@
+ @echo "# test_case = $(TC_NAME)" >> $@
+ @echo "Run timing for $(IDX_ID).$(COMPILE_ID) on $(TC_ID)"
+ $(BIN_DIR)/query_idx_$(IDX_ID).$(COMPILE_ID) \
+ indexes/$(TC_ID) C < $(PAT_DIR)/$(TC_ID).pattern 2>> $@
+
+
+# indexes/[TC_ID].[IDX_ID]
+indexes/%: $(BUILD_EXECS)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ @echo "Building index $(IDX_ID) on $(TC)"
+ $(BIN_DIR)/build_idx_$(IDX_ID) $(TC) $(TMP_DIR) $@
+
+# info/[TC_ID].[IDX_ID]
+info/%.html: $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ @echo "Generating info for $(IDX_ID) on $(TC_ID)"
+ @$(BIN_DIR)/info_$(IDX_ID) indexes/$(TC_ID).$(IDX_ID) > $@
+
+$(PAT_DIR)/%.pattern: $(BIN_DIR)/genpatterns
+ @echo $*
+ $(eval TC:=$(call config_select,test_case.config,$*,2))
+ $(BIN_DIR)/genpatterns $(TC) 20 50000 $@
+
+$(BIN_DIR)/genpatterns: $(SRC_DIR)/genpatterns.c
+ @echo "Build pattern generation program"
+ @$(MY_CC) -O3 -o $@ $(SRC_DIR)/genpatterns.c
+
+# $(BIN_DIR)/build_idx_[IDX_ID]
+$(BIN_DIR)/build_idx_%: $(SRC_DIR)/build_index_sdsl.cpp index.config
+ $(eval IDX_TYPE:=$(call config_select,index.config,$*,2))
+ @echo "Compiling build_idx_$*"
+ @$(MY_CXX) $(CFLAGS) -O3 -DNDEBUG \
+ -DSUF=\"$*\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/build_index_sdsl.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the count experiment. $(BIN_DIR)/count_queries_[IDX_ID].[COMPILE_ID]
+$(BIN_DIR)/query_idx_%: $(SRC_DIR)/run_queries_sdsl.cpp index.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval COMPILE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval COMPILE_OPTIONS:=$(call config_select,compile_options.config,$(COMPILE_ID),2))
+ @echo "Compiling query_idx_$*"
+ @$(MY_CXX) $(CFLAGS) $(COMPILE_OPTIONS) \
+ -DSUF=\"$(IDX_ID)\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/run_queries_sdsl.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the executables which output the indexes structure.
+$(BIN_DIR)/info_%: $(SRC_DIR)/info.cpp index.config
+ $(eval IDX_TYPE:=$(call config_select,index.config,$*,2))
+ @echo "Compiling info_$*"
+ @$(MY_CXX) $(CFLAGS) -O3 -DNDEBUG \
+ -DSUF=\"$*\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/info.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ @rm -f $(QUERY_EXECS) $(BUILD_EXECS) $(INFO_EXECS)
+
+clean:
+ @echo "Remove executables and indexes"
+ @rm -f $(QUERY_EXECS) $(BUILD_EXECS) $(INFO_EXECS) \
+ $(INFO_FILES) $(INDEXES) $(BIN_DIR)/genpatterns
+
+cleanresults:
+ @echo "Remove result files"
+ @rm -f $(TIME_FILES) $(RESULT_FILE) $(INFO_FILES)
+ @rm -f $(PATTERNS)
+
+cleanall: clean cleanresults
+ @echo "Remove all generated files."
+ @rm -f $(TMP_DIR)/*
+ @rm -f $(PAT_DIR)/*
diff --git a/benchmark/indexing_count/README.md b/benchmark/indexing_count/README.md
new file mode 100644
index 0000000..e4c0caf
--- /dev/null
+++ b/benchmark/indexing_count/README.md
@@ -0,0 +1,82 @@
+# Benchmarking operation `count` on FM-indexes
+
+## Methodology
+
+Explored dimensions:
+
+ * text type
+ * instance size (just adjust the test_case.config file for this)
+ * compile options
+ * index implementations
+
+Pattern selection:
+
+We use the benchmark code including the random pattern selection
+and test cases from the [Pizza&Chili][pz] website.
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * `build_idx_*` generates indexes
+ * `query_idx_*` executes the count experiments
+ * `info_*` outputs the space breakdown of an index.
+ * `genpattern` pattern generation from [Pizza&Chili][pz] website.
+ * [indexes](./indexes): Contains the generated indexes.
+ * [results](./visualize): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which generates
+ a report.
+
+ Files included in this archive from the Pizza&Chili website:
+ * [src/genpatterns.c](./src/genpatterns.c)
+ * [src/run_quries_sdsl.cpp](./src/run_quries_sdsl.cpp)
+ is a customized version of the Pizza&Chili file run_queries.c .
+
+## Prerequisites
+ * For the visualization you need the following software:
+ - [R][RPJ] with packages `xtable`,`plyr`. You can install the
+ package by calling `install.packages("xtable", "plyr")` in R.
+ - [pdflatex][LT] to generate the pdf reports.
+ * The construction of the 200MB indexes requires about 1GB
+ of RAM.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads test the
+ 200MB [Pizza&Chili][pz] test cases, builds the indexes,
+ runs the performance tests, and generated a report located at
+ `visualize/count.pdf`. The raw numbers of the timings
+ can be found in `results/all.txt`.
+ Indexes and temporary files are stored in the
+ directory `indexes` and `tmp`. For the 5 x 200 MB of
+ [Pizza&Chili][pz] data the project will produce about
+ 7.2 GB of additional data. On my machine (MacBookPro Retina
+ 2.6GHz Intel Core i7, 16GB 1600 Mhz DDR3, SSD) the
+ benchmark, invoced by `make timing`, took about 11 minutes
+ (excluding the time to download the test instances).
+ Have a look at the [generated report][RES].
+ * All created indexes and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+ The project contains several configuration files:
+
+ * [index.config](./index.config): Specify data structures'
+ ID, sdsl-class, and LaTeX-name for the report.
+ * [test_case.config](./test_case.config): Specify test cases'
+ ID, path, LaTeX-name for the report, and download URL.
+ * [compile_options.config](./compile_options.config): Specify
+ compile options' ID and string.
+
+ Note that the benchmark will execute every combination of your choices.
+
+ Finally, the visualization can also be configured:
+
+ * [visualize/index-filter.config](./visualize/index-filter.config):
+ Specify which indexes should be listed in the report.
+
+[sdsl]: https://github.com/simongog/sdsl "sdsl"
+[pz]: http://pizzachili.di.unipi.it "Pizza&Chili"
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/count.pdf "count.pdf"
diff --git a/benchmark/indexing_count/bin/.gitignore b/benchmark/indexing_count/bin/.gitignore
new file mode 100644
index 0000000..b30744f
--- /dev/null
+++ b/benchmark/indexing_count/bin/.gitignore
@@ -0,0 +1,5 @@
+*
+!HP
+!NOSSE
+!NOOPT
+!.gitignore
diff --git a/benchmark/indexing_count/compile_options.config b/benchmark/indexing_count/compile_options.config
new file mode 100644
index 0000000..f3fdb25
--- /dev/null
+++ b/benchmark/indexing_count/compile_options.config
@@ -0,0 +1,10 @@
+# Compile configurations
+# Column description (columns are separated by semicolon):
+# (1) Identifier for compile configuration (consisting of letters)
+# (2) Compile options
+NOOPT;-std=c++11 -DPOPCOUNT_TL -O3 -g -funroll-loops -fomit-frame-pointer -ffast-math
+NOSSE;-std=c++11 -O3 -g -funroll-loops -fomit-frame-pointer -ffast-math
+SSE;-std=c++11 -msse4.2 -O3 -g -funroll-loops -fomit-frame-pointer -ffast-math
+HP;-std=c++11 -DUSE_HP -msse4.2 -O3 -g -funroll-loops -fomit-frame-pointer -ffast-math
+O1;-std=c++11 -O1
+O0;-std=c++11 -O0
diff --git a/benchmark/indexing_count/index.config b/benchmark/indexing_count/index.config
new file mode 100644
index 0000000..9b2decc
--- /dev/null
+++ b/benchmark/indexing_count/index.config
@@ -0,0 +1,14 @@
+# This file specified sdsl index structures that are used in the benchmark.
+#
+# Each index is specified by a triple: INDEX_ID;SDSL_TYPE;INDEX_LATEX_NAME
+# * INDEX_ID : An identifier for the index. Only letters and underscores
+# are allowed in INDEX_ID.
+# * SDSL_TYPE : Corresponding sdsl type.
+# * LATEX_NAME: LaTeX name for output in the benchmark report.
+FM_HUFF;csa_wt<wt_huff<bit_vector,rank_support_v5<>,select_support_scan<>,select_support_scan<0> >,1<<20,1<<20>;FM-HF-BV
+FM_HUFF_RRR15;csa_wt<wt_huff<rrr_vector<15> >,1<<20,1<<20>;FM-HF-R$^{3}$-15
+FM_HUFF_RRR63;csa_wt<wt_huff<rrr_vector<63> >,1<<20,1<<20>;FM-HF-R$^{3}$-63
+#FM_HUFF_RRR127;csa_wt<wt_huff<rrr_vector<127> >,1<<20,1<<20>;FM-HF-R$^{3}$-127
+#FM_HUFF_RRR255;csa_wt<wt_huff<rrr_vector<255> >,1<<20,1<<20>;FM-HF-R$^{3}$-255
+#CSA_SADA;csa_sada<enc_vector<coder::elias_delta,128>,1<<20,1<<20>;CSA
+FM_RLMN;csa_wt<wt_rlmn<>,1<<20,1<<20>;FM-RLMN
diff --git a/benchmark/indexing_count/indexes/.gitignore b/benchmark/indexing_count/indexes/.gitignore
new file mode 100644
index 0000000..b30744f
--- /dev/null
+++ b/benchmark/indexing_count/indexes/.gitignore
@@ -0,0 +1,5 @@
+*
+!HP
+!NOSSE
+!NOOPT
+!.gitignore
diff --git a/benchmark/indexing_count/info/.gitignore b/benchmark/indexing_count/info/.gitignore
new file mode 100644
index 0000000..b30744f
--- /dev/null
+++ b/benchmark/indexing_count/info/.gitignore
@@ -0,0 +1,5 @@
+*
+!HP
+!NOSSE
+!NOOPT
+!.gitignore
diff --git a/benchmark/indexing_count/pattern/.gitignore b/benchmark/indexing_count/pattern/.gitignore
new file mode 100644
index 0000000..b30744f
--- /dev/null
+++ b/benchmark/indexing_count/pattern/.gitignore
@@ -0,0 +1,5 @@
+*
+!HP
+!NOSSE
+!NOOPT
+!.gitignore
diff --git a/benchmark/indexing_count/results/.gitignore b/benchmark/indexing_count/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_count/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_count/src/build_index_sdsl.cpp b/benchmark/indexing_count/src/build_index_sdsl.cpp
new file mode 100644
index 0000000..9ea3e7a
--- /dev/null
+++ b/benchmark/indexing_count/src/build_index_sdsl.cpp
@@ -0,0 +1,23 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if (argc < 4) {
+ cout << "Usage ./" << argv[0] << " input_file tmp_dir output_file" << endl;
+ return 0;
+ }
+ CSA_TYPE csa;
+ if (argc < 3) {
+ construct(csa, argv[1], 1);
+ } else {
+ // config: do not delete files, tmp_dir=argv[2], id=basename(argv[1])
+ cache_config cconfig(false, argv[2], util::basename(argv[1]));
+ construct(csa, argv[1], cconfig, 1);
+ }
+ store_to_file(csa, argv[3]);
+}
diff --git a/benchmark/indexing_count/src/genpatterns.c b/benchmark/indexing_count/src/genpatterns.c
new file mode 100644
index 0000000..d937391
--- /dev/null
+++ b/benchmark/indexing_count/src/genpatterns.c
@@ -0,0 +1,214 @@
+
+// Extracts random patterns from a file
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int Seed;
+#define ACMa 16807
+#define ACMm 2147483647
+#define ACMq 127773
+#define ACMr 2836
+#define hi (Seed / ACMq)
+#define lo (Seed % ACMq)
+
+static int fst = 1;
+
+/*
+ * returns a random integer in 0..top-1
+ */
+
+int
+aleat(top)
+{
+ long test;
+ struct timeval t;
+ if (fst) {
+ gettimeofday(&t, NULL);
+ Seed = t.tv_sec * t.tv_usec;
+ fst = 0;
+ }
+ {
+ Seed = ((test =
+ ACMa * lo - ACMr * hi) > 0) ? test : test + ACMm;
+ return ((double) Seed) * top / ACMm;
+ }
+}
+
+void parse_forbid(unsigned char* forbid, unsigned char** forbide)
+{
+
+ int len, i, j;
+ len = strlen(forbid);
+
+ *forbide = (unsigned char*) malloc((len+1)*sizeof(unsigned char));
+ if (*forbide == NULL) {
+ fprintf(stderr, "Error: cannot allocate %i bytes\n", len+1);
+ fprintf(stderr, "errno = %i\n", errno);
+ exit(1);
+ }
+
+ for (i = 0, j = 0; i < len; i++) {
+ if (forbid[i] != '\\') {
+ if (forbid[i] != '\n')
+ (*forbide)[j++] = forbid[i];
+ } else {
+ i++;
+ if (i == len) {
+ forbid[i-1] = '\0';
+ (*forbide)[j] = '\0';
+ fprintf(stderr, "Not correct forbidden string: only one \\\n");
+ return;
+ }
+ switch (forbid[i]) {
+ case'n': (*forbide)[j++] = '\n'; break;
+ case'\\': (*forbide)[j++] = '\\'; break;
+ case'b': (*forbide)[j++] = '\b'; break;
+ case'e': (*forbide)[j++] = '\e'; break;
+ case'f': (*forbide)[j++] = '\f'; break;
+ case'r': (*forbide)[j++] = '\r'; break;
+ case't': (*forbide)[j++] = '\t'; break;
+ case'v': (*forbide)[j++] = '\v'; break;
+ case'a': (*forbide)[j++] = '\a'; break;
+ case'c':
+ if (i+3 >= len) {
+ forbid[i-1] = '\0';
+ (*forbide)[j] = '\0';
+ fprintf(stderr, "Not correct forbidden string: 3 digits after \\c\n");
+ return;
+ }
+ (*forbide)[j++] = (forbid[i+1]-48)*100 +
+ (forbid[i+2]-48)*10 + (forbid[i+3]-48);
+ i+=3;
+ break;
+ default:
+ fprintf(stdout, "Unknown escape sequence '\\%c'in forbidden string\n", forbid[i]);
+ break;
+ }
+ }
+ }
+ (*forbide)[j] = '\0';
+}
+
+main(int argc, char** argv)
+{
+ int n, m, J, t;
+ struct stat sdata;
+ FILE* ifile, *ofile;
+ unsigned char* buff;
+ unsigned char* forbid, *forbide = NULL;
+
+ if (argc < 5) {
+ fprintf(stderr,
+ "Usage: genpatterns <file> <length> <number> <patterns file> <forbidden>\n"
+ " randomly extracts <number> substrings of length <length> from <file>,\n"
+ " avoiding substrings containing characters in <forbidden>.\n"
+ " The output file, <patterns file> has a first line of the form:\n"
+ " # number=<number> length=<length> file=<file> forbidden=<forbidden>\n"
+ " and then the <number> patterns come successively without any separator.\n"
+ " <forbidden> uses \\n, \\t, etc. for nonprintable chracters or \\cC\n"
+ " where C is the ASCII code of the character written using 3 digits.\n\n");
+ exit(1);
+ }
+
+ if (stat(argv[1], &sdata) != 0) {
+ fprintf(stderr, "Error: cannot stat file %s\n", argv[1]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+ n = sdata.st_size;
+
+ m = atoi(argv[2]);
+ if ((m <= 0) || (m > n)) {
+ fprintf(stderr,
+ "Error: length must be >= 1 and <= file length"
+ " (%i)\n", n);
+ exit(1);
+ }
+
+ J = atoi(argv[3]);
+ if (J < 1) {
+ fprintf(stderr, "Error: number of patterns must be >= 1\n");
+ exit(1);
+ }
+
+ if (argc > 5) {
+ forbid = argv[5];
+ parse_forbid(forbid, &forbide);
+ } else
+ forbid = NULL;
+
+ ifile = fopen(argv[1], "r");
+ if (ifile == NULL) {
+ fprintf(stderr, "Error: cannot open file %s for reading\n", argv[1]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+
+ buff = (unsigned char*) malloc(n);
+ if (buff == NULL) {
+ fprintf(stderr, "Error: cannot allocate %i bytes\n", n);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+
+ if (fread(buff, n, 1, ifile) != 1) {
+ fprintf(stderr, "Error: cannot read file %s\n", argv[1]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+ fclose(ifile);
+
+ ofile = fopen(argv[4], "w");
+ if (ofile == NULL) {
+ fprintf(stderr, "Error: cannot open file %s for writing\n",
+ argv[4]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+
+ if (fprintf(ofile, "# number=%i length=%i file=%s forbidden=%s\n",
+ J, m, argv[1],
+ forbid == NULL ? "" : (char*) forbid) <= 0) {
+ fprintf(stderr, "Error: cannot write file %s\n", argv[4]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+
+ for (t = 0; t < J; t++) {
+ int j, l;
+ if (!forbide)
+ j = aleat(n - m + 1);
+ else {
+ do {
+ j = aleat(n - m + 1);
+ for (l = 0; l < m; l++)
+ if (strchr(forbide, buff[j + l]))
+ break;
+ } while (l < m);
+ }
+ for (l = 0; l < m; l++)
+ if (putc(buff[j + l], ofile) != buff[j + l]) {
+ fprintf(stderr,
+ "Error: cannot write file %s\n",
+ argv[4]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+ }
+
+ if (fclose(ofile) != 0) {
+ fprintf(stderr, "Error: cannot write file %s\n", argv[4]);
+ fprintf(stderr, " errno = %i\n", errno);
+ exit(1);
+ }
+
+ fprintf(stderr, "File %s successfully generated\n", argv[4]);
+ free(forbide);
+ exit(0);
+}
diff --git a/benchmark/indexing_count/src/info.cpp b/benchmark/indexing_count/src/info.cpp
new file mode 100644
index 0000000..c820808
--- /dev/null
+++ b/benchmark/indexing_count/src/info.cpp
@@ -0,0 +1,21 @@
+/*
+ * This program outputs the structure of an index.
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+#include <cstdlib>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "./" << argv[0] << " index_file " << endl;
+ return 1;
+ }
+ CSA_TYPE csa;
+ load_from_file(csa, argv[1]);
+ write_structure<HTML_FORMAT>(csa, cout);
+}
diff --git a/benchmark/indexing_count/src/interface.h b/benchmark/indexing_count/src/interface.h
new file mode 100644
index 0000000..16d5513
--- /dev/null
+++ b/benchmark/indexing_count/src/interface.h
@@ -0,0 +1,96 @@
+
+/* General interface for using the compressed index libraries */
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef uint
+#define uint unsigned int
+#endif
+#ifndef ulong
+#define ulong unsigned long
+#endif
+
+/* Error management */
+
+/* Returns a string describing the error associated with error number
+ e. The string must not be freed, and it will be overwritten with
+ subsequent calls. */
+
+char* error_index(int e);
+
+/* Building the index */
+
+/* Creates index from text[0..length-1]. Note that the index is an
+ opaque data type. Any build option must be passed in string
+ build_options, whose syntax depends on the index. The index must
+ always work with some default parameters if build_options is NULL.
+ The returned index is ready to be queried. */
+
+int build_index(uchar* text, ulong length, char* build_options, void** index);
+
+/* Saves index on disk by using single or multiple files, having
+ proper extensions. */
+
+int save_index(void* index, char* filename);
+
+/* Loads index from one or more file(s) named filename, possibly
+ adding the proper extensions. */
+
+int load_index(char* filename, void** index);
+
+/* Frees the memory occupied by index. */
+
+int free_index(void* index);
+
+/* Gives the memory occupied by index in bytes. */
+
+int index_size(void* index, ulong* size);
+
+/* Querying the index */
+
+/* Writes in numocc the number of occurrences of the substring
+ pattern[0..length-1] found in the text indexed by index. */
+
+int count(void* index, uchar* pattern, ulong length, ulong* numocc);
+
+/* Writes in numocc the number of occurrences of the substring
+ pattern[0..length-1] in the text indexed by index. It also allocates
+ occ (which must be freed by the caller) and writes the locations of
+ the numocc occurrences in occ, in arbitrary order. */
+
+int locate(void* index, uchar* pattern, ulong length, ulong** occ,
+ ulong* numocc);
+
+/* Gives the length of the text indexed */
+
+int get_length(void* index, ulong* length);
+
+/* Accessing the indexed text */
+
+/* Allocates snippet (which must be freed by the caller) and writes
+ the substring text[from..to] into it. Returns in snippet_length the
+ length of the text snippet actually extracted (that could be less
+ than to-from+1 if to is larger than the text size). */
+
+int extract(void* index, ulong from, ulong to, uchar** snippet,
+ ulong* snippet_length);
+
+/* Displays the text (snippet) surrounding any occurrence of the
+ substring pattern[0..length-1] within the text indexed by index.
+ The snippet must include numc characters before and after the
+ pattern occurrence, totalizing length+2*numc characters, or less if
+ the text boundaries are reached. Writes in numocc the number of
+ occurrences, and allocates the arrays snippet_text and
+ snippet_lengths (which must be freed by the caller). The first is a
+ character array of numocc*(length+2*numc) characters, with a new
+ snippet starting at every multiple of length+2*numc. The second
+ gives the real length of each of the numocc snippets. */
+
+int display(void* index, uchar* pattern, ulong length, ulong numc,
+ ulong* numocc, uchar** snippet_text, ulong** snippet_lengths);
+
+/* Obtains the length of the text indexed by index. */
+
+int length(void* index, ulong* length);
+
diff --git a/benchmark/indexing_count/src/run_queries_sdsl.cpp b/benchmark/indexing_count/src/run_queries_sdsl.cpp
new file mode 100644
index 0000000..eebf355
--- /dev/null
+++ b/benchmark/indexing_count/src/run_queries_sdsl.cpp
@@ -0,0 +1,285 @@
+/*
+ * Run Queries
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+#include <stdlib.h>
+#include "interface.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* only for getTime() */
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#define COUNT ('C')
+#define LOCATE ('L')
+#define EXTRACT ('E')
+#define DISPLAY ('D')
+#define VERBOSE ('V')
+
+using namespace sdsl;
+using namespace std;
+
+/* local headers */
+void do_count(const CSA_TYPE&);
+void do_locate(const CSA_TYPE&);
+void pfile_info(ulong* length, ulong* numpatt);
+double getTime(void);
+void usage(char* progname);
+
+static int Verbose = 0;
+static ulong Index_size, Text_length;
+static double Load_time;
+
+/*
+ * Temporary usage: run_queries <index file> <type> [length] [V]
+ */
+int main(int argc, char* argv[])
+{
+ char* filename;
+ char querytype;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ filename = argv[1];
+ querytype = *argv[2];
+ string index_file = string(argv[1]) + "." + string(SUF);
+ bool mapped = false;
+#ifdef USE_HP
+ uint64_t index_size = util::file_size(index_file);
+ // allocate hugepages, add 10 MiB + 3% overhead
+ uint64_t alloc_size = (uint64_t)(index_size*1.03+(1ULL<<20)*10);
+ try {
+ memory_manager::use_hugepages(alloc_size);
+ mapped = true;
+ } catch (...) {
+ std::cout<<"Unable to allocate "<<alloc_size<<" bytes ";
+ std::cout<<"of hugepage space on your system"<<std::endl;
+ }
+#endif
+
+ CSA_TYPE csa;
+ fprintf(stderr, "# File = %s\n",(string(filename) + "." + string(SUF)).c_str());
+ fprintf(stderr, "# program = %s\n",string(SUF).c_str());
+ Load_time = getTime();
+ load_from_file(csa, index_file);
+ Load_time = getTime() - Load_time;
+ fprintf(stderr, "# Load_index_time_in_sec = %.2f\n", Load_time);
+ std::cerr<<"# text_size = " << csa.size()-1 << std::endl;
+
+ Index_size = size_in_bytes(csa);
+ Text_length = csa.size()-1; // -1 since we added a sentinel character
+ /* Index_size /=1024; */
+ fprintf(stderr, "# Index_size_in_bytes = %lu\n", Index_size);
+
+ fprintf(stderr, "# hugepages = %i\n", (int)mapped);
+ bool use_sse = false;
+#ifdef __SSE4_2__
+ use_sse = true;
+#endif
+ fprintf(stderr, "# sse = %i\n", (int)use_sse);
+ bool use_popcount_tl = false;
+#ifdef POPCOUNT_TL
+ use_popcount_tl = true;
+#endif
+ fprintf(stderr, "# popcount_tl = %i\n", (int)use_popcount_tl);
+
+ switch (querytype) {
+ case COUNT:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", COUNT);
+ }
+ do_count(csa);
+ break;
+ case LOCATE:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", LOCATE);
+ }
+ do_locate(csa);
+ break;
+ default:
+ fprintf(stderr, "Unknow option: main ru\n");
+ exit(1);
+ }
+ return 0;
+}
+
+
+void
+do_count(const CSA_TYPE& csa)
+{
+ ulong numocc, length, tot_numocc = 0, numpatt, res_patt;
+ double time, tot_time = 0;
+ uchar* pattern;
+
+ pfile_info(&length, &numpatt);
+ res_patt = numpatt;
+
+ pattern = (uchar*) malloc(sizeof(uchar) * (length));
+ if (pattern == NULL) {
+ fprintf(stderr, "Error: cannot allocate\n");
+ exit(1);
+ }
+
+ while (res_patt) {
+
+ if (fread(pattern, sizeof(*pattern), length, stdin) != length) {
+ fprintf(stderr, "Error: cannot read patterns file\n");
+ exit(1);
+ }
+
+ /* Count */
+ time = getTime();
+ numocc = sdsl::count(csa, pattern, pattern+length);
+
+ if (Verbose) {
+ fwrite(&length, sizeof(length), 1, stdout);
+ fwrite(pattern, sizeof(*pattern), length, stdout);
+ fwrite(&numocc, sizeof(numocc), 1, stdout);
+ }
+ tot_time += (getTime() - time);
+ tot_numocc += numocc;
+ res_patt--;
+ }
+
+ fprintf(stderr, "# Total_Num_occs_found = %lu\n", tot_numocc);
+ fprintf(stderr, "# Count_time_in_milli_sec = %.4f\n", tot_time*1000);
+ fprintf(stderr, "# Count_time/Pattern_chars = %.4f\n",
+ (tot_time * 1000) / (length * numpatt));
+ fprintf(stderr, "# Count_time/Num_patterns = %.4f\n\n",
+ (tot_time * 1000) / numpatt);
+ fprintf(stderr, "# (Load_time+Count_time)/Pattern_chars = %.4f\n",
+ ((Load_time+tot_time) * 1000) / (length * numpatt));
+ fprintf(stderr, "# (Load_time+Count_time)/Num_patterns = %.4f\n\n",
+ ((Load_time+tot_time) * 1000) / numpatt);
+
+ free(pattern);
+}
+
+
+void
+do_locate(const CSA_TYPE& csa)
+{
+ ulong numocc, length;
+ ulong tot_numocc = 0, numpatt;
+ double time, tot_time = 0;
+ uchar* pattern;
+
+ pfile_info(&length, &numpatt);
+
+ pattern = (uchar*) malloc(sizeof(uchar) * (length));
+ if (pattern == NULL) {
+ fprintf(stderr, "Error: cannot allocate\n");
+ exit(1);
+ }
+
+ while (numpatt) {
+
+ if (fread(pattern, sizeof(*pattern), length, stdin) != length) {
+ fprintf(stderr, "Error: cannot read patterns file\n");
+ perror("run_queries");
+ exit(1);
+ }
+ // Locate
+ time = getTime();
+ auto occ = sdsl::locate(csa, (char*)pattern, (char*)pattern+length);
+ numocc = occ.size();
+ tot_time += (getTime() - time);
+
+ tot_numocc += numocc;
+ numpatt--;
+
+ if (Verbose) {
+ fwrite(&length, sizeof(length), 1, stdout);
+ fwrite(pattern, sizeof(*pattern), length, stdout);
+ fwrite(&numocc, sizeof(numocc), 1, stdout);
+ }
+ }
+
+ fprintf(stderr, "# Total_Num_occs_found = %lu\n", tot_numocc);
+ fprintf(stderr, "# Locate_time_in_secs = %.2f\n", tot_time);
+ fprintf(stderr, "# Locate_time/Num_occs = %.4f\n\n", (tot_time * 1000) / tot_numocc);
+ fprintf(stderr, "# (Load_time+Locate_time)/Num_occs = %.4f\n\n", ((tot_time+Load_time) * 1000) / tot_numocc);
+
+ free(pattern);
+}
+
+/* Open patterns file and read header */
+void
+pfile_info(ulong* length, ulong* numpatt)
+{
+ int error;
+ uchar c;
+ uchar origfilename[257];
+
+ error = fscanf(stdin, "# number=%lu length=%lu file=%s forbidden=", numpatt,
+ length, origfilename);
+ if (error != 3) {
+ fprintf(stderr, "Error: Patterns file header not correct\n");
+ perror("run_queries");
+ exit(1);
+ }
+
+ fprintf(stderr, "# pat_cnt = %lu\n", *numpatt);
+ fprintf(stderr, "# pat_length = %lu\n", *length);
+ fprintf(stderr, "# forbidden_chars = ");
+
+ while ((c = fgetc(stdin)) != 0) {
+ if (c == '\n') break;
+ fprintf(stderr, "%d",c);
+ }
+
+ fprintf(stderr, "\n");
+
+}
+
+double
+getTime(void)
+{
+
+ double usertime, systime;
+ struct rusage usage;
+
+ getrusage(RUSAGE_SELF, &usage);
+
+ usertime = (double) usage.ru_utime.tv_sec +
+ (double) usage.ru_utime.tv_usec / 1000000.0;
+
+ systime = (double) usage.ru_stime.tv_sec +
+ (double) usage.ru_stime.tv_usec / 1000000.0;
+
+ return (usertime + systime);
+
+}
+
+void usage(char* progname)
+{
+ fprintf(stderr, "\nThe program loads <index> and then executes over it the\n");
+ fprintf(stderr, "queries it receives from the standard input. The standard\n");
+ fprintf(stderr, "input comes in the format of the files written by \n");
+ fprintf(stderr, "genpatterns or genintervals.\n");
+ fprintf(stderr, "%s reports on the standard error time statistics\n", progname);
+ fprintf(stderr, "regarding to running the queries.\n\n");
+ fprintf(stderr, "Usage: %s <index> <type> [length] [V]\n", progname);
+ fprintf(stderr, "\n\t<type> denotes the type of queries:\n");
+ fprintf(stderr, "\t %c counting queries;\n", COUNT);
+ fprintf(stderr, "\t %c locating queries;\n", LOCATE);
+ fprintf(stderr, "\t %c displaying queries;\n", DISPLAY);
+ fprintf(stderr, "\t %c extracting queries.\n\n", EXTRACT);
+ fprintf(stderr, "\n\t[length] must be provided in case of displaying queries (D)\n");
+ fprintf(stderr, "\t and denotes the number of characters to display\n");
+ fprintf(stderr, "\t before and after each pattern occurrence.\n");
+ fprintf(stderr, "\n\t[V] with this options it reports on the standard output\n");
+ fprintf(stderr, "\t the results of the queries. The results file should be\n");
+ fprintf(stderr, "\t compared with trusted one by compare program.\n\n");
+}
diff --git a/benchmark/indexing_count/test_case.config b/benchmark/indexing_count/test_case.config
new file mode 100644
index 0000000..996f503
--- /dev/null
+++ b/benchmark/indexing_count/test_case.config
@@ -0,0 +1,16 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENGLISH;../data/english.200MB;english.200MB;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz
+DBLPXML;../data/dblp.xml.200MB;dblp.xml.200MB;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz
+DNA;../data/dna.200MB;dna.200MB;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz
+PROTEINS;../data/proteins.200MB;proteins.200MB;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz
+SOURCES;../data/sources.200MB;sources.200MB;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz
+#INFLUENZA;../data/influenza;influenza;http://pizzachili.dcc.uchile.cl/repcorpus/real/influenza.gz
+#EINSTEIN-de;../data/einstein.de.txt;einstein-de;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.de.txt.gz
+#EINSTEIN-en;../data/einstein.en.txt;einstein-en;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.en.txt.gz
+#PARA;../data/para;para;http://pizzachili.dcc.uchile.cl/repcorpus/real/para.gz
+#WORLDLEADER;../data/world_leaders;world-leaders;http://pizzachili.dcc.uchile.cl/repcorpus/real/world_leaders.gz
+#E-COLI;../data/Escherichia_Coli;E.coli;http://pizzachili.dcc.uchile.cl/repcorpus/real/Escherichia_Coli.gz
diff --git a/benchmark/indexing_count/visualize/.gitignore b/benchmark/indexing_count/visualize/.gitignore
new file mode 100644
index 0000000..acb751e
--- /dev/null
+++ b/benchmark/indexing_count/visualize/.gitignore
@@ -0,0 +1,7 @@
+*
+!.gitignore
+!Makefile
+!count-footer.tex
+!count-header.tex
+!count.R
+!index-filter.config
diff --git a/benchmark/indexing_count/visualize/Makefile b/benchmark/indexing_count/visualize/Makefile
new file mode 100644
index 0000000..66c0b6a
--- /dev/null
+++ b/benchmark/indexing_count/visualize/Makefile
@@ -0,0 +1,19 @@
+include ../../../Make.helper
+COMPILE_IDS:=$(call config_ids,../compile_options.config)
+TABLES = $(foreach COMPILE_ID,$(COMPILE_IDS),tbl-count-$(COMPILE_ID).tex)
+
+CONFIG_FILES=index-filter.config ../index.config ../test_case.config
+
+all: count.pdf
+
+count.pdf: count.tex
+ @echo "Use pdflatex to generate count.pdf"
+ @pdflatex count.tex >> LaTeX.Log 2>&1
+
+count.tex: ../results/all.txt ../../basic_functions.R count.R $(CONFIG_FILES)
+ @echo "Use R to generate count.tex"
+ @R --vanilla < count.R > R.log 2>&1
+
+clean:
+ rm -f $(TABLES) count.pdf count.aux count.tex \
+ count.log R.log LaTeX.log
diff --git a/benchmark/indexing_count/visualize/count-footer.tex b/benchmark/indexing_count/visualize/count-footer.tex
new file mode 100644
index 0000000..6b47932
--- /dev/null
+++ b/benchmark/indexing_count/visualize/count-footer.tex
@@ -0,0 +1 @@
+\end{document}
diff --git a/benchmark/indexing_count/visualize/count-header.tex b/benchmark/indexing_count/visualize/count-header.tex
new file mode 100644
index 0000000..2ed616a
--- /dev/null
+++ b/benchmark/indexing_count/visualize/count-header.tex
@@ -0,0 +1,6 @@
+\documentclass[9pt,a4paper]{scrartcl}
+\usepackage{booktabs}
+\usepackage{array}
+\usepackage{ragged2e}
+
+\begin{document}
diff --git a/benchmark/indexing_count/visualize/count.R b/benchmark/indexing_count/visualize/count.R
new file mode 100644
index 0000000..14ae39c
--- /dev/null
+++ b/benchmark/indexing_count/visualize/count.R
@@ -0,0 +1,130 @@
+library(xtable) # if not installed call install.packages("xtable")
+library(plyr)
+
+source("../../basic_functions.R")
+
+# Load index information
+idx_config <- readConfig("../index.config",c("IDX_ID","SDSL_TYPE","LATEX-NAME"))
+tc_config <- readConfig("../test_case.config",c("TC_ID","PATH","LATEX-NAME","URL"))
+compile_config <- readConfig("../compile_options.config",c("COMPILE_ID","OPTIONS"))
+
+# Create data frame which maps test cases names to their index in the list
+tc_ord <- data.frame("ord"=seq(1,nrow(tc_config)),"LATEX-NAME")
+rownames(tc_ord) <- tc_config[["TC_ID"]]
+
+# Load report information
+
+config <- readConfig("index-filter.config",c("IDX_ID"))
+
+# Load data
+raw <- data_frame_from_key_value_pairs( "../results/all.txt" )
+#
+# Filer indexes
+raw <- raw[raw[["IDX_ID"]]%in%config[["IDX_ID"]],]
+raw[["IDX_ID"]] <- factor(raw[["IDX_ID"]])
+# Normalize data
+raw[["Time"]] <- raw[["Count_time_in_milli_sec"]]*1000
+raw[["Time"]] <- raw[["Time"]]/(raw[["pat_cnt"]]*raw[["pat_length"]])
+raw[["Time"]] <- round(raw[["Time"]], 3)
+raw[["Space"]] <- raw[["Index_size_in_bytes"]]/raw[["text_size"]]
+raw[["Space"]] <- round(raw[["Space"]],2)
+
+raw <- raw[c("TC_ID", "Space", "Time","COMPILE_ID","IDX_ID")]
+raw <- raw[order(raw[["TC_ID"]]),]
+
+data <- split(raw, raw[["COMPILE_ID"]])
+
+
+
+form_table <- function(d, order=NA){
+# calculate the mean time per IDX_ID,TC_ID
+ d <- aggregate(d[c('Time','Space')],
+ by=list(IDX_ID=d[['IDX_ID']],
+ TC_ID=d[['TC_ID']]),
+ FUN=mean,na.rm=TRUE)
+ d <- d[ order(tc_ord[as.character(d[["TC_ID"]]),"ord"]), ]
+ dd <- split(d, d[["IDX_ID"]])
+ table <- data.frame(dd[[1]]["TC_ID"], stringsAsFactors=F)
+ names(table) <- c("TC_ID")
+ table[["TC_ID"]] <- paste("\\textsc{", tc_config[as.character(table[['TC_ID']]), "LATEX-NAME"],"}")
+ names(table) <- c(" ")
+ prog_name <- names(dd)
+ if( !is.na(order) ){
+ prog_name <- order
+ }
+ for( prog in prog_name ){
+ sel <- dd[[prog]]
+ table <- cbind(table, " "=rep("", length(sel["Time"])))
+ table <- cbind(table, round(sel["Time"],3))
+ table <- cbind(table, sel["Space"]*100)
+ }
+ unitrow <- paste(c("", rep(c("&","&($\\mu s$)","&(\\%)"),length(prog_name)), "\\\\[1ex]"),collapse="",sep='')
+ list("table" = table, "names" = table[["TC_ID"]], "unitrow"=unitrow)
+}
+
+
+make_latex_header <- function(names){
+ x <- paste("&&\\multicolumn{2}{c}{", names,"}")
+ x <- paste(x, collapse=" ")
+ clines=""
+ for(i in 1:length(names)){
+ clines <- paste(clines,"\\cmidrule{",3*i,"-",3*i+1,"}",sep="")
+ }
+ y <- paste("\\toprule",x, "\\\\",clines,"\n")
+ gsub("_","\\\\_",y)
+}
+
+print_latex <- function( table, names, unitrow ){
+ ali <- c("l","r", rep(c("@{\\hspace{1ex}}l","c","c"), (ncol(table)-1)/3) )
+ dig <- c(0, 0, rep(c(0,3,0),(ncol(table)-1)/3 ))
+ print( xtable( table, align=ali, digits=dig ),
+ type="latex", hline.after=c(), # TODO replace by bottomrule
+ floating = F, # don't use table environment
+ add.to.row=list(pos=list(-1,0,nrow(table)),
+ command=c(make_latex_header(names),unitrow,"\\bottomrule")),
+ sanitize.rownames.function = identity,
+ sanitize.text.function = identity,
+ include.rownames = FALSE
+ )
+}
+
+generate_table <- function(file, data){
+ sink(file)
+ if ( nrow(data) > 0 ){
+ x <- form_table(data, config[["IDX_ID"]])
+ print_latex(x[["table"]], idx_config[as.character(config[["IDX_ID"]]), "LATEX-NAME"], x[["unitrow"]])
+ }else{
+ cat("\\begin{center}No data for this experiment\\end{center}")
+ }
+ sink(NULL)
+}
+
+for ( compile_id in names(data) ){
+ generate_table(paste("tbl-count-",compile_id,".tex",sep=''), data[[compile_id]])
+}
+
+sink("count.tex")
+cat(paste(readLines("count-header.tex"),"\n",sep=""))
+for ( compile_id in names(data) ){
+ cat("
+ \\begin{table}
+ \\centering
+ \\input{tbl-count-",compile_id,".tex}
+ \\caption{Time in $\\mu$sec per pattern symbol in a count query.
+ Index space as fraction of original file size.
+ Compile options:
+ \\texttt{",gsub("_","\\\\_",compile_config[compile_id, "OPTIONS"]),"}.
+ \\label{tbl-count-",compile_id,"}}
+ \\end{table}",sep="")
+}
+
+# output table containing type information
+cat("\\begin{table}
+ \\centering",
+typeInfoTable("../index.config", config[["IDX_ID"]], 1, 3, 2)
+ ,"\\caption{Index identifier and corresponding sdsl-type.}
+ \\end{table}
+ ")
+
+cat(paste(readLines("count-footer.tex"),"\n",sep=""))
+sink(NULL)
diff --git a/benchmark/indexing_count/visualize/index-filter.config b/benchmark/indexing_count/visualize/index-filter.config
new file mode 100644
index 0000000..c167c6a
--- /dev/null
+++ b/benchmark/indexing_count/visualize/index-filter.config
@@ -0,0 +1,10 @@
+# Use this file to specify which indexes are listed in the report count.pdf.
+#
+# List all the index ids which should be included in the report. Note that
+# the listed index ids must also be present in the file `../index.config`.
+# Each IDX_ID is listed on a separate line. The listing order is used
+# in the report.
+FM_HUFF
+FM_HUFF_RRR15
+FM_RLMN
+FM_HUFF_RRR63
diff --git a/benchmark/indexing_extract/Makefile b/benchmark/indexing_extract/Makefile
new file mode 100644
index 0000000..a07b226
--- /dev/null
+++ b/benchmark/indexing_extract/Makefile
@@ -0,0 +1,159 @@
+include ../Make.helper
+CFLAGS = $(MY_CXX_FLAGS) $(MY_CXX_OPT_FLAGS)
+LIBS = -lsdsl -ldivsufsort -ldivsufsort64
+SRC_DIR = src
+TMP_DIR = ../tmp
+IVL_DIR = intervals
+BIN_DIR = bin
+
+TC_PATHS:=$(call config_column,test_case.config,2)
+TC_IDS:=$(call config_ids,test_case.config)
+IDX_IDS:=$(call config_ids,index.config)
+SAMPLE_IDS:=$(call config_ids,sample.config)
+
+RESULT_FILE=results/all.txt
+
+QUERY_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),$(BIN_DIR)/query_idx_$(IDX_ID).$(SAMPLE_ID)))
+BUILD_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),$(BIN_DIR)/build_idx_$(IDX_ID).$(SAMPLE_ID)))
+INFO_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),$(BIN_DIR)/info_$(IDX_ID).$(SAMPLE_ID)))
+INTERVALS = $(foreach TC_ID,$(TC_IDS),$(IVL_DIR)/$(TC_ID).interval)
+INDEXES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),indexes/$(TC_ID).$(IDX_ID).$(SAMPLE_ID))))
+INFO_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),info/$(TC_ID).$(IDX_ID).$(SAMPLE_ID).json)))
+TIME_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),results/$(TC_ID).$(IDX_ID).$(SAMPLE_ID))))
+COMP_FILES = $(addsuffix .z.info,$(TC_PATHS))
+
+all: $(BUILD_EXECS) $(QUERY_EXECS) $(INFO_EXECS)
+
+info: $(INFO_EXECS) $(INFO_FILES)
+
+indexes: $(INDEXES)
+
+intervals: input $(INTERVALS) $(BIN_DIR)/genintervals
+
+input: $(TC_PATHS)
+
+compression: input $(COMP_FILES)
+
+timing: input $(INDEXES) intervals $(TIME_FILES) compression info
+ @cat $(TIME_FILES) > $(RESULT_FILE)
+ @cd visualize; make
+
+# results/[TC_ID].[IDX_ID].[SAMPLE_ID]
+results/%: $(BUILD_EXECS) $(QUERY_EXECS) $(PATTERNS) $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval SAMPLE_ID:=$(call dim,3,$*))
+ $(eval TC_NAME:=$(call config_select,test_case.config,$(TC_ID),3))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ @echo "# TC_ID = $(TC_ID)" >> $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# test_case = $(TC_NAME)" >> $@
+ @echo "# SAMPLE_ID = $(SAMPLE_ID)" >> $@
+ @echo "# S_SA = $(S_SA)" >> $@
+ @echo "# S_ISA = $(S_ISA)" >> $@
+ @echo "Run timing for $(IDX_ID).$(SAMPLE_ID) on $(TC_ID)"
+ @$(BIN_DIR)/query_idx_$(IDX_ID).$(SAMPLE_ID) \
+ indexes/$(TC_ID) E < $(IVL_DIR)/$(TC_ID).interval 2>> $@
+
+
+# indexes/[TC_ID].[IDX_ID].[SAMPLE_ID]
+indexes/%: $(BUILD_EXECS)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval SAMPLE_ID:=$(call dim,3,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ @echo "Building index $(IDX_ID).$(SAMPLE_ID) on $(TC)"
+ @$(BIN_DIR)/build_idx_$(IDX_ID).$(SAMPLE_ID) $(TC) $(TMP_DIR) $@
+
+# info/[TC_ID].[IDX_ID].[SAMPLE_ID]
+info/%.json: $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval SAMPLE_ID:=$(call dim,3,$*))
+ @echo "Generating info for $(IDX_ID) on $(TC_ID)"
+ $(BIN_DIR)/info_$(IDX_ID).$(SAMPLE_ID) indexes/$(TC_ID).$(IDX_ID).$(SAMPLE_ID) > $@
+
+# $(IVL_DIR)/[TC_ID].interval
+$(IVL_DIR)/%.interval: $(BIN_DIR)/genintervals
+ @echo "Generating intervals for $*"
+ $(eval TC:=$(call config_select,test_case.config,$*,2))
+ @$(BIN_DIR)/genintervals $(TC) 512 10000 $@ 2> /dev/null
+
+$(BIN_DIR)/genintervals: $(SRC_DIR)/genintervals.c
+ @echo "Build interval generation program"
+ @$(MY_CC) -O3 -o $@ $(SRC_DIR)/genintervals.c
+
+
+# $(BIN_DIR)/build_idx_[IDX_ID].[SAMPLE_ID]
+$(BIN_DIR)/build_idx_%: $(SRC_DIR)/build_index_sdsl.cpp index.config sample.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval SAMPLE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ $(eval IDX_TYPE:=$(subst S_SA,$(S_SA),$(IDX_TYPE)))
+ $(eval IDX_TYPE:=$(subst S_ISA,$(S_ISA),$(IDX_TYPE)))
+ @echo "Compiling build_idx_$*"
+ @$(MY_CXX) $(CFLAGS) -DSUF=\"$*\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -DS_SA=$(S_SA) -DS_ISA=$(S_ISA) \
+ -L$(LIB_DIR) $(SRC_DIR)/build_index_sdsl.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the count experiment. $(BIN_DIR)/count_queries_[IDX_ID].[SAMPLE_ID]
+$(BIN_DIR)/query_idx_%: $(SRC_DIR)/run_queries_sdsl.cpp index.config sample.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval SAMPLE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ $(eval IDX_TYPE:=$(subst S_SA,$(S_SA),$(IDX_TYPE)))
+ $(eval IDX_TYPE:=$(subst S_ISA,$(S_ISA),$(IDX_TYPE)))
+ @echo "Compiling query_idx_$*"
+ @$(MY_CXX) $(CFLAGS) -DSUF="$(IDX_ID).$(SAMPLE_ID)" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/run_queries_sdsl.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the info executable. $(BIN_DIR)/info_[IDX_ID].[SAMPLE_ID]
+$(BIN_DIR)/info_%: $(SRC_DIR)/info.cpp index.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval SAMPLE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ $(eval IDX_TYPE:=$(subst S_SA,$(S_SA),$(IDX_TYPE)))
+ $(eval IDX_TYPE:=$(subst S_ISA,$(S_ISA),$(IDX_TYPE)))
+ @echo "Compiling info_$*"
+ @$(MY_CXX) $(CFLAGS) -DSUF=\"$*\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/info.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ @rm -f $(QUERY_EXECS) $(BUILD_EXECS) $(INFO_EXECS)
+
+clean:
+ @echo "Remove executables"
+ @rm -f $(QUERY_EXECS) $(BUILD_EXECS) $(INFO_EXECS) \
+ $(BIN_DIR)/genintervals
+
+cleanresults:
+ @echo "Remove result files"
+ @rm -f $(TIME_FILES) $(RESULT_FILE)
+
+cleanall: clean cleanresults
+ @echo "Remove all generated files."
+ @rm -f $(INDEXES) $(INFO_FILES) $(PATTERNS)
+ @rm -f $(TMP_DIR)/*
+ @rm -f $(INTERVALS)
diff --git a/benchmark/indexing_extract/README.md b/benchmark/indexing_extract/README.md
new file mode 100644
index 0000000..3e1e437
--- /dev/null
+++ b/benchmark/indexing_extract/README.md
@@ -0,0 +1,99 @@
+# Benchmarking operation `extract` on FM-indexes
+
+## Methodology
+
+Explored dimensions:
+
+ * text type
+ * instance size (just adjust the test_case.config file for this)
+ * suffix array sampling density
+ * index implementations
+
+Interval selection:
+
+We use the methodology of [Ferragina et al.][FGNV08] (Section 5.4),
+i.e. 10,000 substrings of length 512 starting at random texts positions
+are extracted.
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * `build_idx_*` generates indexes
+ * `query_idx_*` executes the extract experiments
+ * `info_*` outputs the space breakdown of an index.
+ * `genintervals` intervals generator
+ * [indexes](./indexes): Contains the generated indexes.
+ * [intervals](./intervals): Contains the generated intervals.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which
+ generates a report in LaTeX format.
+
+ Files included in this archive from the [Pizza&Chili][pz] website:
+ * [src/run_quries_sdsl.cpp](src/run_queries_sdsl.cpp) is a adapted version of the
+ Pizza&Chili file run_queries.c .
+ * [src/genintervals.c](src/genintervals.c) is their interval generation
+ program.
+
+## Prerequisites
+ * For the visualization you need the following software:
+ - [R][RPJ] with package `tikzDevice`. You can install the
+ package by calling
+ `install.packages("filehash", repos="http://cran.r-project.org")`
+ and
+ `install.packages("tikzDevice", repos="http://R-Forge.R-project.org")`
+ in `R`.
+ - Compressors [xz][XZ] and [gzip][GZIP] are used to get
+ compression baselines.
+ - [pdflatex][LT] to generate the pdf reports.
+ * The construction of the 200MB indexes requires about 1GB
+ of RAM.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads the 200MB
+ [Pizza&Chili][pz] test cases, builds the indexes,
+ runs the performance tests, and generated a report located at
+ `visualize/extract.pdf`. The raw numbers of the timings
+ can be found in the `results/all.txt`.
+ Indexes and temporary files are stored in the
+ directory `indexes` and `tmp`. For the 5 x 200 MB of
+ [Pizza&Chili][pz] data the project will produce about
+ 36 GB of additional data. On my machine (MacBookPro Retina
+ 2.6GHz Intel Core i7, 16GB 1600 Mhz DDR3, SSD) the
+ benchmark, triggerd by `make timing`, took about 2 hours
+ (excluding the time to download the test instances).
+ Have a look at the [generated report][RES].
+ * All created indexes and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+ The project contains several configuration files:
+
+ * [index.config][IDXCONFIG]: Specify data structures'
+ ID, sdsl-class and LaTeX-name for the report.
+ * [test_case.config][TCCONF]: Specify test cases's
+ ID, path, LaTeX-name for the report, and download URL.
+ * [sample.config][SCONF]: Specify samplings' ID,
+ rate for SA, and rate for ISA.
+
+ Note that the benchmark will execute every combination of your
+ choices.
+
+ Finally, the visualization can also be configured:
+
+ * [visualize/index-filter.config][VCONF]: Specify which
+ indexes should be listed in the report and which style should be used.
+
+[sdsl]: https://github.com/simongog/sdsl "sdsl"
+[pz]: http://pizzachili.di.unipi.it "Pizza&Chili"
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/extract.pdf "extract.pdf"
+[FGNV08]: http://dl.acm.org/citation.cfm?doid=1412228.1455268 "FGNV08"
+[IDXCONFIG]: ./index.config "index.config"
+[TCCONF]: ./test_case.config "test_case.config"
+[SCONF]: ./sample.config "sample.config"
+[VCONF]: ./visualize/index-filter.config "index-filter.config"
+[XZ]: http://tukaani.org/xz/ "XZ Compressor"
+[GZIP]: http://www.gnu.org/software/gzip/ "Gzip Compressor"
diff --git a/benchmark/indexing_extract/bin/.gitignore b/benchmark/indexing_extract/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_extract/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_extract/index.config b/benchmark/indexing_extract/index.config
new file mode 100644
index 0000000..056bd95
--- /dev/null
+++ b/benchmark/indexing_extract/index.config
@@ -0,0 +1,12 @@
+# Specify the extract indexes here. Use S_SA and S_ISA as generic sample parameters.
+# S_SA and S_ISA will be replaced by the values in sample.config
+#
+# Each index is specified by a triple: INDEX_ID;SDSL_TYPE;INDEX_LATE_NAME
+# * INDEX_ID : An identifier for the index. Only letters and underscores
+# are allowed in the name.
+# * SDSL_TYPE : Corresponding sdsl type.
+# * LATEX_NAME: LaTeX name for output in the benchmark report.
+FM_HUFF;csa_wt<wt_huff<bit_vector,rank_support_v5<>,select_support_scan<>,select_support_scan<> >,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;FM-HF-V5
+FM_HUFF_RRR15;csa_wt<wt_huff<rrr_vector<15> >,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;FM-HF-R$^3$15
+CSA_SADA;csa_sada<enc_vector<coder::elias_delta,128>,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;CSA-SADA
+FM_HUFF_RRR63;csa_wt<wt_huff<rrr_vector<63> >,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;FM-HF-R$^3$63
diff --git a/benchmark/indexing_extract/indexes/.gitignore b/benchmark/indexing_extract/indexes/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_extract/indexes/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_extract/info/.gitignore b/benchmark/indexing_extract/info/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_extract/info/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_extract/intervals/.gitignore b/benchmark/indexing_extract/intervals/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_extract/intervals/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_extract/results/.gitignore b/benchmark/indexing_extract/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_extract/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_extract/sample.config b/benchmark/indexing_extract/sample.config
new file mode 100644
index 0000000..f8a39af
--- /dev/null
+++ b/benchmark/indexing_extract/sample.config
@@ -0,0 +1,12 @@
+# Specify the sample rate for suffix array (SA) and inverse suffix array (ISA).
+# You can use the constants SA_MAX and ISA_MAX for the maximal sparse sampling
+# for SA and ISA.
+# Each sampling pair is specified by a triple: SAMPLING_ID;SA_SAMPLE_RATE;ISA_SAMPLE_RATE
+# SAMPLING_ID should consist only of symbols in A-Z,a-z,0-9
+4x4;4;4
+8x8;8;8
+16x16;16;16
+32x32;32;32
+64x64;64;64
+128x128;128;128
+256x256;256;256
diff --git a/benchmark/indexing_extract/src/build_index_sdsl.cpp b/benchmark/indexing_extract/src/build_index_sdsl.cpp
new file mode 100644
index 0000000..9ea3e7a
--- /dev/null
+++ b/benchmark/indexing_extract/src/build_index_sdsl.cpp
@@ -0,0 +1,23 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if (argc < 4) {
+ cout << "Usage ./" << argv[0] << " input_file tmp_dir output_file" << endl;
+ return 0;
+ }
+ CSA_TYPE csa;
+ if (argc < 3) {
+ construct(csa, argv[1], 1);
+ } else {
+ // config: do not delete files, tmp_dir=argv[2], id=basename(argv[1])
+ cache_config cconfig(false, argv[2], util::basename(argv[1]));
+ construct(csa, argv[1], cconfig, 1);
+ }
+ store_to_file(csa, argv[3]);
+}
diff --git a/benchmark/indexing_extract/src/genintervals.c b/benchmark/indexing_extract/src/genintervals.c
new file mode 100644
index 0000000..c625aff
--- /dev/null
+++ b/benchmark/indexing_extract/src/genintervals.c
@@ -0,0 +1,133 @@
+
+// Chooses random intervals from a file
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int Seed;
+#define ACMa 16807
+#define ACMm 2147483647
+#define ACMq 127773
+#define ACMr 2836
+#define hi (Seed / ACMq)
+#define lo (Seed % ACMq)
+
+static int fst=1;
+
+/* returns a random integer in 0..top-1 */
+
+int aleat(top)
+
+{
+ long test;
+ struct timeval t;
+ if (fst) {
+ gettimeofday(&t,NULL);
+ Seed = t.tv_sec*t.tv_usec;
+ fst=0;
+ }
+ {
+ Seed = ((test = ACMa * lo - ACMr * hi) > 0) ? test : test + ACMm;
+ return ((double)Seed) * top/ACMm;
+ }
+}
+
+main(int argc, char** argv)
+
+{
+ int n,m,J,t;
+ struct stat sdata;
+ FILE* ifile,*ofile;
+ unsigned char* buff;
+
+ if (argc < 5) {
+ fprintf(stderr,
+ "Usage: %s <file> <length> <number> <intervals file>\n"
+ " randomly extracts <number> intervals of length <length> from <file>.\n"
+ " The output file, <intervals file> has a first line of the form:\n"
+ " # number=<number> length=<length> file=<file>\n"
+ " and then <number> lines of the form <from>,<to>.\n",argv[0]
+ );
+ exit(1);
+ }
+
+ if (stat(argv[1],&sdata) != 0) {
+ fprintf(stderr,"Error: cannot stat file %s\n",argv[1]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+ n = sdata.st_size;
+
+ m = atoi(argv[2]);
+ if ((m <= 0) || (m > n)) {
+ fprintf(stderr,"Error: length must be >= 1 and <= file length"
+ " (%i)\n",n);
+ exit(1);
+ }
+
+ J = atoi(argv[3]);
+ if (J < 1) {
+ fprintf(stderr,"Error: number of intervals must be >= 1\n");
+ exit(1);
+ }
+
+ ifile = fopen(argv[1],"r");
+ if (ifile == NULL) {
+ fprintf(stderr,"Error: cannot open file %s for reading\n",argv[1]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+
+ buff = (unsigned char*) malloc(n);
+ if (buff == NULL) {
+ fprintf(stderr,"Error: cannot allocate %i bytes\n",n);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+
+ if (fread(buff,n,1,ifile) != 1) {
+ fprintf(stderr,"Error: cannot read file %s\n",argv[1]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+ fclose(ifile);
+
+ ofile = fopen(argv[4],"w");
+ if (ofile == NULL) {
+ fprintf(stderr,"Error: cannot open file %s for writing\n",argv[4]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+
+ if (fprintf(ofile,"# number=%i length=%i file=%s\n", J,m,argv[1]) <= 0) {
+ fprintf(stderr,"Error: cannot write file %s\n",argv[4]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+
+ for (t=0; t<J; t++) {
+ int j,l;
+ j = aleat(n-m+1);
+ if (fprintf(ofile,"%i,%i\n",j,j+m-1) <= 0) {
+ fprintf(stderr,"Error: cannot write file %s\n",argv[4]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+ }
+
+ if (fclose(ofile) != 0) {
+ fprintf(stderr,"Error: cannot write file %s\n",argv[4]);
+ fprintf(stderr," errno = %i\n",errno);
+ exit(1);
+ }
+
+ fprintf(stderr,"File %s successfully generated\n",argv[4]);
+ exit(0);// SG: Replaced 1 by 0.
+}
+
+
diff --git a/benchmark/indexing_extract/src/info.cpp b/benchmark/indexing_extract/src/info.cpp
new file mode 100644
index 0000000..f956f1c
--- /dev/null
+++ b/benchmark/indexing_extract/src/info.cpp
@@ -0,0 +1,19 @@
+/*
+ * This program outputs the structure of an index.
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "./" << argv[0] << " index_file " << endl;
+ return 1;
+ }
+ CSA_TYPE csa;
+ load_from_file(csa, argv[1]);
+ write_structure<JSON_FORMAT>(csa, cout);
+}
diff --git a/benchmark/indexing_extract/src/interface.h b/benchmark/indexing_extract/src/interface.h
new file mode 100644
index 0000000..16d5513
--- /dev/null
+++ b/benchmark/indexing_extract/src/interface.h
@@ -0,0 +1,96 @@
+
+/* General interface for using the compressed index libraries */
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef uint
+#define uint unsigned int
+#endif
+#ifndef ulong
+#define ulong unsigned long
+#endif
+
+/* Error management */
+
+/* Returns a string describing the error associated with error number
+ e. The string must not be freed, and it will be overwritten with
+ subsequent calls. */
+
+char* error_index(int e);
+
+/* Building the index */
+
+/* Creates index from text[0..length-1]. Note that the index is an
+ opaque data type. Any build option must be passed in string
+ build_options, whose syntax depends on the index. The index must
+ always work with some default parameters if build_options is NULL.
+ The returned index is ready to be queried. */
+
+int build_index(uchar* text, ulong length, char* build_options, void** index);
+
+/* Saves index on disk by using single or multiple files, having
+ proper extensions. */
+
+int save_index(void* index, char* filename);
+
+/* Loads index from one or more file(s) named filename, possibly
+ adding the proper extensions. */
+
+int load_index(char* filename, void** index);
+
+/* Frees the memory occupied by index. */
+
+int free_index(void* index);
+
+/* Gives the memory occupied by index in bytes. */
+
+int index_size(void* index, ulong* size);
+
+/* Querying the index */
+
+/* Writes in numocc the number of occurrences of the substring
+ pattern[0..length-1] found in the text indexed by index. */
+
+int count(void* index, uchar* pattern, ulong length, ulong* numocc);
+
+/* Writes in numocc the number of occurrences of the substring
+ pattern[0..length-1] in the text indexed by index. It also allocates
+ occ (which must be freed by the caller) and writes the locations of
+ the numocc occurrences in occ, in arbitrary order. */
+
+int locate(void* index, uchar* pattern, ulong length, ulong** occ,
+ ulong* numocc);
+
+/* Gives the length of the text indexed */
+
+int get_length(void* index, ulong* length);
+
+/* Accessing the indexed text */
+
+/* Allocates snippet (which must be freed by the caller) and writes
+ the substring text[from..to] into it. Returns in snippet_length the
+ length of the text snippet actually extracted (that could be less
+ than to-from+1 if to is larger than the text size). */
+
+int extract(void* index, ulong from, ulong to, uchar** snippet,
+ ulong* snippet_length);
+
+/* Displays the text (snippet) surrounding any occurrence of the
+ substring pattern[0..length-1] within the text indexed by index.
+ The snippet must include numc characters before and after the
+ pattern occurrence, totalizing length+2*numc characters, or less if
+ the text boundaries are reached. Writes in numocc the number of
+ occurrences, and allocates the arrays snippet_text and
+ snippet_lengths (which must be freed by the caller). The first is a
+ character array of numocc*(length+2*numc) characters, with a new
+ snippet starting at every multiple of length+2*numc. The second
+ gives the real length of each of the numocc snippets. */
+
+int display(void* index, uchar* pattern, ulong length, ulong numc,
+ ulong* numocc, uchar** snippet_text, ulong** snippet_lengths);
+
+/* Obtains the length of the text indexed by index. */
+
+int length(void* index, ulong* length);
+
diff --git a/benchmark/indexing_extract/src/run_queries_sdsl.cpp b/benchmark/indexing_extract/src/run_queries_sdsl.cpp
new file mode 100644
index 0000000..fbc11b1
--- /dev/null
+++ b/benchmark/indexing_extract/src/run_queries_sdsl.cpp
@@ -0,0 +1,330 @@
+/*
+ * Run Queries
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+#include <stdlib.h>
+#include "interface.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* only for getTime() */
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#define COUNT ('C')
+#define LOCATE ('L')
+#define EXTRACT ('E')
+#define DISPLAY ('D')
+#define VERBOSE ('V')
+
+using namespace sdsl;
+using namespace std;
+
+/* local headers */
+void do_count(const CSA_TYPE&);
+void do_locate(const CSA_TYPE&);
+void do_extract(const CSA_TYPE&);
+//void do_display(ulong length);
+void pfile_info(ulong* length, ulong* numpatt);
+//void output_char(uchar c, FILE * where);
+double getTime(void);
+void usage(char* progname);
+
+static int Verbose = 0;
+static ulong Index_size, Text_length;
+static double Load_time;
+
+/*
+ * Temporary usage: run_queries <index file> <type> [length] [V]
+ */
+int main(int argc, char* argv[])
+{
+ char* filename;
+ char querytype;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ filename = argv[1];
+ querytype = *argv[2];
+
+ CSA_TYPE csa;
+ fprintf(stderr, "Load from file %s\n",(string(filename) + "." + string(SDSL_XSTR(SUF))).c_str());
+ Load_time = getTime();
+ load_from_file(csa, (string(argv[1]) + "." + string(SDSL_XSTR(SUF))).c_str());
+ Load_time = getTime() - Load_time;
+ fprintf(stderr, "# Load_index_time_in_sec = %.2f\n", Load_time);
+ std::cerr << "# text_size = " << csa.size()-1 << std::endl;
+
+ Index_size = size_in_bytes(csa);
+ Text_length = csa.size()-1; // -1 since we added a sentinel character
+ fprintf(stderr, "# Index_size_in_bytes = %lu\n", Index_size);
+#ifdef USE_HP
+ bool mapped = mm::map_hp();
+ fprintf(stderr, "# hugepages = %i\n", (int)mapped);
+#endif
+
+ switch (querytype) {
+ case COUNT:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", COUNT);
+ }
+ do_count(csa);
+ break;
+ case LOCATE:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", LOCATE);
+ }
+ do_locate(csa);
+ break;
+ case EXTRACT:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", EXTRACT);
+ }
+
+ do_extract(csa);
+ break;
+ default:
+ fprintf(stderr, "Unknow option: main ru\n");
+ exit(1);
+ }
+#ifdef USE_HP
+ if (mapped) {
+ mm::unmap_hp();
+ }
+#endif
+ return 0;
+}
+
+
+void
+do_count(const CSA_TYPE& csa)
+{
+ ulong numocc, length, tot_numocc = 0, numpatt, res_patt;
+ double time, tot_time = 0;
+ uchar* pattern;
+
+ pfile_info(&length, &numpatt);
+ res_patt = numpatt;
+
+ pattern = (uchar*) malloc(sizeof(uchar) * (length));
+ if (pattern == NULL) {
+ fprintf(stderr, "Error: cannot allocate\n");
+ exit(1);
+ }
+
+ while (res_patt) {
+
+ if (fread(pattern, sizeof(*pattern), length, stdin) != length) {
+ fprintf(stderr, "Error: cannot read patterns file\n");
+ perror("run_queries");
+ exit(1);
+ }
+
+ /* Count */
+ time = getTime();
+ numocc = count(csa, pattern, pattern+length);
+
+ if (Verbose) {
+ fwrite(&length, sizeof(length), 1, stdout);
+ fwrite(pattern, sizeof(*pattern), length, stdout);
+ fwrite(&numocc, sizeof(numocc), 1, stdout);
+ }
+ tot_time += (getTime() - time);
+ tot_numocc += numocc;
+ res_patt--;
+ }
+
+ fprintf(stderr, "# Total_Num_occs_found = %lu\n", tot_numocc);
+ fprintf(stderr, "# Count_time_in_milli_sec = %.4f\n", tot_time*1000);
+ fprintf(stderr, "# Count_time/Pattern_chars = %.4f\n",
+ (tot_time * 1000) / (length * numpatt));
+ fprintf(stderr, "# Count_time/Num_patterns = %.4f\n\n",
+ (tot_time * 1000) / numpatt);
+ fprintf(stderr, "# (Load_time+Count_time)/Pattern_chars = %.4f\n",
+ ((Load_time+tot_time) * 1000) / (length * numpatt));
+ fprintf(stderr, "# (Load_time+Count_time)/Num_patterns = %.4f\n\n",
+ ((Load_time+tot_time) * 1000) / numpatt);
+
+ free(pattern);
+}
+
+
+void
+do_locate(const CSA_TYPE& csa)
+{
+ ulong numocc, length;
+ ulong tot_numocc = 0, numpatt = 0, processed_pat = 0;
+ double time, tot_time = 0;
+ uchar* pattern;
+
+ pfile_info(&length, &numpatt);
+
+ pattern = (uchar*) malloc(sizeof(uchar) * (length));
+ if (pattern == NULL) {
+ fprintf(stderr, "Error: cannot allocate\n");
+ exit(1);
+ }
+ /*SG: added timeout of 60 seconds */
+ while (numpatt and tot_time < 60.0) {
+
+ if (fread(pattern, sizeof(*pattern), length, stdin) != length) {
+ fprintf(stderr, "Error: cannot read patterns file\n");
+ perror("run_queries");
+ exit(1);
+ }
+ // Locate
+ time = getTime();
+ auto occ = locate(csa, (char*)pattern, (char*)pattern+length);
+ numocc = occ.size();
+ tot_time += (getTime() - time);
+ ++processed_pat;
+
+ tot_numocc += numocc;
+ numpatt--;
+
+ if (Verbose) {
+ fwrite(&length, sizeof(length), 1, stdout);
+ fwrite(pattern, sizeof(*pattern), length, stdout);
+ fwrite(&numocc, sizeof(numocc), 1, stdout);
+ }
+ }
+
+ fprintf(stderr, "# processed_pattern = %lu\n", processed_pat);
+ fprintf(stderr, "# Total_Num_occs_found = %lu\n", tot_numocc);
+ fprintf(stderr, "# Locate_time_in_secs = %.2f\n", tot_time);
+ fprintf(stderr, "# Locate_time/Num_occs = %.4f\n\n", (tot_time * 1000) / tot_numocc);
+ fprintf(stderr, "# (Load_time+Locate_time)/Num_occs = %.4f\n\n", ((tot_time+Load_time) * 1000) / tot_numocc);
+
+ free(pattern);
+}
+
+/* Open patterns file and read header */
+void
+pfile_info(ulong* length, ulong* numpatt)
+{
+ int error;
+ uchar c;
+ uchar origfilename[257];
+
+ error = fscanf(stdin, "# number=%lu length=%lu file=%s forbidden=", numpatt,
+ length, origfilename);
+ if (error != 3) {
+ fprintf(stderr, "Error: Patterns file header not correct\n");
+ perror("run_queries");
+ exit(1);
+ }
+
+ fprintf(stderr, "# pat_cnt = %lu\n", *numpatt);
+ fprintf(stderr, "# pat_length = %lu\n", *length);
+ fprintf(stderr, "# forbidden_chars = ");
+
+ while ((c = fgetc(stdin)) != 0) {
+ if (c == '\n') break;
+ fprintf(stderr, "%d",c);
+ }
+
+ fprintf(stderr, "\n");
+
+}
+
+void
+do_extract(const CSA_TYPE& csa)
+{
+ int error = 0;
+ uchar* text, orig_file[257];
+ ulong num_pos, from, to, numchars, tot_ext = 0;
+ CSA_TYPE::size_type readlen = 0;
+ double time, tot_time = 0;
+
+ error = fscanf(stdin, "# number=%lu length=%lu file=%s\n", &num_pos, &numchars, orig_file);
+ if (error != 3) {
+ fprintf(stderr, "Error: Intervals file header is not correct\n");
+ perror("run_queries");
+ exit(1);
+ }
+ fprintf(stderr, "# number=%lu length=%lu file=%s\n", num_pos, numchars, orig_file);
+
+ while (num_pos) {
+
+ if (fscanf(stdin,"%lu,%lu\n", &from, &to) != 2) {
+ fprintf(stderr, "Cannot read correctly intervals file\n");
+ exit(1);
+ }
+
+ time = getTime();
+ text = (uchar*)malloc(to-from+2);
+ readlen = sdsl::extract(csa, from, to, text);
+ tot_time += (getTime() - time);
+
+ tot_ext += readlen;
+
+ if (Verbose) {
+ fwrite(&from,sizeof(ulong),1,stdout);
+ fwrite(&readlen,sizeof(ulong),1,stdout);
+ fwrite(text,sizeof(uchar),readlen, stdout);
+ }
+
+ num_pos--;
+ free(text);
+ }
+
+ fprintf(stderr, "# Total_num_chars_extracted = %lu\n", tot_ext);
+ fprintf(stderr, "# Extract_time_in_sec = %.2f\n", tot_time);
+ fprintf(stderr, "# Extract_time/Num_chars_extracted = %.4f\n\n",
+ (tot_time * 1000) / tot_ext);
+ fprintf(stderr, "(Load_time+Extract_time)/Num_chars_extracted = %.4f\n\n",
+ ((Load_time+tot_time) * 1000) / tot_ext);
+}
+
+double
+getTime(void)
+{
+
+ double usertime, systime;
+ struct rusage usage;
+
+ getrusage(RUSAGE_SELF, &usage);
+
+ usertime = (double) usage.ru_utime.tv_sec +
+ (double) usage.ru_utime.tv_usec / 1000000.0;
+
+ systime = (double) usage.ru_stime.tv_sec +
+ (double) usage.ru_stime.tv_usec / 1000000.0;
+
+ return (usertime + systime);
+
+}
+
+void usage(char* progname)
+{
+ fprintf(stderr, "\nThe program loads <index> and then executes over it the\n");
+ fprintf(stderr, "queries it receives from the standard input. The standard\n");
+ fprintf(stderr, "input comes in the format of the files written by \n");
+ fprintf(stderr, "genpatterns or genintervals.\n");
+ fprintf(stderr, "%s reports on the standard error time statistics\n", progname);
+ fprintf(stderr, "regarding to running the queries.\n\n");
+ fprintf(stderr, "Usage: %s <index> <type> [length] [V]\n", progname);
+ fprintf(stderr, "\n\t<type> denotes the type of queries:\n");
+ fprintf(stderr, "\t %c counting queries;\n", COUNT);
+ fprintf(stderr, "\t %c locating queries;\n", LOCATE);
+ fprintf(stderr, "\t %c displaying queries;\n", DISPLAY);
+ fprintf(stderr, "\t %c extracting queries.\n\n", EXTRACT);
+ fprintf(stderr, "\n\t[length] must be provided in case of displaying queries (D)\n");
+ fprintf(stderr, "\t and denotes the number of characters to display\n");
+ fprintf(stderr, "\t before and after each pattern occurrence.\n");
+ fprintf(stderr, "\n\t[V] with this options it reports on the standard output\n");
+ fprintf(stderr, "\t the results of the queries. The results file should be\n");
+ fprintf(stderr, "\t compared with trusted one by compare program.\n\n");
+}
diff --git a/benchmark/indexing_extract/test_case.config b/benchmark/indexing_extract/test_case.config
new file mode 100644
index 0000000..43d7394
--- /dev/null
+++ b/benchmark/indexing_extract/test_case.config
@@ -0,0 +1,10 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENGLISH;../data/english.200MB;english.200MB;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz
+DBLPXML;../data/dblp.xml.200MB;dblp.xml.200MB;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz
+DNA;../data/dna.200MB;dna.200MB;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz
+PROTEINS;../data/proteins.200MB;proteins.200MB;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz
+SOURCES;../data/sources.200MB;sources.200MB;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz
diff --git a/benchmark/indexing_extract/visualize/.gitignore b/benchmark/indexing_extract/visualize/.gitignore
new file mode 100644
index 0000000..77a2618
--- /dev/null
+++ b/benchmark/indexing_extract/visualize/.gitignore
@@ -0,0 +1,6 @@
+*
+!.gitignore
+!Makefile
+!extract.R
+!extract.tex
+!index-filter.config
diff --git a/benchmark/indexing_extract/visualize/Makefile b/benchmark/indexing_extract/visualize/Makefile
new file mode 100644
index 0000000..ba29ac6
--- /dev/null
+++ b/benchmark/indexing_extract/visualize/Makefile
@@ -0,0 +1,16 @@
+include ../../../Make.helper
+CONFIG_FILES=index-filter.config ../index.config ../test_case.config ../sample.config
+
+all: extract.pdf
+
+extract.pdf: extract.tex tbl-extract.tex fig-extract.tex
+ @echo "Use pdflatex to generate extract.pdf"
+ @pdflatex extract.tex >> LaTeX.Log 2>&1
+
+tbl-extract.tex fig-extract.tex: ../../basic_functions.R extract.R $(CONFIG_FILES) ../results/all.txt
+ @echo "Use R to generate fig-extract.tex and tbl-extract.tex"
+ @R --vanilla < extract.R > R.log 2>&1
+
+clean:
+ rm -f extract.pdf extract.aux extract.log R.log LaTeX.log \
+ tbl-extract.tex fig-extract.tex
diff --git a/benchmark/indexing_extract/visualize/extract.R b/benchmark/indexing_extract/visualize/extract.R
new file mode 100644
index 0000000..2355cdf
--- /dev/null
+++ b/benchmark/indexing_extract/visualize/extract.R
@@ -0,0 +1,76 @@
+require(tikzDevice)
+source("../../basic_functions.R")
+
+# Load filter information
+config <- readConfig("index-filter.config",c("IDX_ID","PCH","LTY","COL"))
+idx_config <- readConfig("../index.config",c("IDX_ID","SDSL_TYPE","LATEX-NAME"))
+tc_config <- readConfig("../test_case.config",c("TC_ID","PATH","LATEX-NAME","URL"))
+
+# Load data
+raw <- data_frame_from_key_value_pairs( "../results/all.txt" )
+# Filter indexes
+raw <- raw[raw[["IDX_ID"]]%in%config[["IDX_ID"]],]
+raw[["IDX_ID"]] <- factor(raw[["IDX_ID"]])
+# Normalize data
+raw[["Time"]] <- 1000000*raw[["Extract_time_in_sec"]]/raw[["Total_num_chars_extracted"]]
+raw[["Space"]] <- 100*raw[["Index_size_in_bytes"]]/raw[["text_size"]]
+
+raw <- raw[c("TC_ID", "Space", "Time","IDX_ID","S_SA","S_ISA")]
+raw <- raw[order(raw[["TC_ID"]]),]
+
+data <- split(raw, raw[["TC_ID"]])
+
+tikz("fig-extract.tex", width = 5.5, height = 6, standAlone = F)
+
+multi_figure_style( length(data)/2+1, 2 )
+
+max_space <- 100*2.5 #1.3 # 2.5 #1.8
+max_time <- max(raw[["Time"]]) # in microseconds
+count <- 0
+nr <- 0
+xlabnr <- (2*(length(data)/2)-1)
+for( tc_id in names(data) ){
+ d <- data[[tc_id]]
+
+ plot(c(),c(),xlim=c(0, max_space), ylim=c(0, max_time), xlab="", axes=F, xaxt="n", yaxt="n", ylab="" )
+ box(col="gray")
+ grid(lty="solid")
+ if ( nr %% 2 == 0 ){
+ ylable <- "Time per character ($\\mu s$)"
+ axis( 2, at = axTicks(2) )
+ mtext(ylable, side=2, line=2, las=0)
+ }
+ axis( 1, at = axTicks(1), labels=(nr>=xlabnr) )
+ if ( nr >= xlabnr ){
+ xlable <- "Index size in (\\%)"
+ mtext(xlable, side=1, line=2, las=0)
+ }
+ dd <- split(d, d[["IDX_ID"]])
+ for( idx_id in names(dd) ){
+ ddd <- dd[[idx_id]]
+ lines(ddd[["Space"]], ddd[["Time"]], type="b", lwd=1, pch=config[idx_id, "PCH"],
+ lty=config[idx_id, "LTY"],
+ col=config[idx_id, "COL"]
+ )
+ }
+ draw_figure_heading( sprintf("instance = \\textsc{%s}",tc_config[tc_id,"LATEX-NAME"]) )
+ comp_info <- readConfig(paste("../",tc_config[tc_id,"PATH"],".z.info",sep=""),c("NAME","RATIO","COMMAND"))
+ abline(v=comp_info["xz","RATIO"],lty=1);
+ abline(v=comp_info["gzip","RATIO"],lty=4);
+
+ nr <- nr+1
+ if ( nr == 1 ){ # plot legend
+ plot(NA, NA, xlim=c(0,1),ylim=c(0,1),ylab="", xlab="", bty="n", type="n", yaxt="n", xaxt="n")
+ idx_ids <- as.character(unique(raw[["IDX_ID"]]))
+ legend( "top", legend=idx_config[idx_ids,"LATEX-NAME"], pch=config[idx_ids,"PCH"], col=config[idx_ids,"COL"],
+ lty=config[idx_ids,"LTY"], bty="n", y.intersp=1.5, ncol=2, title="Index", cex=1.2)
+ legend( "bottom", legend=c("\\textsc{xz}~(\\texttt{-9})","\\textsc{gzip}~(\\texttt{-9})"),
+ lty=c(1,4), bty="n", y.intersp=1.5, ncol=2, title="Compression baseline", cex=1.2)
+ nr <- nr+1
+ }
+}
+dev.off()
+
+sink("tbl-extract.tex")
+cat(typeInfoTable("../index.config", config[["IDX_ID"]], 1, 3, 2))
+sink(NULL)
diff --git a/benchmark/indexing_extract/visualize/extract.tex b/benchmark/indexing_extract/visualize/extract.tex
new file mode 100644
index 0000000..0c7fade
--- /dev/null
+++ b/benchmark/indexing_extract/visualize/extract.tex
@@ -0,0 +1,23 @@
+\documentclass[9pt,a4paper]{scrartcl}
+\usepackage{array}
+\usepackage{booktabs}
+\usepackage{ragged2e}
+\usepackage{tikz}
+
+\begin{document}
+\pagestyle{empty}
+
+\begin{figure}
+\input{fig-extract.tex}
+\caption{Time-space trade-offs for operation extract.}
+\end{figure}
+
+\begin{table}
+\centering
+\input{tbl-extract.tex}
+\caption{Class definition of the indexes used in the experiment.
+The sampling rates \texttt{S\_SA} and \texttt{S\_ISA} for
+suffix and inverse suffix values was varied.}
+\end{table}
+
+\end{document}
diff --git a/benchmark/indexing_extract/visualize/index-filter.config b/benchmark/indexing_extract/visualize/index-filter.config
new file mode 100644
index 0000000..5691f94
--- /dev/null
+++ b/benchmark/indexing_extract/visualize/index-filter.config
@@ -0,0 +1,11 @@
+# Use this file to specify which indexes are listed in the report extract.pdf
+# and how they look like in the report.
+#
+# List all the index ids which should be included in the report. Note that
+# the listed index ids must also be present in the file `../index.config`.
+# Eeach INDEX_ID should be listed on a separate line followed by the style:
+# [pch];[lty];[col] (point type, line type, and color).
+FM_HUFF; 1;solid;black
+FM_HUFF_RRR15; 2;solid;blue
+CSA_SADA; 3;solid;red
+FM_HUFF_RRR63; 4;solid;blue
diff --git a/benchmark/indexing_locate/Makefile b/benchmark/indexing_locate/Makefile
new file mode 100644
index 0000000..798f4a5
--- /dev/null
+++ b/benchmark/indexing_locate/Makefile
@@ -0,0 +1,159 @@
+include ../Make.helper
+CFLAGS = $(MY_CXX_FLAGS) $(MY_CXX_OPT_FLAGS)
+LIBS = -lsdsl -ldivsufsort -ldivsufsort64
+SRC_DIR = src
+TMP_DIR = ../tmp
+PAT_DIR = pattern
+BIN_DIR = bin
+
+TC_PATHS:=$(call config_column,test_case.config,2)
+TC_IDS:=$(call config_ids,test_case.config)
+IDX_IDS:=$(call config_ids,index.config)
+SAMPLE_IDS:=$(call config_ids,sample.config)
+
+RESULT_FILE=results/all.txt
+
+QUERY_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),$(BIN_DIR)/query_idx_$(IDX_ID).$(SAMPLE_ID)))
+BUILD_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),$(BIN_DIR)/build_idx_$(IDX_ID).$(SAMPLE_ID)))
+INFO_EXECS = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),$(BIN_DIR)/info_$(IDX_ID).$(SAMPLE_ID)))
+PATTERNS = $(foreach TC_ID,$(TC_IDS),$(PAT_DIR)/$(TC_ID).pattern)
+INDEXES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),indexes/$(TC_ID).$(IDX_ID).$(SAMPLE_ID))))
+INFO_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),info/$(TC_ID).$(IDX_ID).$(SAMPLE_ID).html)))
+TIME_FILES = $(foreach IDX_ID,$(IDX_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ $(foreach SAMPLE_ID,$(SAMPLE_IDS),results/$(TC_ID).$(IDX_ID).$(SAMPLE_ID))))
+COMP_FILES = $(addsuffix .z.info,$(TC_PATHS))
+
+all: $(BUILD_EXECS) $(QUERY_EXECS) $(INFO_EXECS)
+
+info: $(INFO_EXECS) $(INFO_FILES)
+
+indexes: $(INDEXES)
+
+input: $(TC_PATHS)
+
+pattern: input $(PATTERNS) $(BIN_DIR)/pattern_random
+
+compression: input $(COMP_FILES)
+
+timing: input $(INDEXES) pattern $(TIME_FILES) compression info
+ @cat $(TIME_FILES) > $(RESULT_FILE)
+ @cd visualize; make
+
+# results/[TC_ID].[IDX_ID].[SAMPLE_ID]
+results/%: $(BUILD_EXECS) $(QUERY_EXECS) $(PATTERNS) $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval SAMPLE_ID:=$(call dim,3,$*))
+ $(eval TC_NAME:=$(call config_select,test_case.config,$(TC_ID),3))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ @echo "# TC_ID = $(TC_ID)" >> $@
+ @echo "# IDX_ID = $(IDX_ID)" >> $@
+ @echo "# test_case = $(TC_NAME)" >> $@
+ @echo "# SAMPLE_ID = $(SAMPLE_ID)" >> $@
+ @echo "# S_SA = $(S_SA)" >> $@
+ @echo "# S_ISA = $(S_ISA)" >> $@
+ @echo "Run timing for $(IDX_ID).$(SAMPLE_ID) on $(TC_ID)"
+ @$(BIN_DIR)/query_idx_$(IDX_ID).$(SAMPLE_ID) \
+ indexes/$(TC_ID) L < $(PAT_DIR)/$(TC_ID).pattern 2>> $@
+
+
+# indexes/[TC_ID].[IDX_ID].[SAMPLE_ID]
+indexes/%: $(BUILD_EXECS)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval SAMPLE_ID:=$(call dim,3,$*))
+ $(eval TC:=$(call config_select,test_case.config,$(TC_ID),2))
+ @echo "Building index $(IDX_ID).$(SAMPLE_ID) on $(TC)"
+ @$(BIN_DIR)/build_idx_$(IDX_ID).$(SAMPLE_ID) $(TC) $(TMP_DIR) $@
+
+# info/[TC_ID].[IDX_ID].[SAMPLE_ID]
+info/%.html: $(INDEXES)
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval IDX_ID:=$(call dim,2,$*))
+ $(eval SAMPLE_ID:=$(call dim,3,$*))
+ @echo "Generating info for $(IDX_ID) on $(TC_ID)"
+ $(BIN_DIR)/info_$(IDX_ID).$(SAMPLE_ID) indexes/$(TC_ID).$(IDX_ID).$(SAMPLE_ID) > $@
+
+# $(PAT_DIR)/[TC_ID].pattern
+$(PAT_DIR)/%.pattern: $(BIN_DIR)/pattern_random
+ @echo "Generating pattern for $*"
+ $(eval TC:=$(call config_select,test_case.config,$*,2))
+ @$(BIN_DIR)/pattern_random $(TC) $(TMP_DIR) 5 2000000 $@ $@.occ
+
+$(BIN_DIR)/pattern_random: $(SRC_DIR)/pattern_random.cpp
+ @echo "Build pattern generation program"
+ @$(MY_CXX) $(CFLAGS) -L$(LIB_DIR) -I$(INC_DIR) \
+ $(SRC_DIR)/pattern_random.cpp -o $@ $(LIBS)
+
+# $(BIN_DIR)/build_idx_[IDX_ID].[SAMPLE_ID]
+$(BIN_DIR)/build_idx_%: $(SRC_DIR)/build_index_sdsl.cpp index.config sample.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval SAMPLE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ $(eval IDX_TYPE:=$(subst S_SA,$(S_SA),$(IDX_TYPE)))
+ $(eval IDX_TYPE:=$(subst S_ISA,$(S_ISA),$(IDX_TYPE)))
+ @echo "Compiling build_idx_$*"
+ @$(MY_CXX) $(CFLAGS) -DSUF=\"$*\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -DS_SA=$(S_SA) -DS_ISA=$(S_ISA) \
+ -L$(LIB_DIR) $(SRC_DIR)/build_index_sdsl.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the count experiment. $(BIN_DIR)/count_queries_[IDX_ID].[SAMPLE_ID]
+$(BIN_DIR)/query_idx_%: $(SRC_DIR)/run_queries_sdsl.cpp index.config sample.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval SAMPLE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ $(eval IDX_TYPE:=$(subst S_SA,$(S_SA),$(IDX_TYPE)))
+ $(eval IDX_TYPE:=$(subst S_ISA,$(S_ISA),$(IDX_TYPE)))
+ @echo "Compiling query_idx_$*"
+ @$(MY_CXX) $(CFLAGS) -DSUF="$(IDX_ID).$(SAMPLE_ID)" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/run_queries_sdsl.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the info executable. $(BIN_DIR)/info_[IDX_ID].[SAMPLE_ID]
+$(BIN_DIR)/info_%: $(SRC_DIR)/info.cpp index.config
+ $(eval IDX_ID:=$(call dim,1,$*))
+ $(eval SAMPLE_ID:=$(call dim,2,$*))
+ $(eval IDX_TYPE:=$(call config_select,index.config,$(IDX_ID),2))
+ $(eval S_SA:=$(call config_select,sample.config,$(SAMPLE_ID),2))
+ $(eval S_ISA:=$(call config_select,sample.config,$(SAMPLE_ID),3))
+ $(eval IDX_TYPE:=$(subst S_SA,$(S_SA),$(IDX_TYPE)))
+ $(eval IDX_TYPE:=$(subst S_ISA,$(S_ISA),$(IDX_TYPE)))
+ @echo "Compiling info_$*"
+ @$(MY_CXX) $(CFLAGS) -DSUF=\"$*\" -DCSA_TYPE="$(IDX_TYPE)" \
+ -L$(LIB_DIR) $(SRC_DIR)/info.cpp \
+ -I$(INC_DIR) -o $@ $(LIBS)
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ @rm -f $(QUERY_EXECS) $(BUILD_EXECS) $(INFO_EXECS)
+
+clean:
+ @echo "Remove executables"
+ @rm -f $(QUERY_EXECS) $(BUILD_EXECS) $(INFO_EXECS) \
+ $(BIN_DIR)/pattern_random
+
+cleanresults:
+ @echo "Remove result files"
+ @rm -f $(TIME_FILES) $(RESULT_FILE)
+
+cleanall: clean cleanresults
+ @echo "Remove all generated files."
+ @rm -f $(INDEXES) $(INFO_FILES) $(PATTERNS)
+ @rm -f $(TMP_DIR)/*
+ @rm -f $(PAT_DIR)/*
diff --git a/benchmark/indexing_locate/README.md b/benchmark/indexing_locate/README.md
new file mode 100644
index 0000000..25cf315
--- /dev/null
+++ b/benchmark/indexing_locate/README.md
@@ -0,0 +1,97 @@
+# Benchmarking operation `locate` on FM-indexes
+
+## Methodology
+
+Explored dimensions:
+
+ * text type
+ * instance size (just adjust the test_case.config file for this)
+ * suffix array sampling density
+ * index implementations
+
+Pattern selection:
+
+We use the methodology of [Ferragina et al.][FGNV08] (Section 5.3):
+,,Locate sufficient random patterns of length 5 to obtain a total of 2 to
+3 million occurrences''.
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * `build_idx_*` generates indexes
+ * `query_idx_*` executes the locate experiments
+ * `info_*` outputs the space breakdown of an index.
+ * `pattern_random` pattern generator.
+ * [indexes](./indexes): Contains the generated indexes.
+ * [pattern](./pattern): Contains the generated pattern.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which
+ generates a report in LaTeX format.
+
+ Files included in this archive from the [Pizza&Chili][pz] website:
+ * [src/run_quries_sdsl.cpp](src/run_queries_sdsl.cpp) is a adapted version of the
+ Pizza&Chili file run_queries.c .
+
+## Prerequisites
+ * For the visualization you need the following software:
+ - [R][RPJ] with package `tikzDevice`. You can install the
+ package by calling
+ `install.packages("filehash", repos="http://cran.r-project.org")`
+ and
+ `install.packages("tikzDevice", repos="http://R-Forge.R-project.org")`
+ in `R`.
+ - Compressors [xz][XZ] and [gzip][GZIP] are used to get
+ compression baselines.
+ - [pdflatex][LT] to generate the pdf reports.
+ * The construction of the 200MB indexes requires about 1GB
+ of RAM.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads the 200MB
+ [Pizza&Chili][pz] test cases, builds the indexes,
+ runs the performance tests, and generated a report located at
+ `visualize/locate.pdf`. The raw numbers of the timings
+ can be found in the `results/all.txt`.
+ Indexes and temporary files are stored in the
+ directory `indexes` and `tmp`. For the 5 x 200 MB of
+ [Pizza&Chili][pz] data the project will produce about
+ 36 GB of additional data. On my machine (MacBookPro Retina
+ 2.6GHz Intel Core i7, 16GB 1600 Mhz DDR3, SSD) the
+ benchmark, triggerd by `make timing`, took about 2 hours
+ and 20 minutes (excluding the time to download the test instances).
+ Have a look at the [generated report][RES].
+ * All created indexes and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+ The project contains several configuration files:
+
+ * [index.config][IDXCONFIG]: Specify data structures'
+ ID, sdsl-class and LaTeX-name for the report.
+ * [test_case.config][TCCONF]: Specify test cases's
+ ID, path, LaTeX-name for the report, and download URL.
+ * [sample.config][SCONF]: Specify samplings' ID,
+ rate for SA, and rate for ISA.
+
+ Note that the benchmark will execute every combination of your
+ choices.
+
+ Finally, the visualization can also be configured:
+
+ * [visualize/index-filter.config][VCONF]: Specify which
+ indexes should be listed in the report and which style should be used.
+
+[sdsl]: https://github.com/simongog/sdsl "sdsl"
+[pz]: http://pizzachili.di.unipi.it "Pizza&Chili"
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/locate.pdf "locate.pdf"
+[FGNV08]: http://dl.acm.org/citation.cfm?doid=1412228.1455268 "FGNV08"
+[IDXCONFIG]: ./index.config "index.config"
+[TCCONF]: ./test_case.config "test_case.config"
+[SCONF]: ./sample.config "sample.config"
+[VCONF]: ./visualize/index-filter.config "index-filter.config"
+[XZ]: http://tukaani.org/xz/ "XZ Compressor"
+[GZIP]: http://www.gnu.org/software/gzip/ "Gzip Compressor"
diff --git a/benchmark/indexing_locate/bin/.gitignore b/benchmark/indexing_locate/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_locate/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_locate/index.config b/benchmark/indexing_locate/index.config
new file mode 100644
index 0000000..edef756
--- /dev/null
+++ b/benchmark/indexing_locate/index.config
@@ -0,0 +1,12 @@
+# Specify the locate indexes here. Use S_SA and S_ISA as generic sample parameters.
+# S_SA and S_ISA will be replaced by the values in sample.config
+#
+# Each index is specified by a triple: INDEX_ID;SDSL_TYPE;INDEX_LATE_NAME
+# * INDEX_ID : An identifier for the index. Only letters and underscores
+# are allowed in the name.
+# * SDSL_TYPE : Corresponding sdsl type.
+# * LATEX_NAME: LaTeX name for output in the benchmark report.
+FM_HUFF;csa_wt<wt_huff<bit_vector,rank_support_v5<>,select_support_scan<>,select_support_scan<> >,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;FM-HF-V5
+FM_HUFF_RRR15;csa_wt<wt_huff<rrr_vector<15> >,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;FM-HF-R$^3$15
+CSA_SADA;csa_sada<enc_vector<coder::elias_delta,128>,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;CSA-SADA
+FM_HUFF_RRR63;csa_wt<wt_huff<rrr_vector<63> >,S_SA,S_ISA,text_order_sa_sampling<sd_vector<> > >;FM-HF-R$^3$63
diff --git a/benchmark/indexing_locate/indexes/.gitignore b/benchmark/indexing_locate/indexes/.gitignore
new file mode 100644
index 0000000..b30744f
--- /dev/null
+++ b/benchmark/indexing_locate/indexes/.gitignore
@@ -0,0 +1,5 @@
+*
+!HP
+!NOSSE
+!NOOPT
+!.gitignore
diff --git a/benchmark/indexing_locate/info/.gitignore b/benchmark/indexing_locate/info/.gitignore
new file mode 100644
index 0000000..b30744f
--- /dev/null
+++ b/benchmark/indexing_locate/info/.gitignore
@@ -0,0 +1,5 @@
+*
+!HP
+!NOSSE
+!NOOPT
+!.gitignore
diff --git a/benchmark/indexing_locate/pattern/.gitignore b/benchmark/indexing_locate/pattern/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_locate/pattern/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_locate/results/.gitignore b/benchmark/indexing_locate/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/indexing_locate/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/indexing_locate/sample.config b/benchmark/indexing_locate/sample.config
new file mode 100644
index 0000000..f8a39af
--- /dev/null
+++ b/benchmark/indexing_locate/sample.config
@@ -0,0 +1,12 @@
+# Specify the sample rate for suffix array (SA) and inverse suffix array (ISA).
+# You can use the constants SA_MAX and ISA_MAX for the maximal sparse sampling
+# for SA and ISA.
+# Each sampling pair is specified by a triple: SAMPLING_ID;SA_SAMPLE_RATE;ISA_SAMPLE_RATE
+# SAMPLING_ID should consist only of symbols in A-Z,a-z,0-9
+4x4;4;4
+8x8;8;8
+16x16;16;16
+32x32;32;32
+64x64;64;64
+128x128;128;128
+256x256;256;256
diff --git a/benchmark/indexing_locate/src/build_index_sdsl.cpp b/benchmark/indexing_locate/src/build_index_sdsl.cpp
new file mode 100644
index 0000000..9ea3e7a
--- /dev/null
+++ b/benchmark/indexing_locate/src/build_index_sdsl.cpp
@@ -0,0 +1,23 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if (argc < 4) {
+ cout << "Usage ./" << argv[0] << " input_file tmp_dir output_file" << endl;
+ return 0;
+ }
+ CSA_TYPE csa;
+ if (argc < 3) {
+ construct(csa, argv[1], 1);
+ } else {
+ // config: do not delete files, tmp_dir=argv[2], id=basename(argv[1])
+ cache_config cconfig(false, argv[2], util::basename(argv[1]));
+ construct(csa, argv[1], cconfig, 1);
+ }
+ store_to_file(csa, argv[3]);
+}
diff --git a/benchmark/indexing_locate/src/info.cpp b/benchmark/indexing_locate/src/info.cpp
new file mode 100644
index 0000000..c820808
--- /dev/null
+++ b/benchmark/indexing_locate/src/info.cpp
@@ -0,0 +1,21 @@
+/*
+ * This program outputs the structure of an index.
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+#include <cstdlib>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "./" << argv[0] << " index_file " << endl;
+ return 1;
+ }
+ CSA_TYPE csa;
+ load_from_file(csa, argv[1]);
+ write_structure<HTML_FORMAT>(csa, cout);
+}
diff --git a/benchmark/indexing_locate/src/interface.h b/benchmark/indexing_locate/src/interface.h
new file mode 100644
index 0000000..16d5513
--- /dev/null
+++ b/benchmark/indexing_locate/src/interface.h
@@ -0,0 +1,96 @@
+
+/* General interface for using the compressed index libraries */
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef uint
+#define uint unsigned int
+#endif
+#ifndef ulong
+#define ulong unsigned long
+#endif
+
+/* Error management */
+
+/* Returns a string describing the error associated with error number
+ e. The string must not be freed, and it will be overwritten with
+ subsequent calls. */
+
+char* error_index(int e);
+
+/* Building the index */
+
+/* Creates index from text[0..length-1]. Note that the index is an
+ opaque data type. Any build option must be passed in string
+ build_options, whose syntax depends on the index. The index must
+ always work with some default parameters if build_options is NULL.
+ The returned index is ready to be queried. */
+
+int build_index(uchar* text, ulong length, char* build_options, void** index);
+
+/* Saves index on disk by using single or multiple files, having
+ proper extensions. */
+
+int save_index(void* index, char* filename);
+
+/* Loads index from one or more file(s) named filename, possibly
+ adding the proper extensions. */
+
+int load_index(char* filename, void** index);
+
+/* Frees the memory occupied by index. */
+
+int free_index(void* index);
+
+/* Gives the memory occupied by index in bytes. */
+
+int index_size(void* index, ulong* size);
+
+/* Querying the index */
+
+/* Writes in numocc the number of occurrences of the substring
+ pattern[0..length-1] found in the text indexed by index. */
+
+int count(void* index, uchar* pattern, ulong length, ulong* numocc);
+
+/* Writes in numocc the number of occurrences of the substring
+ pattern[0..length-1] in the text indexed by index. It also allocates
+ occ (which must be freed by the caller) and writes the locations of
+ the numocc occurrences in occ, in arbitrary order. */
+
+int locate(void* index, uchar* pattern, ulong length, ulong** occ,
+ ulong* numocc);
+
+/* Gives the length of the text indexed */
+
+int get_length(void* index, ulong* length);
+
+/* Accessing the indexed text */
+
+/* Allocates snippet (which must be freed by the caller) and writes
+ the substring text[from..to] into it. Returns in snippet_length the
+ length of the text snippet actually extracted (that could be less
+ than to-from+1 if to is larger than the text size). */
+
+int extract(void* index, ulong from, ulong to, uchar** snippet,
+ ulong* snippet_length);
+
+/* Displays the text (snippet) surrounding any occurrence of the
+ substring pattern[0..length-1] within the text indexed by index.
+ The snippet must include numc characters before and after the
+ pattern occurrence, totalizing length+2*numc characters, or less if
+ the text boundaries are reached. Writes in numocc the number of
+ occurrences, and allocates the arrays snippet_text and
+ snippet_lengths (which must be freed by the caller). The first is a
+ character array of numocc*(length+2*numc) characters, with a new
+ snippet starting at every multiple of length+2*numc. The second
+ gives the real length of each of the numocc snippets. */
+
+int display(void* index, uchar* pattern, ulong length, ulong numc,
+ ulong* numocc, uchar** snippet_text, ulong** snippet_lengths);
+
+/* Obtains the length of the text indexed by index. */
+
+int length(void* index, ulong* length);
+
diff --git a/benchmark/indexing_locate/src/pattern_random.cpp b/benchmark/indexing_locate/src/pattern_random.cpp
new file mode 100644
index 0000000..c31c248
--- /dev/null
+++ b/benchmark/indexing_locate/src/pattern_random.cpp
@@ -0,0 +1,67 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <string>
+#include <cstdio>
+
+using namespace sdsl;
+using namespace std;
+
+uint64_t my_rand64()
+{
+ int_vector<> v(1);
+ util::set_random_bits(v);
+ return v[0];
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 7) {
+ printf("Usage ./%s input_file tmp_dir pat_len min_cum_occ pat_file occ_file\n",argv[0]);
+ printf(" (1) Build an index for the text T stored in input_file.\n");
+ printf(" Temporary files are stored in tmp_dir.\n");
+ printf(" (2) Set cum_occ=0\n");
+ printf(" (3) Select a random position in T and extracts a pattern P\n");
+ printf(" of length pat_len from this position.\n");
+ printf(" (3) Get x, the number of occurrences of P in T.\n");
+ printf(" (4) cum_occ+=x; if cum_occ>=min_cum_occ exit program.\n");
+ printf(" Otherwise go to step (3).");
+ printf(" (5) Write pattern in Pizza&Chili format into pat_file.");
+ printf(" (6) Write #occurrences in into occ_file.");
+ return 1;
+ }
+ uint64_t min_cum_occ = atoll(argv[4]);
+ uint64_t pat_len = atoll(argv[3]);
+ assert(pat_len > 0);
+ vector<string> pattern;
+ string file = util::basename(argv[1]);
+ ofstream out(argv[5]);
+ ofstream occ_out(argv[6]);
+//(1)
+ csa_wt<> csa;
+ cache_config cconfig(false, argv[2], file);
+ construct(csa, argv[1], cconfig, 1);
+ if (pat_len>=csa.size()) {
+ std::cout << "pat_len=" << pat_len << " too long." << std::endl;
+ return 1;
+ }
+// (2)
+ uint64_t cum_sum = 0;
+ uint64_t number = 0;
+ do {
+// (3)
+ uint64_t start_idx = my_rand64()%(csa.size()-pat_len);
+ auto pat = extract(csa, start_idx, start_idx+pat_len-1);
+ pattern.push_back(pat);
+// (4)
+ uint64_t x = count(csa, pat.begin(), pat.end());
+ occ_out<<x<<std::endl;
+ cum_sum += x;
+ ++number;
+ } while (cum_sum < min_cum_occ);
+// (5)
+ out<<"# number="<<number<<" length="<<pat_len<<" file="<<argv[1];
+ out<<" forbidden="<<std::endl;
+ for (size_t i=0; i<pattern.size(); ++i) {
+ out<<pattern[i];
+ }
+}
diff --git a/benchmark/indexing_locate/src/run_queries_sdsl.cpp b/benchmark/indexing_locate/src/run_queries_sdsl.cpp
new file mode 100644
index 0000000..99a2295
--- /dev/null
+++ b/benchmark/indexing_locate/src/run_queries_sdsl.cpp
@@ -0,0 +1,333 @@
+/*
+ * Run Queries
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+#include <stdlib.h>
+#include "interface.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* only for getTime() */
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#define COUNT ('C')
+#define LOCATE ('L')
+#define EXTRACT ('E')
+#define DISPLAY ('D')
+#define VERBOSE ('V')
+
+using namespace sdsl;
+using namespace std;
+
+/* local headers */
+void do_count(const CSA_TYPE&);
+void do_locate(const CSA_TYPE&);
+void do_extract(const CSA_TYPE&);
+//void do_display(ulong length);
+void pfile_info(ulong* length, ulong* numpatt);
+//void output_char(uchar c, FILE * where);
+double getTime(void);
+void usage(char* progname);
+
+static int Verbose = 0;
+static ulong Index_size, Text_length;
+static double Load_time;
+
+/*
+ * Temporary usage: run_queries <index file> <type> [length] [V]
+ */
+int main(int argc, char* argv[])
+{
+ char* filename;
+ char querytype;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ filename = argv[1];
+ querytype = *argv[2];
+
+ CSA_TYPE csa;
+ fprintf(stderr, "Load from file %s\n",(string(filename) + "." + string(SDSL_XSTR(SUF))).c_str());
+ Load_time = getTime();
+ load_from_file(csa, (string(argv[1]) + "." + string(SDSL_XSTR(SUF))).c_str());
+ Load_time = getTime() - Load_time;
+ fprintf(stderr, "# Load_index_time_in_sec = %.2f\n", Load_time);
+ std::cerr<<"# text_size = " << csa.size()-1 << std::endl;
+
+ Index_size = size_in_bytes(csa);
+ Text_length = csa.size()-1; // -1 since we added a sentinel character
+ /* Index_size /=1024; */
+ fprintf(stderr, "# Index_size_in_bytes = %lu\n", Index_size);
+#ifdef USE_HP
+ bool mapped = mm::map_hp();
+ fprintf(stderr, "# hugepages = %i\n", (int)mapped);
+#endif
+
+ switch (querytype) {
+ case COUNT:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", COUNT);
+ }
+ do_count(csa);
+ break;
+ case LOCATE:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", LOCATE);
+ }
+ do_locate(csa);
+ break;
+ case EXTRACT:
+ if (argc > 3)
+ if (*argv[3] == VERBOSE) {
+ Verbose = 1;
+ fprintf(stdout,"%c", EXTRACT);
+ }
+
+ do_extract(csa);
+ break;
+ default:
+ fprintf(stderr, "Unknow option: main ru\n");
+ exit(1);
+ }
+#ifdef USE_HP
+ if (mapped) {
+ mm::unmap_hp();
+ }
+#endif
+
+ return 0;
+}
+
+
+void
+do_count(const CSA_TYPE& csa)
+{
+ ulong numocc, length, tot_numocc = 0, numpatt, res_patt;
+ double time, tot_time = 0;
+ uchar* pattern;
+
+ pfile_info(&length, &numpatt);
+ res_patt = numpatt;
+
+ pattern = (uchar*) malloc(sizeof(uchar) * (length));
+ if (pattern == NULL) {
+ fprintf(stderr, "Error: cannot allocate\n");
+ exit(1);
+ }
+
+ while (res_patt) {
+
+ if (fread(pattern, sizeof(*pattern), length, stdin) != length) {
+ fprintf(stderr, "Error: cannot read patterns file\n");
+ perror("run_queries");
+ exit(1);
+ }
+
+ /* Count */
+ time = getTime();
+ numocc = count(csa, pattern, pattern+length);
+
+ if (Verbose) {
+ fwrite(&length, sizeof(length), 1, stdout);
+ fwrite(pattern, sizeof(*pattern), length, stdout);
+ fwrite(&numocc, sizeof(numocc), 1, stdout);
+ }
+ tot_time += (getTime() - time);
+ tot_numocc += numocc;
+ res_patt--;
+ }
+
+ fprintf(stderr, "# Total_Num_occs_found = %lu\n", tot_numocc);
+ fprintf(stderr, "# Count_time_in_milli_sec = %.4f\n", tot_time*1000);
+ fprintf(stderr, "# Count_time/Pattern_chars = %.4f\n",
+ (tot_time * 1000) / (length * numpatt));
+ fprintf(stderr, "# Count_time/Num_patterns = %.4f\n\n",
+ (tot_time * 1000) / numpatt);
+ fprintf(stderr, "# (Load_time+Count_time)/Pattern_chars = %.4f\n",
+ ((Load_time+tot_time) * 1000) / (length * numpatt));
+ fprintf(stderr, "# (Load_time+Count_time)/Num_patterns = %.4f\n\n",
+ ((Load_time+tot_time) * 1000) / numpatt);
+
+ free(pattern);
+}
+
+
+void
+do_locate(const CSA_TYPE& csa)
+{
+ ulong numocc, length;
+ ulong tot_numocc = 0, numpatt = 0, processed_pat = 0;
+ double time, tot_time = 0;
+ uchar* pattern;
+
+ pfile_info(&length, &numpatt);
+
+ pattern = (uchar*) malloc(sizeof(uchar) * (length));
+ if (pattern == NULL) {
+ fprintf(stderr, "Error: cannot allocate\n");
+ exit(1);
+ }
+ /*SG: added timeout of 60 seconds */
+ while (numpatt and tot_time < 60.0) {
+
+ if (fread(pattern, sizeof(*pattern), length, stdin) != length) {
+ fprintf(stderr, "Error: cannot read patterns file\n");
+ perror("run_queries");
+ exit(1);
+ }
+ // Locate
+ time = getTime();
+ auto occs = locate(csa, (char*)pattern, (char*)pattern+length);
+ numocc = occs.size();
+ tot_time += (getTime() - time);
+ ++processed_pat;
+
+ tot_numocc += numocc;
+ numpatt--;
+
+ if (Verbose) {
+ fwrite(&length, sizeof(length), 1, stdout);
+ fwrite(pattern, sizeof(*pattern), length, stdout);
+ fwrite(&numocc, sizeof(numocc), 1, stdout);
+ }
+ }
+
+ fprintf(stderr, "# processed_pattern = %lu\n", processed_pat);
+ fprintf(stderr, "# Total_Num_occs_found = %lu\n", tot_numocc);
+ fprintf(stderr, "# Locate_time_in_secs = %.2f\n", tot_time);
+ fprintf(stderr, "# Locate_time/Num_occs = %.4f\n\n", (tot_time * 1000) / tot_numocc);
+ fprintf(stderr, "# (Load_time+Locate_time)/Num_occs = %.4f\n\n", ((tot_time+Load_time) * 1000) / tot_numocc);
+
+ free(pattern);
+}
+
+
+/* Open patterns file and read header */
+void
+pfile_info(ulong* length, ulong* numpatt)
+{
+ int error;
+ uchar c;
+ uchar origfilename[257];
+
+ error = fscanf(stdin, "# number=%lu length=%lu file=%s forbidden=", numpatt,
+ length, origfilename);
+ if (error != 3) {
+ fprintf(stderr, "Error: Patterns file header not correct\n");
+ perror("run_queries");
+ exit(1);
+ }
+
+ fprintf(stderr, "# pat_cnt = %lu\n", *numpatt);
+ fprintf(stderr, "# pat_length = %lu\n", *length);
+ fprintf(stderr, "# forbidden_chars = ");
+
+ while ((c = fgetc(stdin)) != 0) {
+ if (c == '\n') break;
+ fprintf(stderr, "%d",c);
+ }
+
+ fprintf(stderr, "\n");
+
+}
+
+void
+do_extract(const CSA_TYPE& csa)
+{
+ int error = 0;
+ uchar* text, orig_file[257];
+ ulong num_pos, from, to, numchars, tot_ext = 0;
+ CSA_TYPE::size_type readlen = 0;
+ double time, tot_time = 0;
+
+ error = fscanf(stdin, "# number=%lu length=%lu file=%s\n", &num_pos, &numchars, orig_file);
+ if (error != 3) {
+ fprintf(stderr, "Error: Intervals file header is not correct\n");
+ perror("run_queries");
+ exit(1);
+ }
+ fprintf(stderr, "# number=%lu length=%lu file=%s\n", num_pos, numchars, orig_file);
+
+ while (num_pos) {
+
+ if (fscanf(stdin,"%lu,%lu\n", &from, &to) != 2) {
+ fprintf(stderr, "Cannot read correctly intervals file\n");
+ exit(1);
+ }
+
+ time = getTime();
+ text = (uchar*)malloc(to-from+2);
+ readlen += extract(csa, from, to, text);
+ tot_time += (getTime() - time);
+
+ tot_ext += readlen;
+
+ if (Verbose) {
+ fwrite(&from,sizeof(ulong),1,stdout);
+ fwrite(&readlen,sizeof(ulong),1,stdout);
+ fwrite(text,sizeof(uchar),readlen, stdout);
+ }
+
+ num_pos--;
+ free(text);
+ }
+
+ fprintf(stderr, "# Total_num_chars_extracted = %lu\n", tot_ext);
+ fprintf(stderr, "# Extract_time_in_sec = %.2f\n", tot_time);
+ fprintf(stderr, "# Extract_time/Num_chars_extracted = %.4f\n\n",
+ (tot_time * 1000) / tot_ext);
+ fprintf(stderr, "(Load_time+Extract_time)/Num_chars_extracted = %.4f\n\n",
+ ((Load_time+tot_time) * 1000) / tot_ext);
+}
+
+double
+getTime(void)
+{
+
+ double usertime, systime;
+ struct rusage usage;
+
+ getrusage(RUSAGE_SELF, &usage);
+
+ usertime = (double) usage.ru_utime.tv_sec +
+ (double) usage.ru_utime.tv_usec / 1000000.0;
+
+ systime = (double) usage.ru_stime.tv_sec +
+ (double) usage.ru_stime.tv_usec / 1000000.0;
+
+ return (usertime + systime);
+
+}
+
+void usage(char* progname)
+{
+ fprintf(stderr, "\nThe program loads <index> and then executes over it the\n");
+ fprintf(stderr, "queries it receives from the standard input. The standard\n");
+ fprintf(stderr, "input comes in the format of the files written by \n");
+ fprintf(stderr, "genpatterns or genintervals.\n");
+ fprintf(stderr, "%s reports on the standard error time statistics\n", progname);
+ fprintf(stderr, "regarding to running the queries.\n\n");
+ fprintf(stderr, "Usage: %s <index> <type> [length] [V]\n", progname);
+ fprintf(stderr, "\n\t<type> denotes the type of queries:\n");
+ fprintf(stderr, "\t %c counting queries;\n", COUNT);
+ fprintf(stderr, "\t %c locating queries;\n", LOCATE);
+ fprintf(stderr, "\t %c displaying queries;\n", DISPLAY);
+ fprintf(stderr, "\t %c extracting queries.\n\n", EXTRACT);
+ fprintf(stderr, "\n\t[length] must be provided in case of displaying queries (D)\n");
+ fprintf(stderr, "\t and denotes the number of characters to display\n");
+ fprintf(stderr, "\t before and after each pattern occurrence.\n");
+ fprintf(stderr, "\n\t[V] with this options it reports on the standard output\n");
+ fprintf(stderr, "\t the results of the queries. The results file should be\n");
+ fprintf(stderr, "\t compared with trusted one by compare program.\n\n");
+}
diff --git a/benchmark/indexing_locate/test_case.config b/benchmark/indexing_locate/test_case.config
new file mode 100644
index 0000000..43d7394
--- /dev/null
+++ b/benchmark/indexing_locate/test_case.config
@@ -0,0 +1,10 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENGLISH;../data/english.200MB;english.200MB;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz
+DBLPXML;../data/dblp.xml.200MB;dblp.xml.200MB;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz
+DNA;../data/dna.200MB;dna.200MB;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz
+PROTEINS;../data/proteins.200MB;proteins.200MB;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz
+SOURCES;../data/sources.200MB;sources.200MB;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz
diff --git a/benchmark/indexing_locate/visualize/.gitignore b/benchmark/indexing_locate/visualize/.gitignore
new file mode 100644
index 0000000..8d39592
--- /dev/null
+++ b/benchmark/indexing_locate/visualize/.gitignore
@@ -0,0 +1,6 @@
+*
+!.gitignore
+!Makefile
+!index-filter.config
+!locate.R
+!locate.tex
diff --git a/benchmark/indexing_locate/visualize/Makefile b/benchmark/indexing_locate/visualize/Makefile
new file mode 100644
index 0000000..dde419c
--- /dev/null
+++ b/benchmark/indexing_locate/visualize/Makefile
@@ -0,0 +1,16 @@
+include ../../../Make.helper
+CONFIG_FILES=index-filter.config ../index.config ../test_case.config ../sample.config
+
+all: locate.pdf
+
+locate.pdf: locate.tex tbl-locate.tex fig-locate.tex
+ @echo "Use pdflatex to generate locate.pdf"
+ @pdflatex locate.tex >> LaTeX.Log 2>&1
+
+tbl-locate.tex fig-locate.tex: ../../basic_functions.R locate.R $(CONFIG_FILES) ../results/all.txt
+ @echo "Use R to generate tbl-locate.tex and fig-locate.tex"
+ @R --vanilla < locate.R > R.log 2>&1
+
+clean:
+ rm -f locate.pdf locate.aux fig-locate.tex tbl-locate.tex \
+ locate.log R.log LaTeX.log
diff --git a/benchmark/indexing_locate/visualize/index-filter.config b/benchmark/indexing_locate/visualize/index-filter.config
new file mode 100644
index 0000000..705fb11
--- /dev/null
+++ b/benchmark/indexing_locate/visualize/index-filter.config
@@ -0,0 +1,11 @@
+# Use this file to specify which indexes are listed in the report locate.pdf
+# and how they look like in the report.
+#
+# List all the index ids which should be included in the report. Note that
+# the listed index ids must also be present in the file `../index.config`.
+# Eeach INDEX_ID should be listed on a separate line followed by the style:
+# [pch];[lty];[col] (point type, line type, and color).
+FM_HUFF; 1;solid;black
+FM_HUFF_RRR15; 2;solid;blue
+CSA_SADA; 3;solid;red
+FM_HUFF_RRR63; 4;solid;blue
diff --git a/benchmark/indexing_locate/visualize/locate.R b/benchmark/indexing_locate/visualize/locate.R
new file mode 100644
index 0000000..7b0fb35
--- /dev/null
+++ b/benchmark/indexing_locate/visualize/locate.R
@@ -0,0 +1,76 @@
+require(tikzDevice)
+source("../../basic_functions.R")
+
+# Load filter information
+config <- readConfig("index-filter.config",c("IDX_ID","PCH","LTY","COL"))
+idx_config <- readConfig("../index.config",c("IDX_ID","SDSL_TYPE","LATEX-NAME"))
+tc_config <- readConfig("../test_case.config",c("TC_ID","PATH","LATEX-NAME","URL"))
+
+# Load data
+raw <- data_frame_from_key_value_pairs( "../results/all.txt" )
+# Filter indexes
+raw <- raw[raw[["IDX_ID"]]%in%config[["IDX_ID"]],]
+raw[["IDX_ID"]] <- factor(raw[["IDX_ID"]])
+# Normalize data
+raw[["Time"]] <- 1000000*raw[["Locate_time_in_secs"]]/raw[["Total_Num_occs_found"]]
+raw[["Space"]] <- 100*raw[["Index_size_in_bytes"]]/raw[["text_size"]]
+
+raw <- raw[c("TC_ID", "Space", "Time","IDX_ID","S_SA","S_ISA")]
+raw <- raw[order(raw[["TC_ID"]]),]
+
+data <- split(raw, raw[["TC_ID"]])
+
+tikz("fig-locate.tex", width = 5.5, height = 6, standAlone = F)
+
+multi_figure_style( length(data)/2+1, 2 )
+
+max_space <- 100*2.5 #1.3 # 2.5 #1.8
+max_time <- 25 # in microseconds
+count <- 0
+nr <- 0
+xlabnr <- (2*(length(data)/2)-1)
+for( tc_id in names(data) ){
+ d <- data[[tc_id]]
+
+ plot(c(),c(),xlim=c(0, max_space), ylim=c(0, max_time), xlab="", axes=F, xaxt="n", yaxt="n", ylab="" )
+ box(col="gray")
+ grid(lty="solid")
+ if ( nr %% 2 == 0 ){
+ ylable <- "Time per occurrence ($\\mu s$)"
+ axis( 2, at = axTicks(2) )
+ mtext(ylable, side=2, line=2, las=0)
+ }
+ axis( 1, at = axTicks(1), labels=(nr>=xlabnr) )
+ if ( nr >= xlabnr ){
+ xlable <- "Index size in (\\%)"
+ mtext(xlable, side=1, line=2, las=0)
+ }
+ dd <- split(d, d[["IDX_ID"]])
+ for( idx_id in names(dd) ){
+ ddd <- dd[[idx_id]]
+ lines(ddd[["Space"]], ddd[["Time"]], type="b", lwd=1, pch=config[idx_id, "PCH"],
+ lty=config[idx_id, "LTY"],
+ col=config[idx_id, "COL"]
+ )
+ }
+ draw_figure_heading( sprintf("instance = \\textsc{%s}",tc_config[tc_id,"LATEX-NAME"]) )
+ comp_info <- readConfig(paste("../",tc_config[tc_id,"PATH"],".z.info",sep=""),c("NAME","RATIO","COMMAND"))
+ abline(v=comp_info["xz","RATIO"],lty=1);
+ abline(v=comp_info["gzip","RATIO"],lty=4);
+
+ nr <- nr+1
+ if ( nr == 1 ){ # plot legend
+ plot(NA, NA, xlim=c(0,1),ylim=c(0,1),ylab="", xlab="", bty="n", type="n", yaxt="n", xaxt="n")
+ idx_ids <- as.character(unique(raw[["IDX_ID"]]))
+ legend( "top", legend=idx_config[idx_ids,"LATEX-NAME"], pch=config[idx_ids,"PCH"], col=config[idx_ids,"COL"],
+ lty=config[idx_ids,"LTY"], bty="n", y.intersp=1.5, ncol=2, title="Index", cex=1.2)
+ legend( "bottom", legend=c("\\textsc{xz}~(\\texttt{-9})","\\textsc{gzip}~(\\texttt{-9})"),
+ lty=c(1,4), bty="n", y.intersp=1.5, ncol=2, title="Compression baseline", cex=1.2)
+ nr <- nr+1
+ }
+}
+dev.off()
+
+sink("tbl-locate.tex")
+cat(typeInfoTable("../index.config", config[["IDX_ID"]], 1, 3, 2))
+sink(NULL)
diff --git a/benchmark/indexing_locate/visualize/locate.tex b/benchmark/indexing_locate/visualize/locate.tex
new file mode 100644
index 0000000..919f096
--- /dev/null
+++ b/benchmark/indexing_locate/visualize/locate.tex
@@ -0,0 +1,23 @@
+\documentclass[9pt,a4paper]{scrartcl}
+\usepackage{array}
+\usepackage{booktabs}
+\usepackage{ragged2e}
+\usepackage{tikz}
+
+\begin{document}
+\pagestyle{empty}
+
+\begin{figure}
+\input{fig-locate.tex}
+\caption{Time-space trade-offs for operation locate.}
+\end{figure}
+
+\begin{table}
+\centering
+\input{tbl-locate.tex}
+\caption{Class definition of the indexes used in the experiment.
+The sampling rates \texttt{S\_SA} and \texttt{S\_ISA} for
+suffix and inverse suffix values was varied.}
+\end{table}
+
+\end{document}
diff --git a/benchmark/lcp/.gitignore b/benchmark/lcp/.gitignore
new file mode 100644
index 0000000..ee78702
--- /dev/null
+++ b/benchmark/lcp/.gitignore
@@ -0,0 +1,11 @@
+*
+!.gitignore
+!lcp.config
+!README.md
+!bin/
+!src/
+!visualize/
+!compile_options.config
+!Makefile
+!results/
+!test_case.config
diff --git a/benchmark/lcp/Makefile b/benchmark/lcp/Makefile
new file mode 100644
index 0000000..4043263
--- /dev/null
+++ b/benchmark/lcp/Makefile
@@ -0,0 +1,67 @@
+include ../../Make.helper
+CFLAGS = $(MY_CXX_FLAGS)
+SRC_DIR = src
+BIN_DIR = bin
+LIBS = -lsdsl -ldivsufsort -ldivsufsort64
+
+C_OPTIONS:=$(call config_ids,compile_options.config)
+TC_IDS:=$(call config_ids,test_case.config)
+LCP_IDS:=$(call config_ids,lcp.config)
+
+
+DL = ${foreach TC_ID,$(TC_IDS),$(call config_select,test_case.config,$(TC_ID),2)}
+
+LCP_EXECS = $(foreach LCP_ID,$(LCP_IDS),$(BIN_DIR)/build_$(LCP_ID))
+
+RES_FILES = $(foreach TC_ID,$(TC_IDS),\
+ results/$(TC_ID))
+
+RESULT_FILE=results/all.txt
+
+execs: $(BIN_DIR)/prep_sa_bwt $(LCP_EXECS)
+
+timing: execs $(RES_FILES)
+ @cat $(RES_FILES) > $(RESULT_FILE)
+ @cd visualize;make
+
+$(BIN_DIR)/prep_sa_bwt: $(SRC_DIR)/create_sa_bwt.cpp
+ @echo "Compiling prep_sa_bwt"
+ @$(MY_CXX) $(CFLAGS) $(C_OPTIONS) -L${LIB_DIR}\
+ $(SRC_DIR)/create_sa_bwt.cpp -I${INC_DIR} -o bin/prep_sa_bwt $(LIBS)
+
+precalc%: test_case.config $(DL) lcp.config
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval LCP_TEX_NAME:=$(call config_select,lcp.config,$(LCP_ID),3))
+ $(eval TC_TEX_NAME:=$(call config_select,test_case.config,$(TC_ID),3))
+ $(eval TC_PATH:=$(call config_select,test_case.config,$(TC_ID),2))
+ $(eval TC_SIZE:=$(shell wc -c <$(TC_PATH)))
+ @echo "Running test case: $(TC_ID)"
+ @echo "# TC_ID = $(TC_ID)" > results/$(TC_ID)
+ @echo "# TC_TEX_NAME = $(TC_TEX_NAME)">> results/$(TC_ID)
+ @echo "# TC_SIZE = $(TC_SIZE)">> results/$(TC_ID)
+ @$(BIN_DIR)/prep_sa_bwt $(TC_PATH) >> results/$(TC_ID)
+
+results/%: precalc%
+ @$(foreach LCP_EXEC,$(LCP_EXECS),$(shell $(LCP_EXEC) >>$@;rm -f lcp_tmp.sdsl isa_tmp.sdsl))
+ @rm *.sdsl
+
+$(BIN_DIR)/build_%: $(SRC_DIR)/create_lcp.cpp lcp.config
+ $(eval LCP_ID:=$(call dim,1,$*))
+ $(eval LCP_TYPE:=$(call config_select,lcp.config,$(LCP_ID),2))
+ @echo "Compiling build_$*"
+ @$(MY_CXX) $(CFLAGS) $(C_OPTIONS) -DLCP_TYPE="$(LCP_TYPE)" -DLCPID="$(LCP_ID)" -L${LIB_DIR}\
+ $(SRC_DIR)/create_lcp.cpp -I${INC_DIR} -o $@ $(LIBS)
+
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ rm -f $(BIN_DIR)/build*
+ rm -f $(BIN_DIR)/prep*
+
+clean-result:
+ @echo "Remove results"
+ rm -f results/*
+
+cleanall: clean-build clean-result
diff --git a/benchmark/lcp/README.md b/benchmark/lcp/README.md
new file mode 100644
index 0000000..bc5d6d2
--- /dev/null
+++ b/benchmark/lcp/README.md
@@ -0,0 +1,53 @@
+# Benchmarking LCP algorithms
+
+## Methodology
+
+Explored dimensions:
+
+ * lcp algorithms
+ * test cases
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which generates
+ a report in LaTeX format.
+
+## Prerequisites
+
+ * For the visualization you need the following software:
+ - [R][RPJ] with package `xtable`. You can install the
+ package by calling `install.packages("xtable")` in R.
+ - [pdflatex][LT] to generate the pdf reports.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads
+ the test instances, builds the LCP arrays and generates a report located at
+ `visualize/lcp.pdf`. The raw numbers of the timings
+ can be found in the `results/all.txt`. The execution of the
+ default benchmark took 66 minutes on my machine (MacBookPro Retina
+ 2.6GHz Intel Core i7, 16GB 1600 Mhz DDR3, SSD).
+ Have a look at the [generated report][RES].
+ * All created binaries and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+
+ The project contains several configuration files:
+
+ * [wt.config][LCPCONFIG]: Specify different LCP algorithms.
+ * [test_case.config][TCCONF]: Specify test instances by ID, path, LaTeX-name
+ for the report, and download URL.
+ * [compile_options.config][CCONF]: Specify compile options by option string.
+
+ Note that the benchmark will execute every combination of lcp algorithms and test cases.
+
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[LCPCONFIG]: ./lcp.config "lcp.config"
+[TCCONF]: ./test_case.config "test_case.config"
+[CCONF]: ./compile_options.config "compile_options.config"
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/lcp.pdf "lcp.pdf"
diff --git a/benchmark/lcp/bin/.gitignore b/benchmark/lcp/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/lcp/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/lcp/compile_options.config b/benchmark/lcp/compile_options.config
new file mode 100644
index 0000000..cebc3e9
--- /dev/null
+++ b/benchmark/lcp/compile_options.config
@@ -0,0 +1,2 @@
+# Compile options
+-O3 -funroll-loops -fomit-frame-pointer -ffast-math -DNDEBUG
diff --git a/benchmark/lcp/lcp.config b/benchmark/lcp/lcp.config
new file mode 100644
index 0000000..0a47d09
--- /dev/null
+++ b/benchmark/lcp/lcp.config
@@ -0,0 +1,14 @@
+# This file specifies wavelettrees that are used in the benchmark.
+#
+# Each LCP algorithm is specified by a 4-tupel: LCP_ID;LCP_ALGORITHM;LCP_LATEX_NAME;BWT_NEEDED
+# * LCP_ID : An identifier for the index. Only letters and underscores are allowed in ID.
+# * LCP_ALGORITHM : Corresponding lcp alogrithm.
+# * LCP_LATEX_NAME: LaTeX name for output in the benchmark report.
+# * BWT_NEEDED : T(rue) if lcp algorithm needs bwt as input, otherwise F(alse).
+kasai;construct_lcp_kasai<8>;lcp-kasai;F
+phi_algorithm;construct_lcp_PHI<8>;lcp-$\Phi$;F
+semi_extern_phi;construct_lcp_semi_extern_PHI;lcp-semi-extern-$\Phi$;F
+go;construct_lcp_go;lcp-go;T
+goPhi;construct_lcp_goPHI;lcp-go-$\Phi$;T
+bwtb;construct_lcp_bwt_based;lcp-bwt-based;T
+bwtb2;construct_lcp_bwt_based2;lcp-bwt-based2;T
diff --git a/benchmark/lcp/results/.gitignore b/benchmark/lcp/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/lcp/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/lcp/src/.gitignore b/benchmark/lcp/src/.gitignore
new file mode 100644
index 0000000..f666eea
--- /dev/null
+++ b/benchmark/lcp/src/.gitignore
@@ -0,0 +1,4 @@
+*
+!.gitignore
+!create_lcp.cpp
+!create_sa_bwt.cpp
diff --git a/benchmark/lcp/src/create_lcp.cpp b/benchmark/lcp/src/create_lcp.cpp
new file mode 100644
index 0000000..1a5524a
--- /dev/null
+++ b/benchmark/lcp/src/create_lcp.cpp
@@ -0,0 +1,34 @@
+#include <sdsl/sdsl_concepts.hpp>
+#include <sdsl/int_vector.hpp>
+#include <sdsl/construct.hpp>
+#include <sdsl/construct_lcp.hpp>
+#include <string>
+#include <chrono>
+
+using namespace sdsl;
+using namespace std;
+using namespace std::chrono;
+
+#define S(x) #x
+#define SX(x) S(x)
+
+int main()
+{
+ memory_monitor::start();
+ string dir = ".";
+ string id = "tmp";
+ cache_config config(false, dir, id);
+
+ register_cache_file(conf::KEY_TEXT, config);
+ register_cache_file(conf::KEY_SA, config);
+ register_cache_file(conf::KEY_BWT, config);
+
+ auto start = high_resolution_clock::now();
+ LCP_TYPE(config);
+ auto stop = high_resolution_clock::now();
+ memory_monitor::stop();
+ cout << "# " SX(LCPID) "_TIME = " << duration_cast<milliseconds>(stop-start).count()/(double)1000 << endl;
+ cout << "# " SX(LCPID) "_MMPEAK = "<< memory_monitor::peak() << endl;
+
+ return 0;
+}
diff --git a/benchmark/lcp/src/create_sa_bwt.cpp b/benchmark/lcp/src/create_sa_bwt.cpp
new file mode 100644
index 0000000..7d727d5
--- /dev/null
+++ b/benchmark/lcp/src/create_sa_bwt.cpp
@@ -0,0 +1,71 @@
+#include <sdsl/sdsl_concepts.hpp>
+#include <sdsl/int_vector.hpp>
+#include <sdsl/construct.hpp>
+#include <sdsl/construct_sa.hpp>
+#include <sdsl/construct_bwt.hpp>
+#include <string>
+#include <chrono>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+using namespace std::chrono;
+
+typedef bit_vector::size_type size_type;
+
+//argv[1] = test file
+int main(int argc, char** argv)
+{
+ if (argc != 2) {
+ std::cout<<"Usage: input_file" << std::endl;
+ }
+ memory_monitor::start();
+ string file = argv[1];
+ uint8_t num_bytes = 1; // Byte Alphabet
+ string dir = ".";
+ string id = "tmp";
+ cache_config config(false, dir, id);
+
+ //load text
+ auto start = high_resolution_clock::now();
+ {
+ int_vector<8> text;
+ load_vector_from_file(text, file, num_bytes);
+ if (contains_no_zero_symbol(text, file)) {
+ append_zero_symbol(text);
+ store_to_cache(text, conf::KEY_TEXT, config);
+ }
+ register_cache_file(conf::KEY_TEXT, config);
+ }
+ auto stop = high_resolution_clock::now();
+ memory_monitor::stop();
+ cout << "# TXT_TIME = " << duration_cast<milliseconds>(stop-start).count()/(double)1000 << endl;
+ cout << "# TXT_MMPEAK = " << memory_monitor::peak() << endl;
+
+ //construct sa
+ memory_monitor::start();
+ start = high_resolution_clock::now();
+ {
+ construct_sa<8>(config);
+ register_cache_file(conf::KEY_SA, config);
+ }
+ stop = high_resolution_clock::now();
+ memory_monitor::stop();
+ cout << "# SA_TIME = " << duration_cast<milliseconds>(stop-start).count()/(double)1000 << endl;
+ cout << "# SA_MMPEAK = " << memory_monitor::peak() << endl;
+
+ //construct bwt
+ memory_monitor::start();
+ start = high_resolution_clock::now();
+ {
+ construct_bwt<8>(config);
+ register_cache_file(conf::KEY_BWT, config);
+ }
+ stop = high_resolution_clock::now();
+ memory_monitor::stop();
+ cout << "# BWT_TIME = " << duration_cast<milliseconds>(stop-start).count()/(double)1000 <<endl;
+ cout << "# BWT_MMPEAK = "<< memory_monitor::peak() << endl;
+
+ return 0;
+}
+
diff --git a/benchmark/lcp/test_case.config b/benchmark/lcp/test_case.config
new file mode 100644
index 0000000..51588d5
--- /dev/null
+++ b/benchmark/lcp/test_case.config
@@ -0,0 +1,16 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+ENGLISH;../data/english.200MB;english.200MB;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz
+DBLPXML;../data/dblp.xml.200MB;dblp.xml.200MB;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz
+DNA;../data/dna.200MB;dna.200MB;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz
+PROTEINS;../data/proteins.200MB;proteins.200MB;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz
+SOURCES;../data/sources.200MB;sources.200MB;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz
+INFLUENZA;../data/influenza;influenza;http://pizzachili.dcc.uchile.cl/repcorpus/real/influenza.gz
+EINSTEIN-de;../data/einstein.de.txt;einstein-de;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.de.txt.gz
+EINSTEIN-en;../data/einstein.en.txt;einstein-en;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.en.txt.gz
+PARA;../data/para;para;http://pizzachili.dcc.uchile.cl/repcorpus/real/para.gz
+WORLDLEADER;../data/world_leaders;world-leaders;http://pizzachili.dcc.uchile.cl/repcorpus/real/world_leaders.gz
+E-COLI;../data/Escherichia_Coli;E.coli;http://pizzachili.dcc.uchile.cl/repcorpus/real/Escherichia_Coli.gz
diff --git a/benchmark/lcp/visualize/.gitignore b/benchmark/lcp/visualize/.gitignore
new file mode 100644
index 0000000..c652565
--- /dev/null
+++ b/benchmark/lcp/visualize/.gitignore
@@ -0,0 +1,6 @@
+*
+!.gitignore
+!Makefile
+!lcp-header.tex
+!lcp-footer.tex
+!lcp.R
diff --git a/benchmark/lcp/visualize/Makefile b/benchmark/lcp/visualize/Makefile
new file mode 100644
index 0000000..3982c74
--- /dev/null
+++ b/benchmark/lcp/visualize/Makefile
@@ -0,0 +1,17 @@
+include ../../../Make.helper
+
+CONFIG_FILES= ../test_case.config
+
+all: lcp.pdf
+
+lcp.pdf: lcp.tex
+ @echo "Use pdflatex to generate lcp.pdf"
+ @pdflatex lcp.tex >> LaTeX.Log 2>&1
+
+lcp.tex: ../results/all.txt ../../basic_functions.R lcp.R $(CONFIG_FILES)
+ @echo "Use R to generate lcp.tex"
+ @R --vanilla < lcp.R > R.log 2>&1
+
+clean:
+ rm -f lcp.pdf lcp.aux lcp.tex fig* \
+ lcp.log R.log LaTeX.log
diff --git a/benchmark/lcp/visualize/lcp-footer.tex b/benchmark/lcp/visualize/lcp-footer.tex
new file mode 100644
index 0000000..6b47932
--- /dev/null
+++ b/benchmark/lcp/visualize/lcp-footer.tex
@@ -0,0 +1 @@
+\end{document}
diff --git a/benchmark/lcp/visualize/lcp-header.tex b/benchmark/lcp/visualize/lcp-header.tex
new file mode 100644
index 0000000..be9e605
--- /dev/null
+++ b/benchmark/lcp/visualize/lcp-header.tex
@@ -0,0 +1,8 @@
+\documentclass[9pt,a4paper,DIV10]{scrartcl}
+\usepackage{booktabs}
+\usepackage{array}
+\usepackage{ragged2e}
+
+\begin{document}
+
+\pagestyle{empty}
diff --git a/benchmark/lcp/visualize/lcp.R b/benchmark/lcp/visualize/lcp.R
new file mode 100644
index 0000000..ecec3d8
--- /dev/null
+++ b/benchmark/lcp/visualize/lcp.R
@@ -0,0 +1,77 @@
+library(xtable)
+source("../../basic_functions.R")
+
+tex_file = "lcp.tex"
+
+tc_config <- readConfig("../test_case.config",c("TC_ID","PATH","LATEX_NAME","URL"))
+lcp_config <- readConfig("../lcp.config",c("LCP_ID","LCP_TYPE","LATEX_NAME","BWT"))
+
+
+make_latex_header <- function(names){
+ x <- paste("&&\\multicolumn{2}{c}{", names,"}")
+ x <- paste(x, collapse=" ")
+ clines=""
+ for(i in 1:length(names)){
+ clines <- paste(clines,"\\cmidrule{",3*i,"-",3*i+1,"}",sep="")
+ }
+ y <- paste("\\toprule",x, "\\\\",clines,"\n")
+ gsub("_","\\\\_",y)
+}
+
+#read header
+sink(tex_file)
+cat(paste(readLines("lcp-header.tex"),collapse="\n"))
+
+maindata <- data_frame_from_key_value_pairs( "../results/all.txt" )
+
+names<-c("SA","BWT","LCP","OVERALL")
+unitrow <- paste(c("", rep(c("&&Time", "&Space"), length(names)), "\\\\","", rep(c("&&(sec)", "&(\\%)"), length(names)), "\\\\[1ex]"), collapse="", sep='')
+
+# create a table for each test case
+for(i in 1:nrow(maindata)){
+
+ data<-maindata[i,]
+ row<-nrow(lcp_config)
+ size<-data[["TC_SIZE"]]
+ table<-data.frame(EMPTY=character(row),SATIME=character(row),SASPACE=character(row),EMPTY2=character(row),BWTTIME=character(row),BWTSPACE=character(row),EMPTY3=character(row),LCPTIME=character(row),LCPSPACE=character(row),EMPTY4=character(row),OVERALLTIME=character(row),OVERALLSPACE=character(row),stringsAsFactors=FALSE)
+
+ # gather data
+ for(l in 1:row){
+ table[l,]["SATIME"]<-sprintf("%.2f",data[["SA_TIME"]])
+ table[l,]["SASPACE"]<-round(data[["SA_MMPEAK"]]*100/size, digits=0)
+
+
+ if(lcp_config[["BWT"]][l]){
+ table[l,]["BWTTIME"]<-sprintf("%.2f",data[["BWT_TIME"]])
+ table[l,]["BWTSPACE"]<-round(data[["BWT_MMPEAK"]]*100/size, digits=0)
+ table[l,]["OVERALLTIME"]<-sprintf("%.2f",data[["SA_TIME"]]+data[["BWT_TIME"]]+data[[paste(lcp_config[["LCP_ID"]][l],"_TIME",sep="")]])
+ table[l,]["OVERALLSPACE"]<-round(max(data[["SA_MMPEAK"]],data[["BWT_MMPEAK"]],data[[paste(lcp_config[["LCP_ID"]][l],"_MMPEAK",sep="")]])*100/size, digits=0)
+ }
+ else{
+ table[l,]["BWTTIME"]<-"-"
+ table[l,]["BWTSPACE"]<-"-"
+ table[l,]["OVERALLTIME"]<-sprintf("%.2f",data[["SA_TIME"]]+data[[paste(lcp_config[["LCP_ID"]][l],"_TIME",sep="")]])
+ table[l,]["OVERALLSPACE"]<-round(max(data[["SA_MMPEAK"]],data[[paste(lcp_config[["LCP_ID"]][l],"_MMPEAK",sep="")]])*100/size, digits=0)
+ }
+
+ table[l,]["LCPTIME"]<-sprintf("%.2f",data[[paste(lcp_config[["LCP_ID"]][l],"_TIME",sep="")]])
+ table[l,]["LCPSPACE"]<-round(data[[paste(lcp_config[["LCP_ID"]][l],"_MMPEAK",sep="")]]*100/size, digits=0)
+ }
+
+ row.names(table)<-lcp_config[["LATEX_NAME"]]
+
+ # convert and print table
+ ali <- c("l", rep(c("@{\\hspace{1ex}}l","c","c"), (ncol(table))/3) )
+ dig <- c(0, rep(c(0,3,0),(ncol(table))/3 ))
+
+ print( xtable(table, align=ali, digits=dig,
+ caption = paste("Results for ",as.character(data[["TC_TEX_NAME"]])," (size: ",round(size/(1024^2), digits=3),"MB). Runtime in seconds. Space is the peak memory usage (including input and output) as fraction of original file size.")),
+ add.to.row=list(pos=list(-1,0,nrow(table)), command=c(make_latex_header(names),unitrow,"\\bottomrule")),
+ hline.after=c(),
+ sanitize.rownames.function = identity,
+ include.colnames = FALSE
+ )
+}
+
+cat(paste(readLines("lcp-footer.tex"),collapse="\n"))
+sink(NULL)
diff --git a/benchmark/rrr_vector/Makefile b/benchmark/rrr_vector/Makefile
new file mode 100644
index 0000000..40a47a3
--- /dev/null
+++ b/benchmark/rrr_vector/Makefile
@@ -0,0 +1,81 @@
+include ../Make.helper
+CXX_FLAGS = $(MY_CXX_FLAGS) # in compile_options.config
+LIBS = -lsdsl
+SRC_DIR = src
+TMP_DIR = ../tmp
+# Sampling rate for rrr_vector
+t=32
+# Block sizes
+TC_PATHS:=$(call config_column,test_case.config,2)
+TC_IDS:=$(call config_ids,test_case.config)
+COMPILE_IDS:=$(call config_ids,compile_options.config)
+KS:=$(call config_ids,block_size.config)
+
+all: execs
+
+input: bin/generate_rnd_bitvector $(TC_PATHS)
+
+RRR_EXECS = $(foreach K,$(KS),\
+ $(foreach COMPILE_ID,$(COMPILE_IDS),bin/rrr_time_and_space_$(K).$(COMPILE_ID)))
+
+RES_FILES = $(foreach TC_ID,$(TC_IDS),\
+ $(foreach K,$(KS),\
+ $(foreach COMPILE_ID,$(COMPILE_IDS),\
+ results/$(TC_ID).$(K).$(COMPILE_ID))))
+
+RES_FILE=results/all.txt
+
+# Target for the generator programs for the random bitvectors of different densities
+bin/generate_rnd_bitvector: ${SRC_DIR}/generate_rnd_bitvector.cpp
+ $(MY_CXX) -O3 $(CXX_FLAGS) $(SRC_DIR)/generate_rnd_bitvector.cpp -L$(LIB_DIR) -I$(INC_DIR) -o $@ $(LIBS)
+
+# Targets for the access/rank/select rrr_vector experiment
+# Format: bin/rrr_time_and_space_[R].[COMPILE_ID]
+bin/rrr_time_and_space_%: $(SRC_DIR)/rrr_time_and_space.cpp
+ $(eval K:=$(call dim,1,$*))
+ $(eval COMPILE_ID:=$(call dim,2,$*))
+ $(eval COMPILE_OPTIONS:=$(call config_select,compile_options.config,$(COMPILE_ID),2))
+ $(MY_CXX) $(CXX_FLAGS) $(COMPILE_OPTIONS) -DBLOCK_SIZE=$(K) -L$(LIB_DIR) \
+ $(SRC_DIR)/rrr_time_and_space.cpp -I$(INC_DIR) -o $@ $(LIBS)
+
+execs: $(RRR_EXECS)
+
+
+timing: input execs $(RES_FILES)
+ cat $(RES_FILES) > $(RES_FILE)
+ @cd visualize; make
+
+# Format: results/[TC_ID].[K].[COMPILE_ID]
+results/%:
+ $(eval TC_ID:=$(call dim,1,$*))
+ $(eval K:=$(call dim,2,$*))
+ $(eval COMPILE_ID:=$(call dim,3,$*))
+ $(eval TC_PATH:=$(call config_select,test_case.config,$(TC_ID),2))
+ @echo "Running bin/rrr_time_and_space_$(K).$(COMPILE_ID) on $(TC_ID)"
+ @echo "# TC_ID = $(TC_ID)" >> $@
+ @echo "# K = $(K)" >> $@
+ @echo "# COMPILE_ID = $(COMPILE_ID)" >> $@
+ @bin/rrr_time_and_space_$(K).$(COMPILE_ID) $(TC_PATH) $(t) >> $@
+
+# Target for generating a random bitvector of size SIZE and density DENSITY
+# Format: data/rnd_[DENSITY].[SIZE]
+../data/rnd_%: bin/generate_rnd_bitvector
+ $(eval DENSITY:=$(call dim,1,$*))
+ $(eval SIZE:=$(call dim,2,$*))
+ @echo "Generating bitvector of density $(DENSITY) and size $(SIZE)"
+ @bin/generate_rnd_bitvector $(SIZE) $(DENSITY) $@
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ rm -f $(RRR_EXECS)
+
+clean:
+ rm -f $(RRR_EXECS) bin/generate_rnd_bitvector
+
+clean_results:
+ rm -f $(RES_FILES)
+
+
+cleanall: clean clean_results
diff --git a/benchmark/rrr_vector/README.md b/benchmark/rrr_vector/README.md
new file mode 100644
index 0000000..85b45fc
--- /dev/null
+++ b/benchmark/rrr_vector/README.md
@@ -0,0 +1,68 @@
+# Benchmarking bitvector [rrr_vector](../../include/sdsl/rrr_vector.hpp)
+
+## Methodology
+
+Explored dimensions:
+
+ * block size K (K in [5..255])
+ * instance type (artificial, WT based)
+ * instance size (MB and GB range)
+ * methods (`access`, `rank`, `select`)
+ * compile options
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * `rrr_time_and_space_*` generates `rrr_vector`s, answers
+ queries and outputs space information.
+ * `generate_rnd_bitvector` generates evenly distributed bitvectors.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which generates
+ a report in LaTeX format.
+
+## Prerequisites
+ * For the visualization you need the following software:
+ - [R][RPJ] with package `tikzDevice`. You can install the
+ package by calling
+ `install.packages("filehash", repos="http://cran.r-project.org")`
+ and
+ `install.packages("tikzDevice", repos="http://R-Forge.R-project.org")`
+ in `R`.
+ - [pdflatex][LT] to generate the pdf reports.
+ * The processing of the 1GB bitvectors requires about
+ 1.5GB of RAM.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads or generates
+ the test instances, builds the compressed bitvectors,
+ runs the performance tests and generated a report located at
+ `visualize/rrr.pdf`. The raw numbers of the timings
+ can be found in the `results/all.txt`.
+ On my machine (MacBookPro Retina 2.6GHz Intel Core i7,
+ 16GB 1600 Mhz DDR3, SSD) the benchmark took about 58 minutes
+ (excluding the time to download the test instances).
+ Have a look at the [generated report][RES].
+ * All created indexes and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+ The project contains several configuration files:
+
+ * [block_size.config][KCONFIG]: Specify different block sizes.
+ * [test_case.config][TCCONF]: Specify test instances by
+ ID, path, LaTeX-name for the report, and download URL.
+ * [compile_options.config][CCONF]: Specify compile
+ options by ID and option string.
+
+ Note that the benchmark will execute every combination of your
+ choices.
+
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/rrr.pdf "rrr.pdf"
+[KCONFIG]: ./block_size.config "block_size.config"
+[TCCONF]: ./test_case.config "test_case.config"
+[CCONF]: ./compile_options.config "compile_options.config"
+[VCONF]: ./visualize/index-filter.config "index-filter.config"
diff --git a/benchmark/rrr_vector/bin/.gitignore b/benchmark/rrr_vector/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/rrr_vector/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/rrr_vector/block_size.config b/benchmark/rrr_vector/block_size.config
new file mode 100644
index 0000000..4b328b1
--- /dev/null
+++ b/benchmark/rrr_vector/block_size.config
@@ -0,0 +1,27 @@
+# Specify block sizes in [0..255] for which rrr_vector should be tested.
+# Each block size on one line. Default initialization is generated by
+#
+5
+7
+8
+9
+11
+14
+15
+16
+26
+31
+32
+46
+56
+63
+64
+84
+104
+124
+127
+128
+168
+208
+248
+255
diff --git a/benchmark/rrr_vector/compile_options.config b/benchmark/rrr_vector/compile_options.config
new file mode 100644
index 0000000..8fa4bd1
--- /dev/null
+++ b/benchmark/rrr_vector/compile_options.config
@@ -0,0 +1,6 @@
+# Compile configurations
+# Column description (columns are separated by semicolon):
+# (1) Identifier for compile configuration (consisting of letters)
+# (2) Compile options
+O3;-msse4.2 -O3 -funroll-loops -fomit-frame-pointer -ffast-math -DNDEBUG
+#NOOPT;-DRRR_NO_OPT -msse4.2 -O3 -funroll-loops -fomit-frame-pointer -ffast-math -DNDEBUG
diff --git a/benchmark/rrr_vector/results/.gitignore b/benchmark/rrr_vector/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/rrr_vector/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/rrr_vector/src/generate_rnd_bitvector.cpp b/benchmark/rrr_vector/src/generate_rnd_bitvector.cpp
new file mode 100644
index 0000000..a78ca61
--- /dev/null
+++ b/benchmark/rrr_vector/src/generate_rnd_bitvector.cpp
@@ -0,0 +1,47 @@
+#include <iostream>
+#include <fstream>
+#include <sdsl/int_vector.hpp>
+#include <sdsl/util.hpp>
+#include <string>
+
+using namespace std;
+using namespace sdsl;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 4) {
+ cout << "Usage: " << argv[0] << " length density file" << endl;
+ cout << " generates a bit_vector of`length` bits, populates it with " << endl;
+ cout << " `density`\% set bits and saves it to `file`.\n" << endl;
+ cout << "`length` format:\n";
+ cout << " X, where X is the length in number of bytes\n";
+ cout << " XkB, where X is the length in number of kilobytes\n";
+ cout << " XMB, where X is the length in number of megabytes\n";
+ cout << " XGB, where X is the length in number of gigabytes\n";
+ return 1;
+ }
+ uint64_t length = 0;
+ length = atoll(argv[1])*8; // length in bits
+ string length_str(argv[1]);
+ size_t Bpos = length_str.find_first_of("B");
+ if (Bpos != string::npos and Bpos > 1) {
+ char order = length_str.substr(Bpos-1,1)[0];
+ if (order == 'k' or order == 'K')
+ length <<= 10;
+ else if (order == 'm' or order == 'M')
+ length <<= 20;
+ else if (order == 'g' or order == 'G')
+ length <<= 30;
+ }
+ const uint64_t density = atoi(argv[2]);
+ cout << length << endl;
+ bit_vector v(length);
+ srand(17);
+ for (uint64_t i=0; i<v.size(); ++i) {
+ if ((uint64_t)(rand()%100) < density) {
+ v[i] = 1;
+ }
+ }
+ if (!store_to_file(v, argv[3]))
+ return 1;
+}
diff --git a/benchmark/rrr_vector/src/rrr_time_and_space.cpp b/benchmark/rrr_vector/src/rrr_time_and_space.cpp
new file mode 100644
index 0000000..3a3cc9a
--- /dev/null
+++ b/benchmark/rrr_vector/src/rrr_time_and_space.cpp
@@ -0,0 +1,103 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <sdsl/rrr_vector.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+#ifndef BLOCK_SIZE
+#define BLOCK_SIZE 31
+#endif
+
+#ifndef RANK_SAMPLE_DENS
+#define RANK_SAMPLE_DENS 32
+#endif
+
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+//! Performs random accesses on a vector and returns the sum of the accessed elements
+/*! \param v The container.
+ * \param rands Vector of locations which should be accessed. Length is a power of 2.
+ * Can be generated by method: util::rnd_positions<int_vector<64>>(log s, mask, v.size())
+ * \param mask Mask which is used to perform the modulo s operation. See `rands`.
+ * \param times Number of iterations. If times > rands.size() array rands will be
+ * run through several times.
+ */
+template<class t_vec>
+uint64_t test_random_access(const t_vec& v, const int_vector<64>& rands, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += v[rands[ i&mask ]];
+ }
+ return cnt;
+}
+
+template<class t_vec>
+uint64_t test_inv_random_access(const t_vec& v, const int_vector<64>& rands, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += v(rands[ i&mask ]);
+ }
+ return cnt;
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3) {
+ cout << "Usage: " << argv[0] << " bit_vector_file" << endl;
+ cout << " generates a rrr_vector<" << BLOCK_SIZE << "> with sample rate " << RANK_SAMPLE_DENS << endl;
+ cout << " for the bitvector stored in bit_vector_file and run a benchmark" << endl;
+ return 1;
+ }
+
+ typedef rrr_vector<BLOCK_SIZE, int_vector<>, RANK_SAMPLE_DENS> rrr_vec_type;
+ typedef rrr_vec_type::select_1_type rrr_select_type;
+ typedef rrr_vec_type::rank_1_type rrr_rank_type;
+ bit_vector bv;
+ if (load_from_file(bv, argv[1])) {
+ cout << "# plain_size = " << size_in_bytes(bv) << endl;
+ uint16_t k = atoi(argv[2]);
+ auto start = timer::now();
+ rrr_vec_type rrr_vector(bv);
+ util::clear(bv);
+ rrr_select_type rrr_sel(&rrr_vector);
+ rrr_rank_type rrr_rank(&rrr_vector);
+ auto stop = timer::now();
+ cout << "# construct_time = " << duration_cast<milliseconds>(stop-start).count() << endl;
+ rrr_vec_type::size_type args = rrr_rank(rrr_vector.size());
+ cout << "# rrr_vector.size() = " << rrr_vector.size() << endl;
+ cout << "# args = " << args << endl;
+ cout << "# file_name = " << argv[1] << endl;
+ cout << "# block_size = " << BLOCK_SIZE << endl;
+ cout << "# sample_rate = "<< k << endl;
+ cout << "# rrr_size = " << size_in_bytes(rrr_vector) << endl;
+ cout << "# bt_size = " << size_in_bytes(rrr_vector.bt) << endl;
+ cout << "# btnr_size = " << size_in_bytes(rrr_vector.btnr) << endl;
+ const uint64_t reps = 10000000;
+ uint64_t mask = 0;
+ uint64_t check = 0;
+ int_vector<64> rands = util::rnd_positions<int_vector<64>>(20, mask, rrr_vector.size(), 17);
+ start = timer::now();
+ check = test_random_access(rrr_vector, rands, mask, reps);
+ stop = timer::now();
+ cout << "# access_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# access_check = " << check << endl;
+ rands = util::rnd_positions<int_vector<64>>(20, mask, rrr_vector.size()+1, 17);
+ start = timer::now();
+ check = test_inv_random_access(rrr_rank, rands, mask, reps);
+ stop = timer::now();
+ cout << "# rank_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# rank_check = " << check << endl;
+ rands = util::rnd_positions<int_vector<64>>(20, mask, args, 17);
+ for (uint64_t i=0; i<rands.size(); ++i) rands[i] = rands[i]+1;
+ stop = timer::now();
+ check = test_inv_random_access(rrr_sel, rands, mask, reps);
+ stop = timer::now();
+ cout << "# select_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# select_check = " << check << endl;
+ }
+}
diff --git a/benchmark/rrr_vector/test_case.config b/benchmark/rrr_vector/test_case.config
new file mode 100644
index 0000000..96249a9
--- /dev/null
+++ b/benchmark/rrr_vector/test_case.config
@@ -0,0 +1,10 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if not generated automatically, like rnd_X.Y)
+RND50-16M;../data/rnd_50.16MB;rnd-50.16M;
+WT-DNA-16MB;../data/WT-DNA-16MB;wt-dna.16M;http://people.eng.unimelb.edu.au/sgog/data/WT-DNA-16MB.gz
+WT-WEB-16MB;../data/WT-WEB-16MB;wt-web.16M;http://people.eng.unimelb.edu.au/sgog/data/WT-WEB-16MB.gz
+WT-DNA-1GB;../data/WT-DNA-1GB;wt-dna.1G;http://people.eng.unimelb.edu.au/sgog/data/WT-DNA-1GB.gz
+WT-WEB-1GB;../data/WT-WEB-1GB;wt-web.1G;http://people.eng.unimelb.edu.au/sgog/data/WT-WEB-1GB.gz
diff --git a/benchmark/rrr_vector/visualize/.gitignore b/benchmark/rrr_vector/visualize/.gitignore
new file mode 100644
index 0000000..6726336
--- /dev/null
+++ b/benchmark/rrr_vector/visualize/.gitignore
@@ -0,0 +1,6 @@
+*
+!.gitignore
+!Makefile
+!rrr-footer.tex
+!rrr-header.tex
+!rrr.R
diff --git a/benchmark/rrr_vector/visualize/Makefile b/benchmark/rrr_vector/visualize/Makefile
new file mode 100644
index 0000000..77511ed
--- /dev/null
+++ b/benchmark/rrr_vector/visualize/Makefile
@@ -0,0 +1,17 @@
+include ../../../Make.helper
+
+CONFIG_FILES= ../test_case.config
+
+all: rrr.pdf
+
+rrr.pdf: rrr.tex
+ @echo "Use pdflatex to generate rrr.pdf"
+ @pdflatex rrr.tex >> LaTeX.Log 2>&1
+
+rrr.tex: ../results/all.txt ../../basic_functions.R rrr.R $(CONFIG_FILES)
+ @echo "Use R to generate rrr.tex"
+ @R --vanilla < rrr.R > R.log 2>&1
+
+clean:
+ rm -f rrr.pdf rrr.aux rrr.tex fig-rrr* \
+ rrr.log R.log LaTeX.log
diff --git a/benchmark/rrr_vector/visualize/rrr-footer.tex b/benchmark/rrr_vector/visualize/rrr-footer.tex
new file mode 100644
index 0000000..6b47932
--- /dev/null
+++ b/benchmark/rrr_vector/visualize/rrr-footer.tex
@@ -0,0 +1 @@
+\end{document}
diff --git a/benchmark/rrr_vector/visualize/rrr-header.tex b/benchmark/rrr_vector/visualize/rrr-header.tex
new file mode 100644
index 0000000..3b014e8
--- /dev/null
+++ b/benchmark/rrr_vector/visualize/rrr-header.tex
@@ -0,0 +1,6 @@
+\documentclass[9pt,a4paper]{scrartcl}
+\usepackage{tikz}
+
+\begin{document}
+
+\pagestyle{empty}
diff --git a/benchmark/rrr_vector/visualize/rrr.R b/benchmark/rrr_vector/visualize/rrr.R
new file mode 100644
index 0000000..2f1e151
--- /dev/null
+++ b/benchmark/rrr_vector/visualize/rrr.R
@@ -0,0 +1,171 @@
+require(tikzDevice)
+source("../../basic_functions.R")
+
+tex_file = "rrr.tex"
+
+# Load experiment information
+tc_config <- readConfig("../test_case.config",c("TC_ID","PATH","LATEX-NAME","URL"))
+compile_config <- readConfig("../compile_options.config",c("COMPILE_ID","OPTIONS"))
+
+open_tikz <- function( file_name ){
+ tikz(file_name, width = 5.5, height = 6, standAlone = F)
+}
+
+# Method which plots the space figure
+plot_rrr_space <- function(data, max_y, title="", yaxis=T, xaxis=T, color){
+ data <- data[order(data[['K']]), ]
+ plot(c(), c(), ylim = c(0, max_y), xlim = c(min(data[['K']])-1, max(data[['K']])+1),
+ yaxt = "n", ylab = "", xlab="", xaxt="n")
+
+ if ( yaxis ){
+ axis( 2, at = axTicks(2) , cex.axis=0.8)
+ mtext("Space in (\\%) of original bitvector", side=2, line=2, las=0)
+ }
+ xticks <- c(8, 16, 32, 64, 126, 256)
+ xlabel <- NA
+ if ( xaxis ){
+ xlabel <- c("8","","32","64","128","256")
+ mtext("Block size K", side=1, line=2, las=0)
+ }
+ axis( 1, at = xticks, label=xlabel, cex.axis=0.8)
+ hty =1
+ hcol = "lightgray"
+ abline( v=c(8, 16, 32, 64, 128, 256), col=hcol )
+ abline( h=axTicks(2), col=hcol )
+ total_space <- 100*data[['rrr_size']]/data[['plain_size']][1]
+ space_without_C <- 100*(data[['rrr_size']]-data[['bt_size']])/data[['plain_size']][1]
+ space_only_samples <- 100*(data[['rrr_size']]-data[['bt_size']]-data[['btnr_size']])/data[['plain_size']][1]
+
+ polygon( x_for_polygon( data[['K']] ), y_for_polygon( total_space ), border=NA, col=color[1])
+ polygon( x_for_polygon( data[['K']] ), y_for_polygon( space_without_C), border=NA, col=color[2])
+ polygon( x_for_polygon( data[['K']] ), y_for_polygon( space_only_samples ), border=NA, col=color[3])
+ lines( data[['K']], total_space )
+ lines( data[['K']], space_without_C )
+ lines( data[['K']], space_only_samples )
+ draw_figure_heading(sprintf("bitvector = %s",title))
+}
+
+# Method which plots the query time figure
+plot_rrr_query_times <- function( data, max_y=NA, title="", yaxis=T, xaxis=T){
+ cat(title,"\n")
+ data <- aggregate(data[c('access_time','rank_time','select_time')], by=c(data['K']), FUN=min)
+ data[c('access_time','rank_time','select_time')] <- data[c('access_time','rank_time','select_time')]/1000.0
+ data <- data[order(data[['K']]), ]
+
+ max_runtime <- max( data[['access_time']], data[['rank_time']], data[['select_time']])
+ if ( !is.na(max_y) ){
+ max_runtime = max_y
+ }
+
+ plot(data[['K']], data[['access_time']], type="l", ylim=c(0, max_runtime ),
+ xlab = "", ylab="", yaxt="n", cex.axis = 0.8, xaxt="n",
+ col = terrain.colors(6)[1], lwd=1.5
+ )
+ box("plot", col="grey")
+ axis( 1, at = axTicks(1), labels=xaxis, mgp=c(2,0.5,0), tcl=-0.2, cex.axis=1, las=1 )
+ if ( xaxis ){
+ xlable <- "Block size K"
+ mtext(xlable, side=1, line=2, las=0)
+ }
+ if ( yaxis ){
+ axis( 2, at = axTicks(2), mgp=c(1,0.3,0), tcl=-0.2, cex.axis=0.8 )
+ mtext("Time per operation in ($\\mu s$)", side=2, line=2, las=0)
+ }
+ grid(lty=1)
+ lines( data[['K']], data[['rank_time']], lty=1, col=terrain.colors(6)[3], lwd=1.5)
+ lines( data[['K']], data[['select_time']], lty=1, col=terrain.colors(6)[5], lwd=1.5)
+
+ draw_figure_heading(sprintf("bitvector = %s",title))
+}
+
+data <- data_frame_from_key_value_pairs( "../results/all.txt" )
+
+tex_doc <- paste(readLines("rrr-header.tex"),collapse="\n")
+
+for ( compile_id in compile_config[["COMPILE_ID"]] ){
+# Handle query time
+ fig_name <- paste("fig-rrr-time-",compile_id,".tex",sep="")
+ open_tikz( fig_name )
+ n <- nrow(tc_config)
+ d <- subset(data, data[["COMPILE_ID"]]==compile_id)
+ par(mfrow=c(n/2+1,2))
+ multi_figure_style( n/2+1, 2 )
+ nr <- 0
+ xlabnr <- 2*(n/2)-2+1
+ for ( tc_id in tc_config[["TC_ID"]] ){
+ dd <- subset(d, d[["TC_ID"]]==tc_id)
+ plot_rrr_query_times(dd, 2.1,
+ title=tc_config[tc_id,"LATEX-NAME"],
+ yaxis=(nr%%2==0), xaxis=(nr>=xlabnr) )
+ if ( nr == 0 ){
+ plot(NA, NA, xlim=c(0,1),ylim=c(0,1),ylab="", xlab="", bty="n", type="n", yaxt="n", xaxt="n")
+ legend("topleft", legend=rev(c("access","rank","select")), box.lwd=0, lty=rev(c(1,1,1)),
+ title="Operation", col=rev(terrain.colors(6)[seq(1,5,2)]), bg="white", cex=1.5)
+ nr <- nr+1
+ }
+ nr <-nr+1
+ }
+ dev.off()
+ tex_doc <- paste(tex_doc,"\\begin{figure}
+ \\input{",fig_name,"}
+ \\caption{Runtime of \\texttt{rrr\\_vector} dependent on block size K.
+ Compile options:
+ \\texttt{",gsub("_","\\\\_",compile_config[compile_id, "OPTIONS"]),"}.
+ }
+ \\end{figure}")
+}
+
+# Handle space
+fig_name <- "fig-rrr-space.tex"
+open_tikz( fig_name )
+n <- nrow(tc_config)
+d <- subset(data, data[["COMPILE_ID"]]==compile_config[1,1])
+max_size <- 100*max(d[["rrr_size"]]/d[["plain_size"]])
+
+multi_figure_style( n/2+1, 2 )
+
+nr <- 0
+xlabnr <- 2*(n/2)-2+1
+colors = c('gray80','gray50','gray30')
+for ( tc_id in tc_config[["TC_ID"]] ){
+ dd <- subset(d, d[["TC_ID"]]==tc_id)
+ plot_rrr_space(dd, max_size, title=tc_config[tc_id,"LATEX-NAME"],
+ yaxis=(nr%%2==0), xaxis=(nr>=xlabnr), color=colors)
+ if ( nr == 0 ){
+ plot(NA, NA, xlim=c(0,1),ylim=c(0,1),ylab="", xlab="", bty="n", type="n", yaxt="n", xaxt="n")
+ legend_text <- rev(c('pointers/samples','encoded block','block type'))
+ legend( "top", legend=legend_text, fill=colors, bg="white", box.col="white", title="Space of",cex=1.5 )
+ nr <- nr+1
+ }
+ nr <-nr+1
+}
+dev.off()
+tex_doc <- paste(tex_doc,"\\begin{figure}
+ \\input{",fig_name,"}
+ \\caption{Space of \\texttt{rrr\\_vector} dependent on block size K.}.
+ \\end{figure}")
+
+
+tex_doc <- paste(tex_doc, readLines("rrr-footer.tex"),collapse="\n")
+sink(tex_file)
+cat(tex_doc)
+sink(NULL)
+
+## Method which plots the construction time figure
+#plot_rrr_construction_times <- function( file_name, max_y=NA, draw_legend=T, title=""){
+# data <- data_frame_from_key_value_pairs( file_name )
+#
+# data <- aggregate(data['construct_time'], by=c(data['K']), FUN=min)
+# data <- data[order(data[['K']]), ]
+#
+# max_runtime <- max(data[['construct_time']])/1000
+# if ( !is.na(max_y) ){
+# max_runtime = max_y
+# }
+# plot(data[['K']], data[['construct_time']]/1000,
+# type="l", ylab="construction time in seconds",
+# xlab="Block size R", ylim=c(0, max_runtime ))
+# title( main=title, line=0 )
+#}
+#
+
diff --git a/benchmark/self_delimiting_codes/Makefile b/benchmark/self_delimiting_codes/Makefile
new file mode 100644
index 0000000..8111af6
--- /dev/null
+++ b/benchmark/self_delimiting_codes/Makefile
@@ -0,0 +1,67 @@
+include ../../Make.helper
+SRC_DIR = src
+BIN_DIR = bin
+LIBS = -lsdsl
+RES_FILE = results/result.csv #result file of benchmark
+VAT_FILE = results/vat.csv #vector assignment table (vector name -> sdsl type)
+TC_FILE = results/tc.csv #test case table (contains only test case names)
+
+#utility
+empty:=
+space:= $(empty) $(empty)
+comma:= ,
+
+#load test cases
+TC_IDS := $(call config_ids,test_case.config)
+TC_FILES := $(foreach TC_ID,$(TC_IDS),\
+ $(call config_select,test_case.config,$(TC_ID),2))
+
+all: $(RES_FILE)
+
+timing: $(RES_FILE)
+ @cd visualize;make
+
+
+#compilation and creation of vector assignment table
+$(BIN_DIR)/sdcbenchmark: $(SRC_DIR)/sdc_benchmark.cpp vectors.config compile_options.config
+ $(eval VTYPES := $(subst $(space),$(comma),$(strip $(call config_column,vectors.config,2))))
+ $(eval VNAMES := $(subst $(space),\"$(comma)\",$(strip $(call config_column,vectors.config,3))))
+ $(eval VNAMES := $(addprefix {\",$(VNAMES)))
+ $(eval VNAMES := $(addsuffix \"},$(VNAMES)))
+ $(eval C_OPTIONS:=$(call config_ids,compile_options.config))
+ @echo "Compiling build for vectors $(VNAMES)"
+ @$(MY_CXX) $(MY_CXX_FLAGS) $(C_OPTIONS) -DVTYPES="$(VTYPES)" -DVNAMES="$(VNAMES)" -L$(LIB_DIR)\
+ "$(SRC_DIR)/sdc_benchmark.cpp" -I$(INC_DIR) -o "$(BIN_DIR)/sdcbenchmark" $(LIBS)
+ $(eval V_IDS := $(call config_ids,vectors.config))
+ $(eval V_ASSIGNMENTTABLE := $(subst $(space),\n,$(strip $(foreach V_ID,$(V_IDS),\
+ $(call config_select,vectors.config,$(V_ID),3);$(call config_select,vectors.config,$(V_ID),2)))))
+ @echo "Writing Vector Assignment Table"
+ @echo "vector;sdsltype" > $(VAT_FILE)
+ @echo "$(V_ASSIGNMENTTABLE)" >> $(VAT_FILE)
+
+
+#execution and creation of test case table
+$(RES_FILE): test_case.config $(TC_FILES) $(BIN_DIR)/sdcbenchmark
+ $(eval ARGS := $(foreach TC_ID,$(TC_IDS),\
+ $(call config_select,test_case.config,$(TC_ID),3) $(space) \
+ $(call config_select,test_case.config,$(TC_ID),2) $(space) \
+ $(call config_select,test_case.config,$(TC_ID),5) ) )
+ @echo "Executing Benchmark"
+ @$(BIN_DIR)/sdcbenchmark $(ARGS) | tee $(RES_FILE)
+ $(eval TC_TABLE := $(subst $(space),\n,$(strip $(call config_column,test_case.config,3))))
+ @echo "Writing Test Case file"
+ @echo "testcase\\nOverall" > $(TC_FILE)
+ @echo "$(TC_TABLE)" >> $(TC_FILE)
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ rm -f $(BIN_DIR)/sdcbenchmark
+
+clean-result:
+ @echo "Remove results"
+ rm -f results/*
+
+cleanall: clean-build clean-result
+ @cd visualize;make cleanall
diff --git a/benchmark/self_delimiting_codes/README.md b/benchmark/self_delimiting_codes/README.md
new file mode 100644
index 0000000..cbe8c37
--- /dev/null
+++ b/benchmark/self_delimiting_codes/README.md
@@ -0,0 +1,55 @@
+# Benchmarking wavelet trees
+
+## Methodology
+
+Explored dimensions:
+
+ * self - delimiting code implementations
+ * test cases
+ * methods (`encoding`, `decoding`)
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains LaTex files and a makefile for generating a report
+
+## Prerequisites
+
+ * To run the test on larger test cases (>= 200 MB), you should have at least 2 GB
+ of free memory (some vectors have very poor compression).
+ * For the visualization you need the following software:
+ - [pdflatex][LT] to generate the pdf reports.
+ - [pgfplots][PGFP] installed in [LT] to generate plots in pdf reports.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads or generates
+ the test instances, builds the compression vectors,
+ runs the performance tests and generated a report located at
+ `visualize/self_delimiting_codes.pdf`. The raw numbers of the encoding / decoding
+ rates and compression can be found in the file `results/result.csv`.
+ The used test cases can be found in file `results/tc.csv`.
+ The tested vectors can be found in file `results/vat.csv`.
+ The default benchmark took 14 minutes on my machine (Asus P50IJ
+ Pentium(R) Dual-Core CPU T4500 @ 2.30GHz 2GB).
+ * All created binaries and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+
+The project contains several configuration files:
+
+ * [vectors.config][VCONFIG]: Specify different compression vectors and their used coders.
+ * [test_case.config][TCCONFIG]: Specify test instances by ID, path, LaTeX-name
+ for the report, and download URL.
+ * [compile_options.config][CCONFIG]: Specify compile options by option string.
+
+Note that the benchmark will execute every combination of vectors and test cases.
+
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[PGFP]: http://www.ctan.org/pkg/pgfplots "pgfplots"
+[VCONFIG]: ./vectors.config "vectors.config"
+[TCCONFIG]: ./test_case.config "test_case.config"
+[CCONFIG]: ./compile_options.config "compile_options.config"
diff --git a/benchmark/self_delimiting_codes/bin/.gitignore b/benchmark/self_delimiting_codes/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/self_delimiting_codes/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/self_delimiting_codes/compile_options.config b/benchmark/self_delimiting_codes/compile_options.config
new file mode 100644
index 0000000..cebc3e9
--- /dev/null
+++ b/benchmark/self_delimiting_codes/compile_options.config
@@ -0,0 +1,2 @@
+# Compile options
+-O3 -funroll-loops -fomit-frame-pointer -ffast-math -DNDEBUG
diff --git a/benchmark/self_delimiting_codes/results/.gitignore b/benchmark/self_delimiting_codes/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/self_delimiting_codes/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/self_delimiting_codes/src/sdc_benchmark.cpp b/benchmark/self_delimiting_codes/src/sdc_benchmark.cpp
new file mode 100644
index 0000000..e28bbd0
--- /dev/null
+++ b/benchmark/self_delimiting_codes/src/sdc_benchmark.cpp
@@ -0,0 +1,239 @@
+#include <iostream>
+#include <limits>
+#include <sdsl/vectors.hpp>
+#include <sdsl/coder.hpp>
+
+/**** Benchmark for self - delimiting codes ***********************************
+For information about usage of this benchmark, see displayUsage - function.
+
+To compile this benchmark, the following macros have to be defined
+(e.g. by passing them to compiler):
+- VTYPES: a comma - separated list of sdsl vector types to be testet,
+ e.g. vlc_vector<coder::elias_gamma>,vlc_vector<coder::elias_delta>
+- VNAMES: symbolic names of the corresponding vector types, in same order
+ as in macro VTYPES, defined as a character array.
+ According to the upper sample on macro VTYPES, VNAMES could be defined as
+ {"VLC Vector with Elias Gamma Coder","VLC Vector with Elias Delta Coder"}
+*/
+
+
+//assert that needed macros are defined
+#ifndef VTYPES
+#error "Macro VTYPES with comma - separated list of vector types has to be \
+ defined for compiling benchmark"
+#endif
+
+#ifndef VNAMES
+#error "Macro VNAMES with an array of characters has to be \
+ defined for compiling benchmark"
+#endif
+
+using namespace std;
+using namespace sdsl;
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+const char *(vectornames[]) = VNAMES;
+const size_t vectorcount = sizeof(vectornames) / sizeof(vectornames[0]);
+
+struct iv_testresult { //testcase for one defined int vector
+ double enc_MBperSec; //encoding rate: megabytes per second
+ double dec_MBperSec; //decoding rate: megabytes per second
+ double comp_percent; //compression rate: needed space in percentage compared
+ //to original integer vector
+};
+
+//benchmark method declaration
+template<class... Vectors> //used vectors for benchmark
+bool runTestcase( const int_vector<> &iv, iv_testresult *result );
+
+//stuff for nice printing
+void displayUsage(const char *pname);
+void displayHeading();
+void displayResult( const char *testcase, const iv_testresult *result );
+
+int main(const int argc, const char **argv)
+{
+ //check args
+ if ((argc - 1) % 3 != 0) {
+ displayUsage(argv[0]);
+ return 1;
+ }
+
+ //set up needed structures
+ const size_t testcasecount = (argc - 1) / 3;
+ iv_testresult overallresult[vectorcount];
+
+ //prepare overall result
+ for (size_t i = 0; i < vectorcount; i++) {
+ overallresult[i].enc_MBperSec = 0.0;
+ overallresult[i].dec_MBperSec = 0.0;
+ overallresult[i].comp_percent = 0.0;
+ }
+
+ //start fetching test cases and run benchmark
+ displayHeading();
+ for (size_t i = 0; i < testcasecount; i++) {
+ const char *testcase = argv[3*i + 1];
+ const char *file = argv[3*i + 2]; //file of saved vector
+ const char *type = argv[3*i + 3]; //type of saved vector
+ uint8_t v_type = type[0]=='d' ? 'd' : type[0] - '0';
+
+ //load vector
+ int_vector<> iv;
+ if (!load_vector_from_file(iv, file, v_type)) {
+ cerr << "ERROR: vector from file " << file
+ << " with type " << type << " could not be loaded"
+ << endl;
+ displayUsage(argv[0]);
+ return 1;
+ }
+
+ //run test
+ iv_testresult result[vectorcount];
+ if (!runTestcase<VTYPES>( iv, result )) {
+ cerr << "Testcase " << testcase << "failed" << endl;
+ return 1;
+ }
+
+ //print result
+ displayResult( testcase, result );
+
+ //and sum up results for overall result
+ for (size_t j = 0; j < vectorcount; j++) {
+ overallresult[j].enc_MBperSec += result[j].enc_MBperSec;
+ overallresult[j].dec_MBperSec += result[j].dec_MBperSec;
+ overallresult[j].comp_percent += result[j].comp_percent;
+ }
+ }
+
+ //build average for overall result
+ for (size_t i = 0; i < vectorcount; i++) {
+ overallresult[i].enc_MBperSec /= testcasecount;
+ overallresult[i].dec_MBperSec /= testcasecount;
+ overallresult[i].comp_percent /= testcasecount;
+ }
+
+ //and display overall results
+ displayResult( "Overall", overallresult );
+ return 0;
+}
+
+//// BENCHMARK METHODS ////////////////////////////////////////////////////////
+template<class Vector> //used compression vector type
+bool runSingleTest( const int_vector<> &testcase, iv_testresult &result ) {
+ //test encoding rate by constructing Vector
+ auto start = timer::now();
+ Vector test( testcase );
+ auto stop = timer::now();
+ result.enc_MBperSec = size_in_mega_bytes( testcase )
+ / duration_cast<seconds>(stop-start).count();
+
+ //care for compression rate
+ result.comp_percent = size_in_mega_bytes(test)
+ / size_in_mega_bytes(testcase) * 100.0;
+
+ //and finally for decoding rate
+ //use a trick to decode all values: since (currently) all vectors are
+ //using sample tables, access the element right before the next sampling
+ //entry, so everything between 2 samples has to be decoded.
+ size_t sample_dens = test.get_sample_dens();
+ start = timer::now();
+ //repeat test 5 times to avoid infinite decoding rates
+ for (size_t j = 0; j < 5; j++) {
+ size_t i = sample_dens - 1;
+ for (; i < test.size(); i += sample_dens) {
+ test[i]; //acess element right before next sample entry
+ }
+ //and finally access last element if not done yet
+ if (i != test.size() + sample_dens - 1)
+ test[test.size() - 1];
+ }
+ stop = timer::now();
+ result.dec_MBperSec = size_in_mega_bytes( testcase )
+ / duration_cast<seconds>(stop-start).count()
+ * 5.0; //multiply with 5 since vector was decoded 5 times
+
+ return true; //may use this return type for error detection in future
+}
+
+template<class... Vectors> //used vectors for benchmark
+bool runTestcase( const int_vector<> &testcase, iv_testresult *result ) {
+ size_t i = 0;
+ //do variadic template pack expansion
+ bool testfine[] = { runSingleTest<Vectors>( testcase, result[i++] )... };
+ bool testsfine = true;
+ for (i = 0; i < vectorcount; i++) {
+ if (!testfine[i]) {
+ cerr << "Test on Vector " << vectornames[i]
+ << "failed" << endl;
+ testsfine = false;
+ }
+ }
+ return testsfine;
+}
+
+//// DISPLAYING OF RESULTS ////////////////////////////////////////////////////
+
+void displayUsage(const char *pname) {
+ cerr << "USAGE: " << pname << " [testcase file vectortype]*"
+ << endl;
+ cerr << "DESCRIPTION:" << endl;
+ cerr << "\tThis Program runs a benchmark on self-delimiting "
+ << "Codes." << endl;
+ cerr << "\tProgram needs triples of parameters "
+ << "for each test case, see Parameter section." << endl;
+ cerr << "\tProgram will test a couple of compression vectors "
+ << endl
+ << "\ton measured encoding and decoding rates," << endl
+ << "\tplus the compression rate in percent "
+ << "(compared to the original integer vector)" << endl
+ << "\tfor each testcase."
+ << endl
+ << "\tAdditionally, an overall result on different "
+ << endl << "\tcompression vectors is printed." << endl;
+ cerr << "\tThe generated output uses a CSV format, so "
+ << "you may save it to a csv file for better visability"
+ << endl << "\tand other utilites." << endl;
+ cerr << "PARAMETERS: The parameters have to be passed as "
+ << " triples for each test case." << endl
+ << "\tA Triple consist of " << endl
+ << "\t\t- testcase: A name for the test case" << endl
+ << "\t\t- file: a path to the file where the test case" << endl
+ << "\t\t\t(an integer vector) is contained" << endl
+ << "\t\t- vectortype: type of saved integer vector" << endl
+ << "\t\t\t0: serialized int_vector<>" << endl
+ << "\t\t\t1: byte sequence" << endl
+ << "\t\t\t2: 16-bit word sequence" << endl
+ << "\t\t\t4: 32-bit word sequence" << endl
+ << "\t\t\t8: 64-bit word sequence" << endl
+ << "\t\t\td: Parse decimal numbers" << endl;
+ cerr << "TESTET COMPRESSION VECTORS:" << endl;
+ for (size_t i = 0; i < vectorcount; i++) {
+ cerr << "\t- " << vectornames[i] << endl;
+ }
+}
+void displayHeading() {
+ cout << left; //left justify
+ //add a comment how to read values
+ cout << "# encoding / decoding rate unit: MB/s" << endl;
+ cout << "# compression : percentage of needed space "
+ << " compared to original vector" << endl;
+ //and print a header for csv output
+ cout << setw(20) << "testcase"
+ << setw(1) << ";" << setw(20) << "vector"
+ << setw(1) << ";" << setw(20) << "encodingrate"
+ << setw(1) << ";" << setw(20) << "decodingrate"
+ << setw(1) << ";" << "compressionrate" << endl;
+}
+
+void displayResult( const char *testcase, const iv_testresult *result ) {
+ cout << left << fixed; //prepare cout
+ for (size_t i = 0; i < vectorcount; i++) {
+ cout << setw(20) << testcase
+ << setw(1) << ";" << setw(20) << vectornames[i]
+ << setw(1) << ";" << setw(20) << result[i].enc_MBperSec
+ << setw(1) << ";" << setw(20) << result[i].dec_MBperSec
+ << setw(1) << ";" << result[i].comp_percent << endl;
+ }
+}
diff --git a/benchmark/self_delimiting_codes/test_case.config b/benchmark/self_delimiting_codes/test_case.config
new file mode 100644
index 0000000..9f759a8
--- /dev/null
+++ b/benchmark/self_delimiting_codes/test_case.config
@@ -0,0 +1,19 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+# (5) Test file type(0: serialized int_vector<>, 1: byte sequence, 2: 16-bit word sequence, 4: 32-bit word sequence, 8: 64-bit word sequence, d: Parse decimal numbers)
+
+#ENGLISH;../data/english.200MB;english.200MB;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz;1
+#DBLPXML;../data/dblp.xml.200MB;dblp.xml.200MB;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz;1
+#DNA;../data/dna.200MB;dna.200MB;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz;1
+#PROTEINS;../data/proteins.200MB;proteins.200MB;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz;1
+#SOURCES;../data/sources.200MB;sources.200MB;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz;1
+INFLUENZA;../data/influenza;influenza;http://pizzachili.dcc.uchile.cl/repcorpus/real/influenza.gz;1
+EINSTEIN-de;../data/einstein.de.txt;einstein-de;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.de.txt.gz;1
+#EINSTEIN-en;../data/einstein.en.txt;einstein-en;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.en.txt.gz;1
+#PARA;../data/para;para;http://pizzachili.dcc.uchile.cl/repcorpus/real/para.gz;1
+WORLDLEADER;../data/world_leaders;world-leaders;http://pizzachili.dcc.uchile.cl/repcorpus/real/world_leaders.gz;1
+#E_COLI;../data/Escherichia_Coli;E.coli;http://pizzachili.dcc.uchile.cl/repcorpus/real/Escherichia_Coli.gz;1
+#ENWIKISMLINT;../data/enwiki-20130805-pages-articles1.int.sdsl;enwiki-sml-int;http://people.eng.unimelb.edu.au/sgog/data/enwiki-20130805-pages-articles1.int.sdsl.gz;0
diff --git a/benchmark/self_delimiting_codes/vectors.config b/benchmark/self_delimiting_codes/vectors.config
new file mode 100644
index 0000000..f1b53cc
--- /dev/null
+++ b/benchmark/self_delimiting_codes/vectors.config
@@ -0,0 +1,18 @@
+# This file specifies integer vectors that are used in the benchmark.
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Integer Vector sdsl-type (no whitespaces)
+# (3) LaTeX name of testet Vector (no whitespaces)
+# VLC Vectors
+VLC_EG;vlc_vector<coder::elias_gamma>;VLC-Elias-Gamma
+VLC_ED;vlc_vector<coder::elias_delta>;VLC-Elias-Delta
+VLC_FIB;vlc_vector<coder::fibonacci>;VLC-Fibonacci
+VLC_C2;vlc_vector<coder::comma<2>>;VLC-Comma-Base3
+#VLC_C3;vlc_vector<coder::comma<3>>;VLC-Comma-Base7
+#VLC_C8;vlc_vector<coder::comma<8>>;VLC-Comma-Base254
+# ENC Vectors
+ENC_EG;enc_vector<coder::elias_gamma>;ENC-Elias-Gamma
+ENC_ED;enc_vector<coder::elias_delta>;ENC-Elias-Delta
+ENC_FIB;enc_vector<coder::fibonacci>;ENC-Fibonacci
+ENC_C2;enc_vector<coder::comma<2>>;ENC-Comma-Base3
+#ENC_C3;enc_vector<coder::comma<3>>;ENC-Comma-Base7
+#ENC_C8;enc_vector<coder::comma<8>>;ENC-Comma-Base254
diff --git a/benchmark/self_delimiting_codes/visualize/Makefile b/benchmark/self_delimiting_codes/visualize/Makefile
new file mode 100644
index 0000000..a0d3aa7
--- /dev/null
+++ b/benchmark/self_delimiting_codes/visualize/Makefile
@@ -0,0 +1,31 @@
+# Makefile will also automatically generate a tex file with system information
+
+#utility
+empty:=
+space:= $(empty) $(empty)
+
+auto: self_delimiting_codes.pdf
+
+self_delimiting_codes.pdf: ../results/result.csv ../results/tc.csv ../results/vat.csv
+ $(eval CPUINFO := $(strip $(patsubst \\%, $(space),\
+ $(shell cat /proc/cpuinfo | grep "model name.*" | uniq | cut -d':' -f 2))))
+ $(eval MEMINFO := $(strip \
+ $(firstword $(shell free -k | grep "Mem.*" | uniq | cut -d':' -f 2))))
+ $(eval MEMINFO := $(addsuffix " KB", $(MEMINFO)))
+ $(eval DISTINFO := $(strip $(patsubst \\%, $(space),\
+ $(shell cat /etc/issue))))
+ @echo "Creating system information file"
+ @echo "\\\\begin{tabular}{ll}" > sysinfo.tex
+ @echo "\\\\toprule" >> sysinfo.tex
+ @echo "CPU & \\\\verb\\\\$(CPUINFO)\\\\ \\\\\\\\" >> sysinfo.tex
+ @echo "Total Memory & \\\\verb\\\\$(MEMINFO)\\\\ \\\\\\\\" >> sysinfo.tex
+ @echo "Distribution & \\\\verb\\\\$(DISTINFO)\\\\ \\\\\\\\" >> sysinfo.tex
+ @echo "\\\\bottomrule" >> sysinfo.tex
+ @echo "\\\\end{tabular}" >> sysinfo.tex
+ @echo "Use pdflatex to generate self_delimiting_codes.pdf"
+ @pdflatex self_delimiting_codes.tex >> LaTeX.log 2>&1
+
+cleanall:
+ rm -f self_delimiting_codes.pdf self_delimiting_codes.aux \
+ self_delimiting_codes.log LaTeX.log sysinfo.tex
+
diff --git a/benchmark/self_delimiting_codes/visualize/self_delimiting_codes.tex b/benchmark/self_delimiting_codes/visualize/self_delimiting_codes.tex
new file mode 100644
index 0000000..daa2fe2
--- /dev/null
+++ b/benchmark/self_delimiting_codes/visualize/self_delimiting_codes.tex
@@ -0,0 +1,91 @@
+\documentclass{article}
+
+\usepackage{pgfplots}
+\usepackage{pgfplotstable}
+\usepackage{booktabs}
+\usepackage[section]{placeins}
+\pgfplotsset{compat=1.10}
+
+%load necessary data from result and configuration files
+\pgfplotstableread[col sep=semicolon,trim cells]{../results/tc.csv}\testcasetable
+\pgfplotstableread[col sep=semicolon,trim cells]{../results/vat.csv}\vectortable
+
+%some pgf macros and setups
+\pgfplotsset{
+ discard if not/.style 2 args={
+ x filter/.code={
+ \edef\tempa{\thisrow{#1}}
+ \edef\tempb{#2}
+ \ifx\tempa\tempb
+ \else
+ \def\pgfmathresult{inf}
+ \fi
+ }
+ },
+ small
+}
+\pgfkeys{/pgf/number format/.cd,fixed,precision=2}
+
+%background
+\usetikzlibrary{backgrounds}
+\definecolor{graphicbackground}{rgb}{0.96,0.96,0.8}
+\pgfkeys{/tikz/.cd,
+ background color/.initial=graphicbackground,
+ background color/.get=\backcol,
+ background color/.store in=\backcol,
+}
+\tikzset{background rectangle/.style={
+ fill=\backcol,
+ },
+ use background/.style={
+ show background rectangle
+ }
+}
+
+\begin{document}
+\title{Self -- Delimiting Codes Benchmark}
+
+\maketitle
+
+This file contains the results of a benchmark on self delimiting codes
+using \texttt{SDSL} Library. Benchmark tested a list of integer vectors
+for encoding and decoding rates (both measured in Megabytes per second),
+and the achieved compression rate (measured in percentage, compared to
+the uncompressed integer vector) on different self -- delimiting codes
+and compression vectors.
+
+\input{testcase.tex}
+% iterate over each test case and output its result
+\pgfplotstabletypeset[
+ begin table=,
+ end table=,
+ typeset cell/.style={/pgfplots/table/@cell content={\showTestcaseResult{#1}}},
+ before row=,
+ after row=,
+ skip coltypes,
+ TeX comment=,
+ every head row/.style={output empty row},
+ string type,
+ ]{\testcasetable}
+
+%write some appendix with additional information
+\appendix
+
+\section{Vector Assignment Table}
+\pgfplotstabletypeset[columns={vector,sdsltype},
+ columns/vector/.style={column name=Vector,string type},
+ columns/sdsltype/.style={column name=SDSL Type,
+ string replace*={_}{\_},
+ assign cell content/.code={
+ \pgfkeyssetvalue{/pgfplots/table/@cell content}{\texttt{##1}}
+ }},
+ column type={ll},
+ every head row/.style={before row=\toprule,after row=\midrule},
+ every last row/.style={after row=\bottomrule},
+ row sep=\\,col sep=&
+ ]{\vectortable}
+
+\section{System Information}
+\input{sysinfo.tex}
+
+\end{document}
diff --git a/benchmark/self_delimiting_codes/visualize/testcase.tex b/benchmark/self_delimiting_codes/visualize/testcase.tex
new file mode 100644
index 0000000..675f78f
--- /dev/null
+++ b/benchmark/self_delimiting_codes/visualize/testcase.tex
@@ -0,0 +1,63 @@
+% This file declares a macro for showing the results of one test case.
+% macro expects testcase name as parameter.
+\newcommand{\showTestcaseResult}[1]{
+\section{#1 Result}
+
+%draw first picture containing coding rates
+\begin{figure}[htb]
+\begin{tikzpicture}[use background]
+\begin{axis}[
+ width=.75\textwidth,
+ xbar,
+ xmin=0,
+ xlabel= {Rate (MB/s)},
+ xmajorgrids=true,
+ enlarge x limits={value=0.2, upper},
+ y=1cm,
+ enlarge y limits={true, abs value=0.75},
+ ytick=data,
+ yticklabels from table={\vectortable}{vector},
+ y tick label style={major tick length=0pt},
+ y dir=reverse,
+ legend style={cells={anchor=east},legend pos=outer north east},
+ legend reversed=true,
+ nodes near coords,
+ nodes near coords align={horizontal}]
+\addplot[draw=black,fill=red,discard if not={testcase}{#1}] table
+ [x=decodingrate,y expr=\coordindex,col sep=semicolon,trim cells]
+ {../results/result.csv};
+\addplot[draw=black,fill=blue,discard if not={testcase}{#1}] table
+ [x=encodingrate,y expr=\coordindex,col sep=semicolon,trim cells]
+ {../results/result.csv};
+\legend{Decoding,Encoding};
+\end{axis}
+\end{tikzpicture}
+\caption{Coding Rates on Testcase #1}
+\end{figure}
+
+%and second picture containing compression rate
+\begin{figure}[htb]
+\begin{tikzpicture}[use background]
+\begin{axis}[
+ width=.75\textwidth,
+ xbar,
+ xmin=0,
+ xlabel= {Compression (in percentage)},
+ xmajorgrids=true,
+ enlarge x limits={value=0.2, upper},
+ y=0.6cm,
+ enlarge y limits={true, abs value=0.75},
+ ytick=data,
+ yticklabels from table={\vectortable}{vector},
+ y tick label style={major tick length=0pt},
+ y dir=reverse,
+ nodes near coords,
+ nodes near coords align={horizontal}]
+\addplot[draw=black,fill=green,discard if not={testcase}{#1}] table
+ [x=compressionrate,y expr=\coordindex,col sep=semicolon,trim cells]
+ {../results/result.csv};
+\end{axis}
+\end{tikzpicture}
+\caption{Compression Rate on Testcase #1}
+\end{figure}
+}
diff --git a/benchmark/tmp/.gitignore b/benchmark/tmp/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/tmp/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/wavelet_trees/Makefile b/benchmark/wavelet_trees/Makefile
new file mode 100644
index 0000000..744cf3b
--- /dev/null
+++ b/benchmark/wavelet_trees/Makefile
@@ -0,0 +1,83 @@
+include ../../Make.helper
+CFLAGS = $(MY_CXX_FLAGS)
+SRC_DIR = src
+BIN_DIR = bin
+LIBS = -lsdsl
+
+C_OPTIONS:=$(call config_ids,compile_options.config)
+TC_IDS:=$(call config_ids,test_case.config)
+WT_IDS:=$(call config_ids,wt.config)
+
+DL = $(foreach TC_ID,$(TC_IDS),\
+ $(call config_select,test_case.config,$(TC_ID),2))
+DL_BWT = $(foreach TC_ID,$(TC_IDS),../tmp/BWT.$(TC_ID))
+
+WT_EXECS = $(foreach WT_ID,$(WT_IDS),$(BIN_DIR)/build_$(WT_ID))
+
+RES_FILES = $(foreach WT_ID,$(WT_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ results/$(WT_ID).$(TC_ID)))
+
+BWT_RES_FILES = $(foreach WT_ID,$(WT_IDS),\
+ $(foreach TC_ID,$(TC_IDS),\
+ results-bwt/$(WT_ID).$(TC_ID)))
+
+RESULT_FILE=results/all.txt
+
+all: execs
+
+execs: $(WT_EXECS)
+
+timing: execs $(RES_FILES)
+ @cat $(RES_FILES) > $(RESULT_FILE)
+ @cd visualize;make
+
+../tmp/BWT.%: $(DL) $(BIN_DIR)/gen_bwt
+ $(eval TC_ID:=$*)
+ $(eval TC_PATH:=$(call config_select,test_case.config,$(TC_ID),2))
+ $(eval BWT:=$(strip $(call config_select,test_case.config,$(TC_ID),6)))
+ $(eval NUM_BYTE:=$(call config_select,test_case.config,$(TC_ID),5))
+ @$(BIN_DIR)/gen_bwt $(TC_PATH) ../tmp/BWT.$(TC_ID) ../tmp $(BWT) $(NUM_BYTE)
+
+# Execute $(BIN_DIR)/build_[WT_ID] and write result
+results/%: test_case.config $(DL) $(DL_BWT) execs
+ $(eval WT_ID:=$(call dim,1,$*))
+ $(eval TC_ID:=$(call dim,2,$*))
+ $(eval WT_TEX_NAME:=$(call config_select,wt.config,$(WT_ID),3))
+ $(eval TC_TEX_NAME:=$(call config_select,test_case.config,$(TC_ID),3))
+ $(eval BWT:=$(strip $(call config_select,test_case.config,$(TC_ID),6)))
+ $(eval TC_PATH:=$(if $(findstring BWT,$(BWT)),"../tmp/BWT.$(TC_ID)",$(call config_select,test_case.config,$(TC_ID),2)))
+ $(eval TC_TYPE:=$(call config_select,test_case.config,$(TC_ID),5))
+ $(eval TC_SIZE:=$(shell wc -c <$(TC_PATH)))
+ $(eval ARGS:=$(TC_PATH) $(TC_TYPE) $(TC_ID) $(WT_ID))
+ @echo "Running bin/build_$(WT_ID) on $(TC_ID)"
+ @echo "# WT_ID = $(WT_ID)" > $@
+ @echo "# TC_ID = $(TC_ID)" >> $@
+ @echo "# WT_TEX_NAME = $(WT_TEX_NAME)">>$@
+ @echo "# TC_TEX_NAME = $(TC_TEX_NAME)">>$@
+ @echo "# TC_SIZE = $(TC_SIZE)">>$@
+ @$(BIN_DIR)/build_$(WT_ID) $(ARGS) >> $@
+
+# $(BIN_DIR)/build_[WT_ID]
+$(BIN_DIR)/build_%: $(SRC_DIR)/wt_time_and_space.cpp wt.config
+ $(eval WT_ID:=$(call dim,1,$*))
+ $(eval WT_TYPE:=$(call config_select,wt.config,$(WT_ID),2))
+ @echo "Compiling build_$*"
+ @$(MY_CXX) $(CFLAGS) $(C_OPTIONS) -DWT_TYPE="$(WT_TYPE)" -L$(LIB_DIR)\
+ $(SRC_DIR)/wt_time_and_space.cpp -I$(INC_DIR) -o $@ $(LIBS)
+
+$(BIN_DIR)/gen_bwt: $(SRC_DIR)/gen_bwt.cpp
+ @$(MY_CXX) $(CFLAGS) $(C_OPTIONS) -L$(LIB_DIR)\
+ $(SRC_DIR)/gen_bwt.cpp -I$(INC_DIR) -o $@ $(LIBS) -ldivsufsort -ldivsufsort64
+
+include ../Make.download
+
+clean-build:
+ @echo "Remove executables"
+ rm -f $(BIN_DIR)/build*
+
+clean-result:
+ @echo "Remove results"
+ rm -f results/*
+
+cleanall: clean-build clean-result
diff --git a/benchmark/wavelet_trees/README.md b/benchmark/wavelet_trees/README.md
new file mode 100644
index 0000000..37d16bb
--- /dev/null
+++ b/benchmark/wavelet_trees/README.md
@@ -0,0 +1,59 @@
+# Benchmarking wavelet trees
+
+## Methodology
+
+Explored dimensions:
+
+ * wavelet tree implementations
+ * test cases
+ * methods (`access`, `rank`, `select`, `inverse_select`, `interval_symbols`, `lex_count`, `lex_smaller_count`,`construct`)
+
+## Directory structure
+
+ * [bin](./bin): Contains the executables of the project.
+ * [results](./results): Contains the results of the experiments.
+ * [src](./src): Contains the source code of the benchmark.
+ * [visualize](./visualize): Contains a `R`-script which generates
+ a report in LaTeX format.
+
+## Prerequisites
+
+ * For the visualization you need the following software:
+ - [R][RPJ] with package `tikzDevice`. You can install the
+ package by calling
+ `install.packages("filehash", repos="http://cran.r-project.org")`
+ and
+ `install.packages("tikzDevice", repos="http://R-Forge.R-project.org")`
+ in `R`.
+ - [pdflatex][LT] to generate the pdf reports.
+
+## Usage
+
+ * `make timing` compiles the programs, downloads or generates
+ the test instances, builds the wavelet trees,
+ runs the performance tests and generated a report located at
+ `visualize/wt.pdf`. The raw numbers of the timings
+ can be found in the `results/all.txt`. The default benchmark
+ took 28 minutes on my machine (MacBookPro Retina 2.6Ghz Intel
+ Code i7 16GB 1600 Mhz DDR3, SSD). Have a look at the
+ [generated report][RES].
+ * All created binaries and test results can be deleted
+ by calling `make cleanall`.
+
+## Customization of the benchmark
+
+The project contains several configuration files:
+
+ * [wt.config][WTCONFIG]: Specify different wavelet tree implementations.
+ * [test_case.config][TCCONF]: Specify test instances by ID, path, LaTeX-name
+ for the report, and download URL.
+ * [compile_options.config][CCONF]: Specify compile options by option string.
+
+Note that the benchmark will execute every combination of wavelet trees and test cases.
+
+[RPJ]: http://www.r-project.org/ "R"
+[LT]: http://www.tug.org/applications/pdftex/ "pdflatex"
+[WTCONFIG]: ./wt.config "wt.config"
+[TCCONF]: ./test_case.config "test_case.config"
+[CCONF]: ./compile_options.config "compile_options.config"
+[RES]: https://github.com/simongog/simongog.github.com/raw/master/assets/images/wt.pdf "wt.pdf"
diff --git a/benchmark/wavelet_trees/bin/.gitignore b/benchmark/wavelet_trees/bin/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/wavelet_trees/bin/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/wavelet_trees/compile_options.config b/benchmark/wavelet_trees/compile_options.config
new file mode 100644
index 0000000..cebc3e9
--- /dev/null
+++ b/benchmark/wavelet_trees/compile_options.config
@@ -0,0 +1,2 @@
+# Compile options
+-O3 -funroll-loops -fomit-frame-pointer -ffast-math -DNDEBUG
diff --git a/benchmark/wavelet_trees/results/.gitignore b/benchmark/wavelet_trees/results/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/benchmark/wavelet_trees/results/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/benchmark/wavelet_trees/src/gen_bwt.cpp b/benchmark/wavelet_trees/src/gen_bwt.cpp
new file mode 100644
index 0000000..2d7f389
--- /dev/null
+++ b/benchmark/wavelet_trees/src/gen_bwt.cpp
@@ -0,0 +1,50 @@
+#include <iostream>
+#include <fstream>
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+
+using namespace sdsl;
+int main(int argc, char* argv[])
+{
+ if (argc == 6) {
+ uint8_t num_byte = argv[5][0]=='d' ? 'd' : argv[5][0]-'0';
+ if (strcmp(argv[4], "BWT")==0) {
+ std::cout<<"Calculate BWT of " << argv[1] << " and store it to " << argv[2] << std::endl;
+ cache_config cc(false, argv[3], "gen_bwt_");
+ if (1 == num_byte) {
+ {
+ csa_wt<> wt;
+ construct(wt, argv[1], cc, 1);
+ }
+ int_vector<8> bwt;
+ load_from_file(bwt, cache_file_name(conf::KEY_BWT, cc));
+ std::ofstream out(argv[2]);
+ out.write((char*)bwt.data(), bwt.size());
+ util::delete_all_files(cc.file_map);
+ } else {
+ {
+ csa_wt<wt_int<>, 64, 64, sa_order_sa_sampling<>, int_vector<>, int_alphabet<>> wt;
+ construct(wt, argv[1], cc, num_byte);
+ }
+ int_vector<> bwt;
+ load_from_file(bwt, cache_file_name(conf::KEY_BWT_INT, cc));
+ std::ofstream out(argv[2]);
+ if ('d' == num_byte) {
+ if (bwt.size()) {
+ out << bwt[0];
+ }
+ for (uint64_t i=1; i<bwt.size(); ++i) {
+ out << " " << bwt[i];
+ }
+ } else if (0 == num_byte) {
+ store_to_file(bwt, argv[2]);
+ } else {
+ out.write((char*)bwt.data(), num_byte*bwt.size());
+ }
+ util::delete_all_files(cc.file_map);
+ }
+ }
+ } else {
+ std::cout<<"Usage: input_file output_file temp_dir create_bwt num_byte" << std::endl;
+ }
+}
diff --git a/benchmark/wavelet_trees/src/wt_time_and_space.cpp b/benchmark/wavelet_trees/src/wt_time_and_space.cpp
new file mode 100644
index 0000000..6e050e8
--- /dev/null
+++ b/benchmark/wavelet_trees/src/wt_time_and_space.cpp
@@ -0,0 +1,288 @@
+#include<iostream>
+#include<fstream>
+#include<string>
+#include<sdsl/wavelet_trees.hpp>
+#include<sdsl/wt_helper.hpp>
+
+using namespace std;
+using namespace sdsl;
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+typedef int_vector<>::size_type size_type;
+typedef WT_TYPE::value_type value_type;
+
+
+// test access
+template<class t_wt>
+uint64_t test_access(const t_wt& wt, const vector<size_type>& is, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += wt[is[i&mask]];
+ }
+ return cnt;
+}
+
+// test rank
+template<class t_wt>
+uint64_t test_rank(const t_wt& wt, const vector<size_type>& is, const vector<value_type>& cs, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += wt.rank(is[i&mask], cs[i&mask]);
+ }
+ return cnt;
+}
+
+// test inverse_select
+template<class t_wt>
+uint64_t test_inverse_select(const t_wt& wt, const vector<size_type>& is, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += wt.inverse_select(is[i&mask]).first;
+ }
+ return cnt;
+}
+
+// test interval_symbols
+template<class t_wt>
+uint64_t
+test_interval_symbols(typename enable_if<!(has_node_type<t_wt>::value),
+ t_wt>::type&, const vector<size_type>&, const vector<size_type>&, size_type&, uint64_t, uint64_t)
+{
+ return 0; // interval_symbols not implemented
+}
+
+template<class t_wt>
+uint64_t
+test_interval_symbols(typename enable_if<has_node_type<t_wt>::value,
+ t_wt>::type& wt, const vector<size_type>& is, const vector<size_type>& js, size_type& k, uint64_t mask, uint64_t times=100000000)
+{
+ vector<value_type> tmp(wt.sigma);
+ vector<size_type> tmp2(wt.sigma);
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ interval_symbols(wt, is[i&mask], js[i&mask], k, tmp, tmp2, tmp2);
+ cnt += k;
+ }
+ return cnt;
+}
+
+// test lex_count
+template<class t_wt>
+uint64_t
+test_lex_count(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&, const vector<size_type>&, const vector<size_type>&, const vector<value_type>&, uint64_t, uint64_t)
+{
+ return 0; // lex_count not implemented
+}
+
+template<class t_wt>
+uint64_t
+test_lex_count(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt, const vector<size_type>& is, const vector<size_type>& js, const vector<value_type>& cs, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += get<0>(wt.lex_count(is[i&mask], js[i&mask], cs[i&mask]));
+ }
+ return cnt;
+}
+
+// test lex_smaller_count
+template<class t_wt>
+uint64_t
+test_lex_smaller_count(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&, const vector<size_type>&, const vector<value_type>&, uint64_t, uint64_t)
+{
+ return 0; // lex_smaller_count not implemented
+}
+
+template<class t_wt>
+uint64_t
+test_lex_smaller_count(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt, const vector<size_type>& is, const vector<value_type>& cs, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += get<0>(wt.lex_smaller_count(is[i&mask], cs[i&mask]));
+ }
+ return cnt;
+}
+
+// test select
+template<class t_wt>
+uint64_t test_select(const t_wt& wt, const vector<size_type>& is, const vector<value_type>& cs, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += wt.select(is[i&mask], cs[i&mask]);
+ }
+ return cnt;
+}
+
+// generate benchmark input
+template<class t_iv>
+void random_cs(const t_iv& iv, vector<value_type>& cs)
+{
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, iv.size()-1);
+ auto dice = bind(distribution, rng);
+ for (uint64_t l = 0; l<cs.size(); ++l) {
+ cs[l]=iv[dice()];
+ }
+}
+
+template<class t_iv>
+void random_is_js(const t_iv& iv, vector<size_type>& is, vector<size_type>& js)
+{
+
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, iv.size()-1);
+ auto dice = bind(distribution, rng);
+ for (uint64_t l = 0; l<is.size(); ++l) {
+ is[l]=dice();
+ js[l]=min(is[l]+dice(), iv.size());
+ }
+}
+
+template<class t_iv>
+void prepare_for_select(const t_iv& iv, vector<value_type>& cs, vector<size_type>& is)
+{
+
+ uint64_t sigma = 0;
+ for (uint64_t i=0; i<iv.size(); ++i) {
+ if (sigma < iv[i]) sigma = iv[i];
+ }
+ ++sigma;
+
+ vector<size_type> symbols(sigma, 0);
+
+ for (uint64_t i=0; i<iv.size(); ++i) {
+ ++symbols[iv[i]];
+ }
+
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, iv.size()-1);
+ auto dice = bind(distribution, rng);
+ for (uint64_t l = 0; l<cs.size(); ++l) {
+ is[l] = dice();
+ is[l] = is[l]%symbols[cs[l]]+1;
+ }
+}
+
+template<class t_wt>
+struct wt_trait {
+ static uint64_t test_access(const t_wt& wt, const vector<size_type>& is, uint64_t mask, uint64_t times=100000000) {
+ return ::test_access(wt, is, mask, times);
+ }
+ static uint64_t test_inverse_select(const t_wt& wt, const vector<size_type>& is, uint64_t mask, uint64_t times=100000000) {
+ return ::test_inverse_select(wt, is, mask, times);
+ }
+};
+
+template<class t_rac, class t_bitvector, class t_select, class t_select_zero>
+struct wt_trait<wt_gmr_rs<t_rac, t_bitvector, t_select, t_select_zero>> {
+ static uint64_t test_access(const wt_gmr_rs<t_rac, t_bitvector, t_select, t_select_zero>&, const vector<size_type>&, uint64_t, uint64_t) {
+ return 0;
+ }
+ static uint64_t test_inverse_select(const wt_gmr_rs<t_rac, t_bitvector, t_select, t_select_zero>&, const vector<size_type>&, uint64_t, uint64_t) {
+ return 0;
+ }
+};
+
+// argv[1] = test case path argv[2] = test case type argv[3] test case name argv[4] wavelet tree id
+int main(int argc, char* argv[])
+{
+ if (argc < 4) {
+ cout << "Usage: file num_bytes testcase_name wt_id" << endl;
+ return 1;
+ }
+ uint8_t type = argv[2][0]=='d' ? 'd' : argv[2][0]-'0';
+ const uint64_t reps = 100000;
+ uint64_t log_s = 20;
+ uint64_t mask = (1<<log_s)-1;
+ uint64_t check = 0;
+ uint64_t size = 1<<log_s;
+
+ // create values
+ size_type k = 0;
+ vector<value_type> cs(size);
+ vector<size_type> is(size);
+ vector<size_type> is2(size);
+ vector<size_type> js(size);
+
+ {
+ int_vector<> iv;
+ load_vector_from_file(iv, argv[1], type);
+ random_cs(iv, cs);
+ random_is_js(iv, is, js);
+ prepare_for_select(iv, cs, is2);
+ }
+ // construct
+ memory_monitor::start();
+ auto start = timer::now();
+ WT_TYPE wt;
+ construct(wt, argv[1], type);
+ auto stop = timer::now();
+ memory_monitor::stop();
+ cout << "# constructs_time = " << duration_cast<milliseconds>(stop-start).count()/(double)1000 << endl;
+ cout << "# constructs_space = " << memory_monitor::peak() << endl;
+
+ // size
+ cout << "# wt_size = " << size_in_bytes(wt) << endl;
+
+ // print structure
+ // ofstream out("wt_"+string(argv[4])+"_"+string(argv[3])+".html");
+ // write_structure<HTML_FORMAT>(wt, out);
+
+ // access
+ start = timer::now();
+ check = wt_trait<WT_TYPE>::test_access(wt, is, mask, reps);
+ stop = timer::now();
+ cout << "# access_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# access_check = " << check << endl;
+
+ // rank
+ start = timer::now();
+ check = test_rank(wt, is, cs, mask, reps);
+ stop = timer::now();
+ cout << "# rank_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# rank_check = " << check << endl;
+
+ // inverse_select
+ start = timer::now();
+ check = wt_trait<WT_TYPE>::test_inverse_select(wt, is, mask, reps);
+ stop = timer::now();
+ cout << "# inverse_select_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# inverse_select_check = " << check << endl;
+
+ // interval_symbols
+ const uint64_t reps_interval_symbols = wt.sigma < 10000 ? reps : reps/100;
+ start = timer::now();
+ check = test_interval_symbols<WT_TYPE>(wt, is, js, k, mask, reps_interval_symbols);
+ stop = timer::now();
+ cout << "# interval_symbols_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps_interval_symbols << endl;
+ cout << "# interval_symbols_check = " << check << endl;
+
+ // lex_count
+ start = timer::now();
+ check = test_lex_count<WT_TYPE>(wt, is, js, cs, mask, reps);
+ stop = timer::now();
+ cout << "# lex_count_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# lex_count_check = " << check << endl;
+
+ // lex_smaller_count
+ start = timer::now();
+ check = test_lex_smaller_count<WT_TYPE>(wt, is, cs, mask, reps);
+ stop = timer::now();
+ cout << "# lex_smaller_count_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# lex_smaller_count_check = " << check << endl;
+
+ // select
+ start = timer::now();
+ check = test_select(wt, is2, cs, mask, reps);
+ stop = timer::now();
+ cout << "# select_time = " << duration_cast<microseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# select_check = " << check << endl;
+
+ return 0;
+}
diff --git a/benchmark/wavelet_trees/test_case.config b/benchmark/wavelet_trees/test_case.config
new file mode 100644
index 0000000..ce2a5be
--- /dev/null
+++ b/benchmark/wavelet_trees/test_case.config
@@ -0,0 +1,32 @@
+# Configuration for test files
+# (1) Identifier for test file (consisting of letters, no `.`)
+# (2) Path to the test file
+# (3) LaTeX name
+# (4) Download link (if the test is available online)
+# (5) Test file type(0: serialized int_vector<>, 1: byte sequence, 2: 16-bit word sequence, 4: 32-bit word sequence, 8: 64-bit word sequence, d: Parse decimal numbers)
+# (6) Input type for wavelet tree construction (PLAIN: (2) is used as input, BWT: The BWT for (2) will be constructed and used as input)
+ENGLISH;../data/english.200MB;english.200MB;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz;1;PLAIN
+DBLPXML;../data/dblp.xml.200MB;dblp.xml.200MB;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz;1;PLAIN
+DNA;../data/dna.200MB;dna.200MB;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz;1;PLAIN
+PROTEINS;../data/proteins.200MB;proteins.200MB;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz;1;PLAIN
+SOURCES;../data/sources.200MB;sources.200MB;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz;1;PLAIN
+#INFLUENZA;../data/influenza;influenza;http://pizzachili.dcc.uchile.cl/repcorpus/real/influenza.gz;1;PLAIN
+#EINSTEIN-de;../data/einstein.de.txt;einstein-de;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.de.txt.gz;1;PLAIN
+#EINSTEIN-en;../data/einstein.en.txt;einstein-en;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.en.txt.gz;1;PLAIN
+#PARA;../data/para;para;http://pizzachili.dcc.uchile.cl/repcorpus/real/para.gz;1;PLAIN
+#WORLDLEADER;../data/world_leaders;world-leaders;http://pizzachili.dcc.uchile.cl/repcorpus/real/world_leaders.gz;1;PLAIN
+#E_COLI;../data/Escherichia_Coli;E.coli;http://pizzachili.dcc.uchile.cl/repcorpus/real/Escherichia_Coli.gz;1;PLAIN
+#ENWIKISMLINT;../data/enwiki-20130805-pages-articles1.int.sdsl;enwiki-sml-int;http://people.eng.unimelb.edu.au/sgog/data/enwiki-20130805-pages-articles1.int.sdsl.gz;0;PLAIN
+
+ENGLISH_BWT;../data/english.200MB;english.200MB-bwt;http://pizzachili.di.unipi.it/texts/nlang/english.200MB.gz;1;BWT
+DBLPXML_BWT;../data/dblp.xml.200MB;dblp.xml.200MB-bwt;http://pizzachili.di.unipi.it/texts/xml/dblp.xml.200MB.gz;1;BWT
+DNA_BWT;../data/dna.200MB;dna.200MB-bwt;http://pizzachili.di.unipi.it/texts/dna/dna.200MB.gz;1;BWT
+PROTEINS_BWT;../data/proteins.200MB;proteins.200MB-bwt;http://pizzachili.di.unipi.it/texts/protein/proteins.200MB.gz;1;BWT
+SOURCES_BWT;../data/sources.200MB;sources.200MB-bwt;http://pizzachili.di.unipi.it/texts/code/sources.200MB.gz;1;BWT
+#INFLUENZA_BWT;../data/influenza;influenza-bwt;http://pizzachili.dcc.uchile.cl/repcorpus/real/influenza.gz;1;BWT
+#EINSTEIN-de_BWT;../data/einstein.de.txt;einstein-de-bwt;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.de.txt.gz;1;BWT
+#EINSTEIN-en_BWT;../data/einstein.en.txt;einstein-en-bwt;http://pizzachili.dcc.uchile.cl/repcorpus/real/einstein.en.txt.gz;1;BWT
+#PARA_BWT;../data/para;para-bwt;http://pizzachili.dcc.uchile.cl/repcorpus/real/para.gz;1;BWT
+#WORLDLEADER_BWT;../data/world_leaders;world-leaders-bwt;http://pizzachili.dcc.uchile.cl/repcorpus/real/world_leaders.gz;1;BWT
+#E_COLI_BWT;../data/Escherichia_Coli;E.coli-bwt;http://pizzachili.dcc.uchile.cl/repcorpus/real/Escherichia_Coli.gz;1;BWT
+#ENWIKISMLINT_BWT;../data/enwiki-20130805-pages-articles1.int.sdsl;enwiki-sml-int-bwt;http://people.eng.unimelb.edu.au/sgog/data/enwiki-20130805-pages-articles1.int.sdsl.gz;0;BWT
diff --git a/benchmark/wavelet_trees/visualize/.gitignore b/benchmark/wavelet_trees/visualize/.gitignore
new file mode 100644
index 0000000..27318f9
--- /dev/null
+++ b/benchmark/wavelet_trees/visualize/.gitignore
@@ -0,0 +1,6 @@
+*
+!.gitignore
+!Makefile
+!wt-footer.tex
+!wt-header.tex
+!wt.R
diff --git a/benchmark/wavelet_trees/visualize/Makefile b/benchmark/wavelet_trees/visualize/Makefile
new file mode 100644
index 0000000..58056fa
--- /dev/null
+++ b/benchmark/wavelet_trees/visualize/Makefile
@@ -0,0 +1,17 @@
+include ../../../Make.helper
+
+CONFIG_FILES= ../test_case.config
+
+all: wt.pdf
+
+wt.pdf: wt.tex
+ @echo "Use pdflatex to generate wt.pdf"
+ @pdflatex wt.tex >> LaTeX.Log 2>&1
+
+wt.tex: ../results/all.txt ../../basic_functions.R wt.R $(CONFIG_FILES)
+ @echo "Use R to generate wt.tex"
+ @R --vanilla < wt.R > R.log 2>&1
+
+clean:
+ rm -f wt.pdf wt.aux wt.tex fig* \
+ wt.log R.log LaTeX.log
diff --git a/benchmark/wavelet_trees/visualize/wt-footer.tex b/benchmark/wavelet_trees/visualize/wt-footer.tex
new file mode 100644
index 0000000..6b47932
--- /dev/null
+++ b/benchmark/wavelet_trees/visualize/wt-footer.tex
@@ -0,0 +1 @@
+\end{document}
diff --git a/benchmark/wavelet_trees/visualize/wt-header.tex b/benchmark/wavelet_trees/visualize/wt-header.tex
new file mode 100644
index 0000000..0b4deec
--- /dev/null
+++ b/benchmark/wavelet_trees/visualize/wt-header.tex
@@ -0,0 +1,10 @@
+\documentclass[9pt,a4paper,DIV10]{scrartcl}
+\usepackage{tikz}
+\usepackage{booktabs}
+\usepackage{array}
+\usepackage{ragged2e}
+\usepackage{float}
+
+\begin{document}
+
+\pagestyle{empty}
diff --git a/benchmark/wavelet_trees/visualize/wt.R b/benchmark/wavelet_trees/visualize/wt.R
new file mode 100644
index 0000000..b296a89
--- /dev/null
+++ b/benchmark/wavelet_trees/visualize/wt.R
@@ -0,0 +1,198 @@
+require(tikzDevice)
+source("../../basic_functions.R")
+
+tex_file = "wt.tex"
+
+tc_config <- readConfig("../test_case.config",c("TC_ID","PATH","LATEX_NAME","URL","TC_TYPE"))
+
+open_tikz <- function( file_name ){
+ tikz(file_name, width = 5.5, height = 7.5 , standAlone = F)
+}
+
+x_for_bar<-function(value){
+ c(0,0,value,value)
+}
+
+y_for_bar<-function(offset){
+ c(offset,offset+0.4,offset+0.4,offset)
+}
+
+#Method which plots the size figure
+plot_size_figure <-function(data,heading,ylab=F){
+
+ #set margin
+ par(mar=c(3,2,3,0))
+ if(ylab){
+ par(mar=c(3,10,3,0))
+ }
+
+ plot(c(),c(),ylim=c(0,(length(data)*0.5)+0.2),xlim=c(0,max(101,(max(data)+1))),xlab="",ylab="",xaxt="n",yaxt="n")
+
+ #label y-axis
+ if(ylab){
+ axis( 2, at =seq(0.3,(length(data)*0.5)+0.2,0.5), label=colnames(data),las=1)
+ }
+ #label x-axis
+ axis(1)
+ mtext("Size relative to original file size", side=1, line=2)
+
+ #draw bars
+ offset=0.1
+ for(time in data){
+ polygon( x_for_bar(time),y_for_bar(offset), border=NA, col="grey")
+ offset=offset+0.5
+ }
+
+ #abline(v=c(axis(1)/2,max(axis(1)/2)+axis(1)/2), col="gray")
+ abline(v=c(axis(1),axis(1)+(axis(1)[2]-axis(1)[1])/2),col="gray")
+ abline(v=100, col="red")
+ draw_figure_heading(heading)
+}
+
+#Method which plots the a time figure
+plot_time_figure <-function(data,heading,ylab=T,xlab=T,constructor=F,xmax=max(data)){
+ #set margin
+ par(mar=c(3,2,2,0))
+ if(ylab){
+ par(mar=c(3,10,2,0))
+ }
+
+ plot(c(),c(),ylim=c(0,(length(data)*0.5)+0.2),xlim=c(0,(xmax*1.02)),xlab="",ylab="",xaxt="n",yaxt="n")
+
+ #label y-axis
+ if(ylab){
+ axis( 2, at =seq(0.3,(length(data)*0.5)+0.2,0.5), label=colnames(data),las=1)
+ }
+ #label x-axis
+ axis(1)
+ abline(v=c(axis(1),axis(1)+(axis(1)[2]-axis(1)[1])/2),col="gray")
+ if(xlab){
+ mtext("Time in microseconds", side=1, line=2)
+ }
+ if(constructor){
+ mtext("Time in seconds", side=1, line=2)
+ }
+
+ #draw bars
+ offset=0.1
+ for(time in data){
+ polygon( x_for_bar(time),y_for_bar(offset), border=NA, col="grey")
+ offset=offset+0.5
+ }
+
+ draw_figure_heading(heading)
+}
+
+
+#read header
+tex_doc <- paste(readLines("wt-header.tex"),collapse="\n")
+
+tex_doc<-paste(tex_doc,"\\section{Result of the Wavelet Tree benchmark}")
+
+
+maindata <- data_frame_from_key_value_pairs( "../results/all.txt" )
+
+#create two pages for each test case
+#for(tc in tc_config[['TC_ID']]){
+for(tc in unique(maindata$TC_ID)){
+
+ data<-maindata[maindata$TC_ID==tc,]
+ id <-data[['WT_TEX_NAME']]
+ xmax<-max(data[c('access_time','rank_time','select_time','inverse_select_time','lex_count_time','lex_smaller_count_time')])
+
+ #first page start
+ fig_name <- paste("fig-page1-",tc,".tex",sep="")
+ tex_doc<-paste(tex_doc,"\\subsection{Test case: {\\sc ",data[['TC_TEX_NAME']],"}}")
+
+ open_tikz( fig_name )
+
+ layout(matrix(c(1,2,3,4,5,6), 3, 2, byrow = TRUE),
+ widths=c(1.35,1), heights=c(1,1,1))
+
+ #access-plot
+ a <-data['access_time']
+ rownames(a)<-id
+ plot_time_figure(t(a),"\\tt{access}",xlab=F,xmax=xmax)
+
+ #rank-plot
+ rank <-data['rank_time']
+ rownames(rank)<-id
+ plot_time_figure(t(rank),"\\tt{rank}",ylab=F,xlab=F,xmax=xmax)
+
+ #select-plot
+ s <-data['select_time']
+ rownames(s)<-id
+ plot_time_figure(t(s),"\\tt{select}",xlab=F,xmax=xmax)
+
+ #inverse-select-plot
+ is <-data['inverse_select_time']
+ rownames(is)<-id
+ plot_time_figure(t(is),"\\tt{inverse\\_select}",xlab=F,ylab=F,xmax=xmax)
+
+ #lex-count-plot
+ lc <-data['lex_count_time']
+ rownames(lc)<-id
+ plot_time_figure(t(lc),"\\tt{lex\\_count}",xmax=xmax)
+
+ #lex-smaller-count-plot
+ lsc <-data['lex_smaller_count_time']
+ rownames(lsc)<-id
+ plot_time_figure(t(lsc),"\\tt{lex\\_smaller\\_count}",ylab=F,xmax=xmax)
+
+ old<-par()
+ dev.off()
+ tex_doc <- paste(tex_doc,"\\begin{figure}[H]
+ \\input{",fig_name,"}
+ \\end{figure}")
+ #first page end
+
+ #second page start
+ fig_name <- paste("fig-page2-",tc,".tex",sep="")
+ open_tikz( fig_name )
+
+ layout(matrix(c(1,2,3,4,5,6), 3, 2, byrow = TRUE),
+ widths=c(1.35,1), heights=c(1,1,1))
+
+ #interval-symbols-plot
+ ivs <-data['interval_symbols_time']
+ rownames(ivs)<-id
+ plot_time_figure(t(ivs),"\\tt{interval\\_symbols}",xmax=max(xmax,max(ivs)))
+
+ #constructor-plot
+ con <-data['constructs_time']
+ rownames(con)<-id
+ plot_time_figure(t(con),"\\tt{construct}",ylab=F,xlab=F,constructor=T)
+
+ #construction-size-plot
+ tsize<-data[[1,'TC_SIZE']]
+ consize <-(data['constructs_space']/tsize)*100
+ rownames(consize)<-id
+
+ plot_size_figure(t(consize),"\\tt{construction space}",ylab=T)
+
+ #size-plot
+ tsize<-data[[1,'TC_SIZE']]
+ size <-(data['wt_size']/tsize)*100
+ rownames(size)<-id
+
+ plot_size_figure(t(size),"\\tt{space}")
+
+ dev.off()
+ tex_doc <- paste(tex_doc,"\\begin{figure}[H]
+ \\input{",fig_name,"}
+ \\end{figure}")
+ #second page end
+}
+
+#type identification table
+tex_doc<-paste(tex_doc,"\\begin{table}[b]
+ \\centering",
+ typeInfoTable("../wt.config",data[['WT_ID']], 1, 3, 2),
+ "\\caption{Wavelet tree identifier and corresponding sdsl-type.}
+ \\end{table}")
+
+#read footer+end
+tex_doc <- paste(tex_doc, readLines("wt-footer.tex"),collapse="\n")
+sink(tex_file)
+cat(tex_doc)
+sink(NULL)
diff --git a/benchmark/wavelet_trees/wt.config b/benchmark/wavelet_trees/wt.config
new file mode 100644
index 0000000..2c76779
--- /dev/null
+++ b/benchmark/wavelet_trees/wt.config
@@ -0,0 +1,66 @@
+# This file specifies wavelettrees that are used in the benchmark.
+#
+# Each index is specified by a triple: WT_ID;SDSL_TYPE;WT_LATEX_NAME
+# * WT_ID : An identifier for the index. Only letters and underscores are allowed in ID.
+# * SDSL_TYPE : Corresponding sdsl type.
+# * WT_LATEX_NAME: LaTeX name for output in the benchmark report.
+
+# Different Shapes and Bit-Vectors (Byte-Alphabet):
+BLCD_v;wt_blcd<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, byte_tree<>>;WT-BLCD-v
+#BLCD_v5;wt_blcd<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>, byte_tree<>>;WT-BLCD-v5
+#BLCD_il;wt_blcd<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>, byte_tree<>>;WT-BLCD-il
+BLCD_RRR15;wt_blcd<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type, byte_tree<>>;WT-BLCD-RRR15
+BLCD_RRR63;wt_blcd<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, byte_tree<>>;WT-BLCD-RRR63
+HUTU_v;wt_hutu<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, byte_tree<>>;WT-HUTU-v
+#HUTU_v5;wt_hutu<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>, byte_tree<>>;WT-HUTU-v5
+#HUTU_il;wt_hutu<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>, byte_tree<>>;WT-HUTU-il
+HUTU_RRR15;wt_hutu<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type, byte_tree<>>;WT-HUTU-RRR15
+HUTU_RRR63;wt_hutu<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, byte_tree<>>;WT-HUTU-RRR63
+HUFF_v;wt_huff<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, byte_tree<>>;WT-HUFF-v
+#HUFF_v5;wt_huff<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>, byte_tree<>>;WT-HUFF-v5
+#HUFF_il;wt_huff<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>, byte_tree<>>;WT-HUFF-il
+HUFF_RRR15;wt_huff<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type, byte_tree<>>;WT-HUFF-RRR15
+HUFF_RRR63;wt_huff<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, byte_tree<>>;WT-HUFF-RRR63
+RLMN_v;wt_rlmn<bit_vector, rank_support_v<>, select_support_mcl<1>, wt_huff<>>;WT-RLMN-v
+#RLMN_v5;wt_rlmn<bit_vector, rank_support_v5<>, select_support_mcl<1>, wt_huff<>>;WT-RLMN-v5
+#RLMN_il;wt_rlmn<bit_vector_il<>, rank_support_il<>, select_support_il<1>, wt_huff<>>;WT-RLMN-il
+#RLMN_RRR15;wt_rlmn<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, wt_huff<>>;WT-RLMN-RRR15
+#RLMN_RRR63;wt_rlmn<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, wt_huff<>>;WT-RLMN-RRR63
+RLMN_SD;wt_rlmn<sd_vector<>, sd_vector<>::rank_1_type, sd_vector<>::select_1_type, wt_huff<>>;WT-RLMN-SD
+
+# Different Shapes and Bit-Vectors (Int-Alphabet):
+#WT_INT_v;wt_int<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>>;WT-INT-v
+#WT_INT_v5;wt_int<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>>;WT-INT-v5
+#WT_INT_il;wt_int<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>>;WT-INT-il
+#WT_INT_RRR15;wt_int<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type>;WT-INT-RRR15
+#WT_INT_RRR63;wt_int<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type>;WT-INT-RRR63
+#BLCD_v;wt_blcd<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>;WT-BLCD-v
+#BLCD_v5;wt_blcd<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>;WT-BLCD-v5
+#BLCD_il;wt_blcd<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>, int_tree<>>;WT-BLCD-il
+#BLCD_RRR15;wt_blcd<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type, int_tree<>>;WT-BLCD-RRR15
+#BLCD_RRR63;wt_blcd<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, int_tree<>>;WT-BLCD-RRR63
+#HUTU_v;wt_hutu<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>;WT-HUTU-v
+#HUTU_v5;wt_hutu<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>;WT-HUTU-v5
+#HUTU_il;wt_hutu<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>, int_tree<>>;WT-HUTU-il
+#HUTU_RRR15;wt_hutu<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type, int_tree<>>;WT-HUTU-RRR15
+#HUTU_RRR63;wt_hutu<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, int_tree<>>;WT-HUTU-RRR63
+#HUFF_v;wt_huff<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>;WT-HUFF-v
+#HUFF_v5;wt_huff<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>;WT-HUFF-v5
+#HUFF_il;wt_huff<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>, int_tree<>>;WT-HUFF-il
+#HUFF_RRR15;wt_huff<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type, int_tree<>>;WT-HUFF-RRR15
+#HUFF_RRR63;wt_huff<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, int_tree<>>;WT-HUFF-RRR63
+#WM_INT_v;wm_int<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>>;WM-INT-v
+#WM_INT_v5;wm_int<bit_vector, rank_support_v5<>, select_support_mcl<1>, select_support_mcl<0>>;WM-INT-v5
+#WM_INT_il;wm_int<bit_vector_il<>, rank_support_il<>, select_support_il<1>, select_support_il<0>>;WM-INT-il
+#WM_INT_RRR15;wm_int<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, rrr_vector<15>::select_0_type>;WM-INT-RRR15
+#WM_INT_RRR63;wm_int<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type>;WM-INT-RRR63
+#RLMN_v_INT;wt_rlmn<bit_vector, rank_support_v<>, select_support_mcl<1>, wt_int<>>;INT-WT-RLMN-v
+#RLMN_v5_INT;wt_rlmn<bit_vector, rank_support_v5<>, select_support_mcl<1>, wt_int<>>;INT-WT-RLMN-v5
+#RLMN_il_INT;wt_rlmn<bit_vector_il<>, rank_support_il<>, select_support_il<1>, wt_int<>>;INT-WT-RLMN-il
+#RLMN_RRR15_INT;wt_rlmn<rrr_vector<15>, rrr_vector<15>::rank_1_type, rrr_vector<15>::select_1_type, wt_int<>>;INT-WT-RLMN-RRR15
+#RLMN_RRR63_INT;wt_rlmn<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, wt_int<>>;INT-WT-RLMN-RRR63
+#RLMN_SD_INT;wt_rlmn<sd_vector<>, sd_vector<>::rank_1_type, sd_vector<>::select_1_type, wt_int<>>;INT-WT-RLMN-SD
+#WT_GMR_RS_IV;wt_gmr_rs<int_vector<>, bit_vector, select_support_mcl<1>, select_support_mcl<0>>;WT-GMR-RS-IV
+#WT_GMR_RS_ED128;wt_gmr_rs<enc_vector<coder::elias_delta,128>, bit_vector, select_support_mcl<1>, select_support_mcl<0>>;WT-GMR-RS-ED128
+#WT_GMR_IV_IPS32;wt_gmr<int_vector<>, inv_multi_perm_support<32, int_vector<> > >;WT-GMR-IV-IPS32
+#WT_GMR_ED128_IPS32;wt_gmr< enc_vector<coder::elias_delta,128>, inv_multi_perm_support<32,enc_vector<coder::elias_delta,128> > >;WT-GMR-ED128-IPS32
diff --git a/build/.gitignore b/build/.gitignore
new file mode 100644
index 0000000..59573ce
--- /dev/null
+++ b/build/.gitignore
@@ -0,0 +1,4 @@
+*
+!.gitignore
+!build.sh
+!clean.sh
diff --git a/build/build.sh b/build/build.sh
new file mode 100755
index 0000000..97a7396
--- /dev/null
+++ b/build/build.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+CUR_DIR=`pwd`
+OLD_DIR="$( cd "$( dirname "$0" )" && pwd )" # gets the directory where the script is located in
+cd "${OLD_DIR}"
+
+cmake .. -DCMAKE_INSTALL_PREFIX=${HOME} && make install
+
+cd ${CUR_DIR}
diff --git a/build/clean.sh b/build/clean.sh
new file mode 100755
index 0000000..0f30bdc
--- /dev/null
+++ b/build/clean.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# activate globbing
+shopt -s extglob
+# removes all but the listed files in the directory
+# and subdirectories
+rm -rf !(build.sh|clean.sh|.gitignore|..|.)
+
diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 0000000..35b6904
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1,4 @@
+*
+!*.cpp
+!Makefile
+!.gitignore
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..2268987
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,16 @@
+include ../Make.helper
+CXX_FLAGS=$(MY_CXX_FLAGS) $(MY_CXX_OPT_FLAGS) -I$(INC_DIR) -L$(LIB_DIR)
+CCLIB=-lsdsl -ldivsufsort -ldivsufsort64
+SOURCES=$(wildcard *.cpp)
+EXECS=$(SOURCES:.cpp=.x)
+
+all: $(EXECS)
+
+build-test: $(EXECS)
+
+%.x:%.cpp
+ $(MY_CXX) $(CXX_FLAGS) -o $@ $< $(CCLIB)
+
+clean:
+ rm -f $(EXECS)
+ rm -rf *.dSYM
diff --git a/examples/bit-vector.cpp b/examples/bit-vector.cpp
new file mode 100644
index 0000000..51cc78d
--- /dev/null
+++ b/examples/bit-vector.cpp
@@ -0,0 +1,46 @@
+#include <sdsl/bit_vectors.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+
+ bit_vector b(10000000, 0);
+ b[8] = 1;
+ rank_support_v<> rb(&b);
+
+ cout<<rb(8)<<endl;
+ cout<<rb(9)<<endl;
+
+ cout<< "size of b in MB: " << size_in_mega_bytes(b)<< endl;
+ cout<< "size of rb in MB: " << size_in_mega_bytes(rb)<< endl;
+
+ rrr_vector<127> rrrb(b);
+ rrr_vector<127>::rank_1_type rank_rrrb(&rrrb);
+ cout<<rank_rrrb(8)<<endl;
+ cout<<rank_rrrb(9)<<endl;
+
+ cout<< "size of rrrb in MB: " << size_in_mega_bytes(rrrb)<< endl;
+ cout<< "size of rank_rrrb in MB: " << size_in_mega_bytes(rank_rrrb)<< endl;
+
+
+ rrr_vector<127>::select_1_type select_rrrb(&rrrb);
+ cout<<"position of first one in b: "<<select_rrrb(1)<<endl;
+
+ bit_vector x;
+ util::assign(x, bit_vector(10000000,1));
+
+ int_vector<> v(100, 5, 7);
+
+ cout<<"v[5]="<<v[5]<<endl;
+ v[5]=120;
+ cout<<"v[5]="<<v[5]<<endl;
+
+
+ int_vector<32> w(100, 4);
+
+ write_structure<JSON_FORMAT>(rrrb, cout);
+ cout<<endl;
+}
diff --git a/examples/c++11-initializer-list.cpp b/examples/c++11-initializer-list.cpp
new file mode 100644
index 0000000..8bb204d
--- /dev/null
+++ b/examples/c++11-initializer-list.cpp
@@ -0,0 +1,24 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+#include <algorithm>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ int_vector<8> b = {'c','d','a','b','d'};
+ int_vector<> a = {1,8,3,15,5};
+
+ for (auto c : b) {
+ cout << c;
+ } cout << endl;
+ for (auto x : a) {
+ cout << x << ",";
+ }
+ cout << endl;
+ sort(a.begin(), a.end());
+ for (auto x: a) {
+ cout << x << ",";
+ }
+}
diff --git a/examples/construct-in-memory.cpp b/examples/construct-in-memory.cpp
new file mode 100644
index 0000000..8e5e802
--- /dev/null
+++ b/examples/construct-in-memory.cpp
@@ -0,0 +1,53 @@
+#include <sdsl/suffix_trees.hpp>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ string file = "@testinput.iv8";
+ string v = "abracadabradabarab";
+ cout<<"v.size()="<<v.size()<<endl;
+ cout<<v<<endl;
+ store_to_file((const char*)v.c_str(), file);
+ cout<<"---------"<<endl;
+ cout << util::file_size(file) << endl;
+ cout<<"--------- construct wt_huff<> ----------"<<endl;
+ {
+ wt_huff<> wt;
+ construct(wt, file, 1);
+ cout << "wt.size()="<<wt.size()<<endl;
+ cout << util::file_size(file) << endl;
+ for (size_t i=0; i < wt.size(); ++i) {
+ cout << wt[i] << " ";
+ }
+ cout << endl;
+ }
+ cout<<"---------"<<endl;
+ cout<<"--------- construct csa_wt<> ----------"<<endl;
+ {
+ csa_wt<> csa;
+ construct(csa, file, 1);
+ cout << "csa.size()="<<csa.size()<<endl;
+ for (size_t i=0; i < csa.size(); ++i) {
+ cout << csa[i] << " ";
+ }
+ cout << endl;
+ }
+ cout<<"---------"<<endl;
+
+ cout<<"--------- construct csa_sct3<> ----------"<<endl;
+ {
+ typedef cst_sada<> cst_type;
+ cst_type cst;
+ construct(cst, file, 1);
+ cout << "cst.size()="<<cst.size()<<endl;
+ for (cst_type::const_iterator it=cst.begin(); it!=cst.end(); ++it) {
+ cout << cst.depth(*it) << "-[" << cst.lb(*it) << "," << cst.rb(*it) << "]" << endl;
+ }
+ cout << endl;
+ }
+ cout<<"---------"<<endl;
+
+}
diff --git a/examples/csa-alphabet-strategy.cpp b/examples/csa-alphabet-strategy.cpp
new file mode 100644
index 0000000..72b4584
--- /dev/null
+++ b/examples/csa-alphabet-strategy.cpp
@@ -0,0 +1,49 @@
+/* This example shows how the representation of the alphabet dependent
+ * part of a CST can be altered by using policy classes.
+ */
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+template<class csa_t>
+void csa_info(csa_t& csa, const char* file, bool json)
+{
+ cout << "file : " << file << endl;
+ construct(csa, file, 1);
+ cout << "csa of type : " << util::demangle(typeid(csa).name()) << endl;
+ cout << "size in bytes : " << size_in_bytes(csa) << endl;
+ if (json) {
+ cout << "---------------" << endl;
+ cout << "json output: " << endl;
+ write_structure<JSON_FORMAT>(csa, cout);
+ cout << endl;
+ }
+ cout << "---------------" << endl;
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " file [JSON]" << endl;
+ cout << " (1) Constructs CSAs 2 csa_sada and 2 csa_wt, with" << endl;
+ cout << " alphabet strategies." << endl;
+ cout << " (2) Outputs type and size. If JSON is specified," << endl;
+ cout << " also the structure in JSON-format." << endl;
+ return 1;
+ }
+ bool json = false;
+ if (argc > 2) {
+ json = true;
+ }
+ csa_sada<enc_vector<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, byte_alphabet> csa1;
+ csa_sada<enc_vector<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, succinct_byte_alphabet<> > csa2;
+ csa_wt<wt_huff<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, byte_alphabet> csa3;
+ csa_wt<wt_huff<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, succinct_byte_alphabet<> > csa4;
+ csa_info(csa1, argv[1], json);
+ csa_info(csa2, argv[1], json);
+ csa_info(csa3, argv[1], json);
+ csa_info(csa4, argv[1], json);
+}
diff --git a/examples/cst-bfs-iterator.cpp b/examples/cst-bfs-iterator.cpp
new file mode 100644
index 0000000..428f41f
--- /dev/null
+++ b/examples/cst-bfs-iterator.cpp
@@ -0,0 +1,28 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+#include <string>
+
+using namespace std;
+using namespace sdsl;
+
+typedef cst_sct3<> cst_t;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "usage: "<<argv[0]<< " file" << std::endl;
+ return 1;
+ }
+
+ cst_t cst;
+ construct(cst, argv[1], 1);
+
+ typedef cst_bfs_iterator<cst_t> iterator;
+ iterator begin = iterator(&cst, cst.root());
+ iterator end = iterator(&cst, cst.root(), true, true);
+
+ for (iterator it = begin; it != end; ++it) {
+ std::cout << cst.depth(*it) << "-[" << cst.lb(*it) << "," << cst.rb(*it) << "]" << std::endl;
+ }
+
+}
diff --git a/examples/cst-node-child-iterator.cpp b/examples/cst-node-child-iterator.cpp
new file mode 100644
index 0000000..8a46693
--- /dev/null
+++ b/examples/cst-node-child-iterator.cpp
@@ -0,0 +1,33 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+#include <string>
+
+using namespace std;
+using namespace sdsl;
+
+typedef cst_sct3<> cst_t;
+typedef cst_sada<> csts_t;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "usage: "<<argv[0]<< " file" << std::endl;
+ return 1;
+ }
+
+ cst_t cst;
+ construct(cst, argv[1], 1);
+
+ auto root = cst.root();
+
+ for (auto& child: cst.children(root)) {
+ std::cout << "sct3 id = " << cst.id(child) << std::endl;
+ }
+
+ csts_t csts;
+ construct(csts, argv[1], 1);
+ auto roots = csts.root();
+ for (auto child: csts.children(roots)) {
+ std::cout << "sada id = " << csts.id(child) << std::endl;
+ }
+}
diff --git a/examples/fm-index.cpp b/examples/fm-index.cpp
new file mode 100644
index 0000000..c57784d
--- /dev/null
+++ b/examples/fm-index.cpp
@@ -0,0 +1,87 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <string>
+#include <iostream>
+#include <algorithm>
+#include <iomanip>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ cout << "Usage " << argv[0] << " text_file [max_locations] [post_context] [pre_context]" << endl;
+ cout << " This program constructs a very compact FM-index" << endl;
+ cout << " which supports count, locate, and extract queries." << endl;
+ cout << " text_file Original text file." << endl;
+ cout << " max_locations Maximal number of location to report." <<endl;
+ cout << " post_context Maximal length of the reported post-context." << endl;
+ cout << " pre_context Maximal length of the pre-context." << endl;
+ return 1;
+ }
+ size_t max_locations = 5;
+ size_t post_context = 10;
+ size_t pre_context = 10;
+ if (argc >= 3) {
+ max_locations = atoi(argv[2]);
+ }
+ if (argc >= 4) {
+ post_context = atoi(argv[3]);
+ }
+ if (argc >= 5) {
+ pre_context = atoi(argv[4]);
+ }
+ string index_suffix = ".fm9";
+ string index_file = string(argv[1])+index_suffix;
+ csa_wt<wt_huff<rrr_vector<127> >, 512, 1024> fm_index;
+
+ if (!load_from_file(fm_index, index_file)) {
+ ifstream in(argv[1]);
+ if (!in) {
+ cout << "ERROR: File " << argv[1] << " does not exist. Exit." << endl;
+ return 1;
+ }
+ cout << "No index "<<index_file<< " located. Building index now." << endl;
+ construct(fm_index, argv[1], 1); // generate index
+ store_to_file(fm_index, index_file); // save it
+ }
+ cout << "Index construction complete, index requires " << size_in_mega_bytes(fm_index) << " MiB." << endl;
+ cout << "Input search terms and press Ctrl-D to exit." << endl;
+ string prompt = "\e[0;32m>\e[0m ";
+ cout << prompt;
+ string query;
+ while (getline(cin, query)) {
+ size_t m = query.size();
+ size_t occs = sdsl::count(fm_index, query.begin(), query.end());
+ cout << "# of occurrences: " << occs << endl;
+ if (occs > 0) {
+ cout << "Location and context of first occurrences: " << endl;
+ auto locations = locate(fm_index, query.begin(), query.begin()+m);
+ sort(locations.begin(), locations.end());
+ for (size_t i = 0, pre_extract = pre_context, post_extract = post_context; i < min(occs, max_locations); ++i) {
+ cout << setw(8) << locations[i] << ": ";
+ if (pre_extract > locations[i]) {
+ pre_extract = locations[i];
+ }
+ if (locations[i]+m+ post_extract > fm_index.size()) {
+ post_extract = fm_index.size()-locations[i]-m;
+ }
+ auto s = extract(fm_index, locations[i]-pre_extract, locations[i]+m+ post_extract-1);
+ string pre = s.substr(0, pre_extract);
+ s = s.substr(pre_extract);
+ if (pre.find_last_of('\n') != string::npos) {
+ pre = pre.substr(pre.find_last_of('\n')+1);
+ }
+ cout << pre;
+ cout << "\e[1;31m";
+ cout << s.substr(0, m);
+ cout << "\e[0m";
+ string context = s.substr(m);
+ cout << context.substr(0, context.find_first_of('\n')) << endl;
+ }
+ }
+ cout << prompt;
+ }
+ cout << endl;
+}
+
diff --git a/examples/fm-rmq-index.cpp b/examples/fm-rmq-index.cpp
new file mode 100644
index 0000000..0817216
--- /dev/null
+++ b/examples/fm-rmq-index.cpp
@@ -0,0 +1,143 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <sdsl/rmq_support.hpp>
+#include <string>
+#include <iostream>
+#include <algorithm>
+#include <iomanip>
+#include <queue>
+
+using namespace sdsl;
+using namespace std;
+
+struct interval {
+ size_t lb, rb; // left bound, right bound (both inclusive)
+ size_t min_val, min_idx; // minimal value, index of the minimum
+
+ interval(size_t lb, size_t rb, size_t min_val, size_t min_idx):
+ lb(lb), rb(rb), min_val(min_val), min_idx(min_idx) {};
+
+ interval(const interval& i):
+ lb(i.lb), rb(i.rb), min_val(i.min_val), min_idx(i.min_idx) {};
+
+ bool operator>(const interval& i)const {
+ if (min_val != i.min_val) {
+ return min_val > i.min_val;
+ }
+ if (min_idx != i.min_idx) {
+ return min_idx > i.min_idx;
+ }
+ if (lb != i.lb) {
+ return lb > i.lb;
+ }
+ return rb > i.rb;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ cout << "Usage " << argv[0] << " text_file [max_locations] [post_context] [pre_context]" << endl;
+ cout << " This program constructs a very compact FM-index" << endl;
+ cout << " which supports count, locate, and extract queries." << endl;
+ cout << " text_file Original text file." << endl;
+ cout << " max_locations Maximal number of location to report." <<endl;
+ cout << " post_context Maximal length of the reported post-context." << endl;
+ cout << " pre_context Maximal length of the pre-context." << endl;
+ return 1;
+ }
+ size_t max_locations = 5;
+ size_t post_context = 10;
+ size_t pre_context = 10;
+ if (argc >= 3) {
+ max_locations = atoi(argv[2]);
+ }
+ if (argc >= 4) {
+ post_context = atoi(argv[3]);
+ }
+ if (argc >= 5) {
+ pre_context = atoi(argv[4]);
+ }
+ string index_suffix = ".fm9";
+ string index_file = string(argv[1])+index_suffix;
+ typedef csa_wt<wt_huff<rrr_vector<127> >, 512, 1024> fm_index_type;
+ typedef fm_index_type::size_type size_type;
+ fm_index_type fm_index;
+ if (!load_from_file(fm_index, index_file)) {
+ ifstream in(argv[1]);
+ if (!in) {
+ cout << "ERROR: File " << argv[1] << " does not exist. Exit." << endl;
+ return 1;
+ }
+ cout << "No index "<<index_file<< " located. Building index now." << endl;
+ construct(fm_index, argv[1], 1); // generate index
+ store_to_file(fm_index, index_file); // save it
+ }
+ string rmq_suffix = ".rmq";
+ string rmq_file = string(argv[1])+rmq_suffix;
+ rmq_succinct_sct<> rmq;
+ csa_wt<wt_huff<>, 1,1<<20 > tmp_csa;
+ if (!load_from_file(rmq, rmq_file)) {
+ ifstream in(argv[1]);
+ if (!in) {
+ cout << "ERROR: File " << argv[1] << " does not exist. Exit." << endl;
+ return 1;
+ }
+ cout << "No index "<<rmq_file<< " located. Building index now." << endl;
+ construct(tmp_csa, argv[1], 1);
+ util::assign(rmq, rmq_succinct_sct<>(&tmp_csa));
+ store_to_file(rmq, rmq_file);
+ }
+ double index_size = size_in_mega_bytes(fm_index) + size_in_mega_bytes(rmq);
+ cout << "Index construction complete, index requires " << index_size << " MiB." << endl;
+ cout << "Input search terms and press Ctrl-D to exit." << endl;
+ string prompt = "\e[0;32m>\e[0m ";
+ cout << prompt;
+ string query;
+ while (getline(cin, query)) {
+ size_type m = query.size();
+ size_type lb = 0, rb=0; // left and right bound of the matching interval in the suffix array
+ size_t occs = backward_search(fm_index, 0, fm_index.size()-1, query.begin(), query.end(), lb, rb);
+ cout << "# of occurrences: " << occs << endl;
+ if (occs > 0) {
+ cout << "Location and context of first occurrences: " << endl;
+ size_t min_idx = rmq(lb, rb);
+ size_t min_val = fm_index[min_idx];
+ priority_queue<interval, vector<interval>, greater<interval> > pq; // min-heap
+ pq.push(interval(lb, rb, min_val, min_idx));
+ for (size_t i = 0, pre_extract = pre_context, post_extract = post_context; i < min(occs, max_locations); ++i) {
+ interval r = pq.top(); pq.pop();
+ size_t location = r.min_val;
+ if (r.min_idx > r.lb) {
+ min_idx = rmq(r.lb, r.min_idx-1);
+ pq.push(interval(r.lb, r.min_idx-1, fm_index[min_idx], min_idx));
+ }
+ if (r.min_idx < r.rb) {
+ min_idx = rmq(r.min_idx+1, r.rb);
+ pq.push(interval(r.min_idx+1, r.rb, fm_index[min_idx], min_idx));
+ }
+ cout << setw(8) << location << ": ";
+ if (pre_extract > location) {
+ pre_extract = location;
+ }
+ if (location+m+ post_extract > fm_index.size()) {
+ post_extract = fm_index.size()-location-m;
+ }
+ auto s = extract(fm_index, location-pre_extract, location+m+ post_extract-1);
+ string pre = s.substr(0, pre_extract);
+ s = s.substr(pre_extract);
+ if (pre.find_last_of('\n') != string::npos) {
+ pre = pre.substr(pre.find_last_of('\n')+1);
+ }
+ cout << pre;
+ cout << "\e[1;31m";
+ cout << s.substr(0, m);
+ cout << "\e[0m";
+ string context = s.substr(m);
+ cout << context.substr(0, context.find_first_of('\n')) << endl;
+ }
+ }
+ cout << prompt;
+ }
+ cout << endl;
+}
+
diff --git a/examples/hugepages.cpp b/examples/hugepages.cpp
new file mode 100644
index 0000000..493be83
--- /dev/null
+++ b/examples/hugepages.cpp
@@ -0,0 +1,44 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+template<class t_cst>
+void do_something(const t_cst& cst)
+{
+ uint64_t sum=0;
+ auto start = timer::now();
+ for (size_t i=0; i<cst.csa.size() and i<50000000; ++i) {
+ sum+=cst.csa.lf[i];
+ }
+ auto stop = timer::now();
+ cout << "runtime in seconds: " << duration_cast<seconds>(stop-start).count() << endl;
+ cout << "sum="<<sum<<endl;
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " file <use_hugepages>" << endl;
+ cout << " (1) Creates a CST for a byte file. " << endl;
+ cout << " (2) Runs a benchmark with enabled/disabled hugepages." << endl;
+ return 1;
+ }
+
+ if (argc==3) {
+ // memory_manager::use_hugepages(500ULL*1024ULL*1024ULL);
+ // use all available hugepages if nothing is specified
+ memory_manager::use_hugepages();
+ }
+
+ cst_sct3<> cst;
+ auto start = timer::now();
+ construct(cst, argv[1], 1);
+ auto stop = timer::now();
+ cout << "construction time in seconds: " << duration_cast<seconds>(stop-start).count() << endl;
+ do_something(cst); // before it is mapped
+}
diff --git a/examples/int-vector-buffer-iterator.cpp b/examples/int-vector-buffer-iterator.cpp
new file mode 100644
index 0000000..3b1d76d
--- /dev/null
+++ b/examples/int-vector-buffer-iterator.cpp
@@ -0,0 +1,22 @@
+#include <sdsl/vectors.hpp>
+#include <iostream>
+#include <algorithm>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ string file = "int_vector_buffer_iterator.sdsl";
+ {
+ int_vector<> iv = {1,2,3,4,5,9,8,7,6};
+ store_to_file(iv, file);
+ }
+ int_vector_buffer<> ivb(file);
+ cout << std::accumulate(ivb.begin(), ivb.end(), 0) << endl;
+ cout << std::count_if(ivb.begin(), ivb.end(), [](uint64_t x) {
+ return 0 == x%2;
+ }) << endl;
+}
+
+
diff --git a/examples/int-vector-buffer.cpp b/examples/int-vector-buffer.cpp
new file mode 100644
index 0000000..697305e
--- /dev/null
+++ b/examples/int-vector-buffer.cpp
@@ -0,0 +1,61 @@
+#include <sdsl/int_vector_buffer.hpp>
+#include <string>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 1) {
+ cout << "Usage: " << argv[0] << endl;
+ cout << "(1) Writes an int_vector sequentially to a file" << endl;
+ cout << "(2) Streams the content from file" << endl;
+ cout << "(3) Remove the file" << endl;
+ return 1;
+ }
+ string tmp_file = "tmp_file.sdsl";
+ size_t size = 10000000;
+ std::mt19937_64 rng(13);
+
+ // (1) Writes an int_vector sequentially to the file tmp_file
+ {
+ // create an int_vector_buffer
+ int_vector_buffer<> ivb(tmp_file, // filename
+ std::ios::out, // we do not want to open an existing file, but create a new one
+ 1024*1024, // use a buffer of about 1MB
+ 64, // use 64bit for each integer
+ false); // use int_vector format
+
+ // write sequentially random values to disk
+ for (uint64_t i=0; i<size; ++i) {
+ ivb[i] = rng();
+ }
+ }
+
+ // (2) Streams the content of tmp_file
+ {
+ // open file with an int_vector_buffer.
+ // Default is: open existing file, use 1MB Buffer, 64bit for each integer and int_vector format
+ int_vector_buffer<> ivb(tmp_file);
+ if (!ivb.is_open()) {
+ std::cerr << "ERROR: ivb could not be opend with file " << tmp_file << size << std::endl;
+ return 1;
+ }
+ if (ivb.size() != size) {
+ std::cerr << "ERROR: ivb.size()="<< ivb.size() << " != " << size << std::endl;
+ return 1;
+ }
+ rng.seed(13); // To get the same values than before use the same seed
+ for (uint64_t i=0; i<ivb.size(); ++i) {
+ uint64_t expected_value = rng();
+ if (ivb[i] != expected_value) {
+ std::cerr << "ERROR: ivb["<< i << "]=" << ivb[i] << " != " << expected_value << "= expected_value" << std::endl;
+ return 1;
+ }
+ }
+ ivb.close(true); // close buffer and (3) remove the file
+ }
+
+ return 0;
+}
diff --git a/examples/int-vector-entry.cpp b/examples/int-vector-entry.cpp
new file mode 100644
index 0000000..0c88966
--- /dev/null
+++ b/examples/int-vector-entry.cpp
@@ -0,0 +1,40 @@
+//! Program for debugging. Load vector v of type int_vector<> from
+// file argv[1]. Then the program outputs for each integer i,
+// which is read from stdin, the value v[i].
+#include <sdsl/int_vector.hpp>
+#include <iostream>
+#include <string>
+
+using namespace std;
+using namespace sdsl;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " file [lb] [rb]" << endl;
+ cout << " Reads a serialized int_vector<> from disk." <<endl;
+ cout << " Outputs elements in the range [lb..rb], if specified." << endl;
+ cout << " Otherwise, reads indexes from stdin and outputs values. "<<endl;
+ }
+ int_vector<> v;
+ load_from_file(v, argv[1]);
+ cout<<"loaded int_vector<> containing "<<v.size()<<" "<<
+ (int)v.width()<<"-bit integers"<<endl;
+ if (argc>3) {
+ size_t a=stoull(argv[2]);;
+ size_t b=stoull(argv[3]);
+ if (b >= v.size())
+ b = v.size()-1;
+ if (a > b)
+ a = b;
+ for (size_t i=a; i<=b; ++i) {
+ cout<<"v["<<i<<"]="<<v[i]<<endl;
+ }
+ } else {
+ cout << "Interactive mode." << endl;
+ size_t i;
+ while (cin>>i) {
+ cout<<"v["<<i<<"]="<<v[i]<<endl;
+ }
+ }
+}
diff --git a/examples/int-vector-mapper.cpp b/examples/int-vector-mapper.cpp
new file mode 100644
index 0000000..7c55a4f
--- /dev/null
+++ b/examples/int-vector-mapper.cpp
@@ -0,0 +1,88 @@
+#include <sdsl/int_vector_mapper.hpp>
+#include <string>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 1) {
+ cout << "Usage: " << argv[0] << endl;
+ cout << "(1) Writes an int_vector sequentially to a file" << endl;
+ cout << "(2) Streams the content from file" << endl;
+ cout << "(3) Remove the file" << endl;
+ return 1;
+ }
+ string tmp_file = "tmp_file.sdsl";
+ size_t size = 10000000;
+ std::mt19937_64 rng(13);
+ uint8_t width = 0;
+ int_vector<> iv(size,0,64);
+ int_vector<64> ivf(size,0);
+ std::vector<uint64_t> stdv(size,0);
+
+ // (1) write an int vector to disk
+ {
+ // write sequentially random values to disk
+ for (uint64_t i=0; i<size; ++i) {
+ iv[i] = rng();
+ stdv[i] = iv[i];
+ ivf[i] = iv[i];
+ }
+
+ util::bit_compress(iv);
+ width = iv.width();
+ store_to_file(iv,tmp_file);
+ }
+
+ // (2) memory map the content of tmp_file
+ {
+ int_vector_mapper<> ivm(tmp_file);
+ if (ivm.size() != size) {
+ std::cerr << "ERROR: ivm.size()="<< ivm.size() << " != " << size << std::endl;
+ return 1;
+ }
+ if (ivm.width() != width) {
+ std::cerr << "ERROR: ivm.width()="<< ivm.width() << " != " << width << std::endl;
+ return 1;
+ }
+ rng.seed(13); // To get the same values than before use the same seed
+ for (uint64_t i=0; i<ivm.size(); ++i) {
+ uint64_t expected_value = rng();
+ if (ivm[i] != expected_value) {
+ std::cerr << "ERROR: ivm["<< i << "]=" << ivm[i] << " != " << expected_value << "= expected_value" << std::endl;
+ return 1;
+ }
+ }
+
+ if(ivm != stdv) {
+ std::cerr << "ERROR: std::vector CMP failed.";
+ }
+ if(ivm != iv) {
+ std::cerr << "ERROR: iv CMP failed.";
+ }
+ if(ivm != ivf) {
+ std::cerr << "ERROR: ivf CMP failed.";
+ }
+ }
+
+ // (3) remove the file as the mapper does not do that
+ {
+ sdsl::remove(tmp_file);
+ }
+
+ {
+ auto tmp_buf = temp_file_buffer<64>::create();
+ for(const auto& val : stdv) {
+ tmp_buf.push_back(val);
+ }
+ if(tmp_buf != stdv) {
+ std::cerr << "ERROR: tmp_buf CMP failed." << std::endl;
+ }
+
+ // tmp buf file is deleted automatically
+ }
+
+ return 0;
+}
diff --git a/examples/intersect.cpp b/examples/intersect.cpp
new file mode 100644
index 0000000..47281c0
--- /dev/null
+++ b/examples/intersect.cpp
@@ -0,0 +1,21 @@
+#include <sdsl/wavelet_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ wt_int<> wt;
+ //0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
+ construct_im(wt, int_vector<> {1,2,2,4,5,3,2,4,5,3,2,4,7,4,2,52,7,4,2,1,5,74,3});
+
+ cout << "wt = " << wt << endl;
+ cout << "wt[0,3] intersect with wt[7,10]" << endl;
+ auto res = intersect(wt, {{0,3},{7,10}});
+ cout << "element : sum of occurrences in ranges" << endl;
+for (auto x : res) {
+ cout << x.first << " : " << x.second <<endl;
+ }
+
+}
diff --git a/examples/k2_treap_in_mem.cpp b/examples/k2_treap_in_mem.cpp
new file mode 100644
index 0000000..7a913b6
--- /dev/null
+++ b/examples/k2_treap_in_mem.cpp
@@ -0,0 +1,53 @@
+#include <iostream>
+#include <vector>
+#include <tuple>
+#include <string>
+#include <complex>
+#include <sdsl/k2_treap.hpp>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ typedef k2_treap<3,rrr_vector<63>> k2_rrr;
+ k2_rrr k2treap;
+
+ // Initialize treap with a vector of (x,y,weight) elements
+ construct_im(k2treap, {{1,2,3},{2,2,6},{4,4,1},{3,3,2},{3,1,8}});
+
+ cout << "Points in the k2treap: " << k2treap.size() << endl;
+
+ cout << "Points in the rectangle from (2,1) to (3,3): " ;
+ cout << count(k2treap, {2,1}, {3,3}) << endl;
+
+ cout << "Heaviest points in rectangle from (0,0) to (2,8):" << endl;
+ auto topk_it = top_k(k2treap, {0,0}, {2,8});
+ while (topk_it) {
+ auto point_weight = *topk_it;
+ cout << point_weight.first <<" weight: "<<point_weight.second << endl;
+ ++topk_it;
+ }
+
+ cout << "Report all points in rectangle from (2,2) to (10,10)" << endl;
+ cout << "with weight in [2..6]:" << endl;
+ auto range_it = range_3d(k2treap, {2,2}, {10,10}, {2,100});
+ while (range_it) {
+ auto point_weight = *range_it;
+ cout << point_weight.first <<" weight: "<<point_weight.second << endl;
+ ++range_it;
+ }
+
+ cout<<"---"<<endl;
+ {
+ k2_rrr k2t;
+ construct_im(k2t, {{1,2,3},{2,3,3},{3,1,3}});
+ auto topk_it = top_k(k2t, {0,0}, {10,10});
+ while (topk_it) {
+ auto point_weight = *topk_it;
+ cout << point_weight.first <<" weight: "<<point_weight.second << endl;
+ ++topk_it;
+ }
+ }
+}
diff --git a/examples/louds-tree.cpp b/examples/louds-tree.cpp
new file mode 100644
index 0000000..a01d1a4
--- /dev/null
+++ b/examples/louds-tree.cpp
@@ -0,0 +1,55 @@
+#include <iostream>
+#include <string>
+#include <sdsl/util.hpp>
+#include <sdsl/suffix_trees.hpp>
+#include <sdsl/louds_tree.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+typedef cst_sct3<> cst_t;
+typedef cst_t::node_type node_t;
+
+
+void print_tree(const louds_tree<>& tree, const louds_tree<>::node_type& v, int depth, bit_vector& visited)
+{
+ typedef louds_tree<>::node_type louds_node_t;
+ for (int i=0; i < depth; ++i) cout << " ";
+ cout << v << " tree.id(v) = " << tree.id(v) << endl;
+ visited[tree.id(v)] = 1;
+ for (uint64_t i = 1; i <= tree.degree(v); ++i) {
+ louds_node_t child = tree.child(v, i);
+ print_tree(tree, child, depth+1, visited);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: "<<argv[0]<< " file [max_print=80]" << std::endl;
+ cout << " (1) Builds the CST of file" << std::endl;
+ cout << " (2) Builds a LOUDS tree " << std::endl;
+ cout << " (3) Prints information about the tree, if file size < 59." << std::endl;
+ return 1;
+ }
+ string file = argv[1];
+ cout << file << endl;
+ cst_t cst;
+ construct(cst, file, 1);
+ uint64_t max_print = 80;
+ if (argc > 2) {
+ max_print = stoull(argv[2]);
+ }
+
+ typedef cst_bfs_iterator<cst_t> iterator;
+ iterator begin = iterator(&cst, cst.root());
+ iterator end = iterator(&cst, cst.root(), true, true);
+
+ louds_tree<> louds(cst, begin, end);
+ if (cst.size() <= max_print+1) {
+ cout << "LOUDS = " << louds.bv << endl;
+ bit_vector visited(louds.nodes(), 0);
+ print_tree(louds, louds.root(), 0, visited);
+ cout << "visited = " << visited << endl;
+ }
+}
diff --git a/examples/memory-visualization.cpp b/examples/memory-visualization.cpp
new file mode 100644
index 0000000..101e5f5
--- /dev/null
+++ b/examples/memory-visualization.cpp
@@ -0,0 +1,50 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " file" << endl;
+ cout << " Creates a CST and CSA for a byte file and visualizes the memory utilization during construction." << endl;
+ return 1;
+ }
+
+ memory_monitor::start();
+
+ cst_sct3<> cst;
+ auto start = timer::now();
+ construct(cst, argv[1], 1);
+ auto stop = timer::now();
+ cout << "construction cst time in seconds: " << duration_cast<seconds>(stop-start).count() << endl;
+
+ memory_monitor::stop();
+
+ std::cout << "peak usage = " << memory_monitor::peak() / (1024*1024) << " MB" << std::endl;
+
+ std::ofstream cstofs("cst-construction.html");
+ cout << "writing memory usage visualization to cst-construction.html\n";
+ memory_monitor::write_memory_log<HTML_FORMAT>(cstofs);
+ cstofs.close();
+ util::clear(cst);
+
+ memory_monitor::start();
+
+ csa_wt<> csa;
+ start = timer::now();
+ construct(csa, argv[1], 1);
+ stop = timer::now();
+ cout << "construction csa time in seconds: " << duration_cast<seconds>(stop-start).count() << endl;
+
+ memory_monitor::stop();
+ std::ofstream csaofs("csa-construction.html");
+ cout << "writing memory usage visualization to csa-construction.html\n";
+ memory_monitor::write_memory_log<HTML_FORMAT>(csaofs);
+ csaofs.close();
+
+}
diff --git a/examples/node_iterator.cpp b/examples/node_iterator.cpp
new file mode 100644
index 0000000..15f3d74
--- /dev/null
+++ b/examples/node_iterator.cpp
@@ -0,0 +1,39 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+template<class t_cst>
+void output_node(const typename t_cst::node_type& v, const t_cst& cst)
+{
+ cout << cst.depth(v) << "-[" << cst.lb(v) << ","
+ << cst.rb(v) << "]" << endl;
+}
+
+template<class t_cst>
+void run()
+{
+ t_cst cst;
+ construct_im(cst, "ananas", 1);
+ for (auto v : cst) {
+ output_node(v, cst);
+ }
+ cout<<"--"<<endl;
+ auto v = cst.select_leaf(2);
+ for (auto it = cst.begin(v); it != cst.end(v); ++it) {
+ output_node(*it, cst);
+ }
+ cout<<"--"<<endl;
+ v = cst.parent(cst.select_leaf(4));
+ for (auto it = cst.begin(v); it != cst.end(v); ++it) {
+ output_node(*it, cst);
+ }
+ cout<<"---"<<endl;
+}
+
+int main()
+{
+ run<cst_sct3<>>();
+ run<cst_sada<>>();
+}
diff --git a/examples/range-minimum-queries.cpp b/examples/range-minimum-queries.cpp
new file mode 100644
index 0000000..827b8cb
--- /dev/null
+++ b/examples/range-minimum-queries.cpp
@@ -0,0 +1,51 @@
+#include <sdsl/rmq_support.hpp> // include header for range minimum queries
+#include <iostream>
+#include <cstdlib>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ uint64_t len = 50;
+ if (argc > 1) {
+ len = stoull(argv[1]);
+ }
+ int_vector<> v(len, 7); // create a vector of length 50
+ for (uint64_t i=1; i < v.size(); ++i) {
+ uint64_t x = v[i-1];
+ v[i] = (x*7-1) % 97;
+ }
+ cout << "size_in_bytes(v)=" << size_in_bytes(v) << endl;
+
+ rmq_succinct_sct<> rmq(&v);
+ cout << "size_in_bytes(rmq)/v.size()=" << ((double)size_in_bytes(rmq))/v.size() << endl;
+
+ if (v.size() < 100) { // if the vector is small
+ cout << "v = " << v << endl; // output it
+ }
+ uint64_t left = 0, right = v.size()-1;
+
+ // rmq does not need v to answer the queries
+ util::clear(v); // so we can free the space for v
+
+ uint64_t count = 0;
+
+ while (left < right) {
+ uint64_t min_pos = rmq(left, right);
+ if (++count < 10) {
+ cout << "minimum of v[" << left << "..." << right << "] at index ";
+ cout << min_pos << endl;
+ }
+ if (min_pos - left > right - min_pos) {
+ right = min_pos - 1;
+ } else {
+ left = min_pos + 1;
+ }
+ }
+ cout << endl;
+ cout << "write_structure<JSON_FORMAT>:" << endl;
+ cout << "----------------------------- " << endl;
+ write_structure<JSON_FORMAT>(rmq, cout);
+ cout << endl;
+}
diff --git a/examples/sa-construct-space-efficient.cpp b/examples/sa-construct-space-efficient.cpp
new file mode 100644
index 0000000..108a59f
--- /dev/null
+++ b/examples/sa-construct-space-efficient.cpp
@@ -0,0 +1,43 @@
+#include <iostream>
+#include <fstream>
+#include <sdsl/construct.hpp>
+
+using namespace sdsl;
+using namespace std;
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+int main(int argc, char** argv)
+{
+ // Check Parameters
+ if (argc!=2) {
+ cout << "Usage: " << argv[0] << " file" << endl;
+ cout << " Computes the SA from file space efficiently." << endl;
+ cout << " Result is stored in `sa_<file>.sdsl`." << endl;
+ return 1;
+ }
+
+ cache_config config(false, ".", util::basename(argv[1]));
+
+ int_vector<8> text;
+ load_vector_from_file(text, argv[1], 1);
+ append_zero_symbol(text);
+ auto n = text.size();
+ store_to_cache(text, conf::KEY_TEXT, config);
+ util::clear(text);
+
+ cout << "Calculate suffix array ... " << flush;
+ construct_config::byte_algo_sa = SE_SAIS; // or LIBDIVSUFSORT for less space-efficient but faster construction
+ memory_monitor::start();
+ auto start = timer::now();
+ construct_sa<8>(config);
+ auto stop = timer::now();
+ memory_monitor::stop();
+ cout << "done." << endl;
+ cout << "Construction needed:" << endl;
+ cout << duration_cast<seconds>(stop-start).count() << " seconds." << endl;
+ cout << memory_monitor::peak() << " bytes." << endl;
+ cout << (1.0*memory_monitor::peak())/n << " bytes per input byte." << endl;
+ sdsl::remove(cache_file_name(conf::KEY_TEXT, config));
+ return 0;
+}
diff --git a/examples/sa-int-construct-from-file.cpp b/examples/sa-int-construct-from-file.cpp
new file mode 100644
index 0000000..d8de72d
--- /dev/null
+++ b/examples/sa-int-construct-from-file.cpp
@@ -0,0 +1,44 @@
+#include <iostream>
+#include <fstream>
+#include <sdsl/suffix_trees.hpp>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc > 1) {
+ string file = string(argv[1]);
+ string ofile = file + ".sa";
+ if (argc > 2) {
+ ofile = argv[2];
+ }
+ int_vector<> sa;
+ {
+ int_vector<64> temp;
+ load_vector_from_file(temp, file, 8);
+ cout << "input elements = " << temp.size() << endl;
+ if (temp.size()==0 or temp[temp.size()-1] != 0) {
+ cout << "Add 0 to input `" << file << "`" << endl;
+ temp.resize(temp.size()+1);
+ temp[temp.size()-1] = 0;
+ store_to_plain_array<uint64_t>(temp, file);
+ }
+ }
+ qsufsort::construct_sa(sa, file.c_str(), 8);
+ cout << "done" << endl;
+ cout << "sa.size()="<<sa.size() << endl;
+ cout << "sa.width()=" <<(int)sa.width() << endl;
+ cout << "bit_compress..." << endl;
+ util::bit_compress(sa);
+ cout << "sa.width()=" <<(int)sa.width() << endl;
+ store_to_file(sa, ofile);
+ } else {
+ cout << "Usage: " << argv[0] << " file [ofile]" << endl;
+ cout << " Computes the SA from an array of 64-bit integers." << endl;
+ cout << " Result is stored in `ofile`, or `file`.sa if `ofile`" << endl;
+ cout << " is not specified." << endl;
+ }
+}
+
+
diff --git a/examples/sd_vector_benchmark.cpp b/examples/sd_vector_benchmark.cpp
new file mode 100644
index 0000000..cfdf4fb
--- /dev/null
+++ b/examples/sd_vector_benchmark.cpp
@@ -0,0 +1,122 @@
+#include <sdsl/bit_vectors.hpp>
+#include <random>
+#include <iostream>
+#include <chrono>
+
+using namespace sdsl;
+using namespace std;
+
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+
+template<class t_vec>
+uint64_t test_inv_random_access(const t_vec& v, const int_vector<64>& rands, uint64_t mask, uint64_t times=100000000)
+{
+ uint64_t cnt=0;
+ for (uint64_t i=0; i<times; ++i) {
+ cnt += v(rands[ i&mask ]);
+ }
+ return cnt;
+}
+
+
+
+//int main(int argc, char* argv[]){
+int main()
+{
+ auto start = timer::now();
+ bool default_value = 0; //ID[ID.length()-1]-'0';
+ bit_vector bv = bit_vector(800000000, default_value);
+
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, bv.size()-1);
+ auto dice = bind(distribution, rng);
+ // populate vectors with some other bits
+ for (uint64_t i=0; i < bv.size()/25; ++i) {
+ uint64_t x = dice();
+ bv[x] = !default_value;
+ }
+ auto stop = timer::now();
+ cout << "initialization in (ms): " << duration_cast<milliseconds>(stop-start).count() << endl;
+ cout << "size in MiB: " << size_in_mega_bytes(bv) << endl;
+
+ start = timer::now();
+ sd_vector<> bv_sd(bv);
+ stop = timer::now();
+ cout << "sd_construction in (ms): " << duration_cast<milliseconds>(stop-start).count() << endl;
+ {
+ bit_vector().swap(bv);
+ }
+ cout << "size in MiB: " << size_in_mega_bytes(bv_sd) << endl;
+ cout << "wl = " << (size_t) bv_sd.wl << endl;
+ cout << "n = " << bv_sd.size() << endl;
+ cout << "2*m = " << bv_sd.high.size()<<endl;
+ cout <<"n/m=" << (2.0*bv_sd.size())/bv_sd.high.size()<<endl;
+
+ auto zeros = sd_vector<>::rank_0_type(&bv_sd)(bv_sd.size());
+ auto ones = bv_sd.size()-zeros;
+ cout << "zeros = "<< zeros << endl;
+ {
+ uint64_t mask = 0;
+ auto rands = util::rnd_positions<int_vector<64>>(20, mask, zeros, 17);
+ for (uint64_t i=0; i<rands.size(); ++i) rands[i] = rands[i]+1;
+ sd_vector<>::select_0_type select0(&bv_sd);
+ const uint64_t reps = 10000000;
+ start = timer::now();
+ auto check = test_inv_random_access(select0, rands, mask, reps);
+ stop = timer::now();
+
+ cout << "# select0_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# select_check = " << check << endl;
+ cout << "# size_in_mega_bytes(bv_sd) = " << size_in_mega_bytes(bv_sd) << endl;
+ cout << "# size_in_mega_bytes(select0) = " << size_in_mega_bytes(select0) << endl;
+ }
+ {
+ uint64_t mask = 0;
+ auto rands = util::rnd_positions<int_vector<64>>(20, mask, zeros, 17);
+ for (uint64_t i=0; i<rands.size(); ++i) rands[i] = rands[i]+1;
+ select_0_support_sd<sd_vector<>> select0(&bv_sd);
+ const uint64_t reps = 10000000;
+ start = timer::now();
+ auto check = test_inv_random_access(select0, rands, mask, reps);
+ stop = timer::now();
+
+ cout << "# select0_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# select_check = " << check << endl;
+ cout << "# size_in_mega_bytes(bv_sd) = " << size_in_mega_bytes(bv_sd) << endl;
+ cout << "# size_in_mega_bytes(select0) = " << size_in_mega_bytes(select0) << endl;
+ }
+ {
+ uint64_t mask = 0;
+ auto rands = util::rnd_positions<int_vector<64>>(20, mask, ones, 17);
+ for (uint64_t i=0; i<rands.size(); ++i) rands[i] = rands[i]+1;
+ sd_vector<>::select_1_type select1(&bv_sd);
+ const uint64_t reps = 10000000;
+ start = timer::now();
+ auto check = test_inv_random_access(select1, rands, mask, reps);
+ stop = timer::now();
+
+ cout << "# select1_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# select_check = " << check << endl;
+ }
+ {
+ uint64_t mask = 0;
+ auto rands = util::rnd_positions<int_vector<64>>(20, mask, bv_sd.size(), 17);
+ cout<<"done"<<endl;
+ cout<<(uint64_t)&(bv_sd.high_1_select)<<endl;
+ cout<<(uint64_t)&(bv_sd.high_0_select)<<endl;
+ sd_vector<>::rank_1_type rank1(&bv_sd);
+ cout<<"done"<<endl;
+ const uint64_t reps = 10000000;
+// for(size_t i=0; i<bv_sd.size();++i){
+// cout << "i="<<i<<" rank1("<<i<<")="<<rank1(i)<<endl;
+// }
+ start = timer::now();
+ auto check = test_inv_random_access(rank1, rands, mask, reps);
+ stop = timer::now();
+
+ cout << "# rank1_time = " << duration_cast<nanoseconds>(stop-start).count()/(double)reps << endl;
+ cout << "# select_check = " << check << endl;
+ }
+}
diff --git a/examples/storage-visualization.cpp b/examples/storage-visualization.cpp
new file mode 100644
index 0000000..e081254
--- /dev/null
+++ b/examples/storage-visualization.cpp
@@ -0,0 +1,26 @@
+#include <sdsl/suffix_trees.hpp>
+#include <sdsl/io.hpp>
+#include <iostream>
+#include <chrono>
+
+using timer = std::chrono::high_resolution_clock;
+using namespace std::chrono;
+using namespace sdsl;
+
+int main(int argc, char** argv)
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " file" << std::endl;
+ cout << " Creates a CST for a byte file and visualizes the space used by the data structure." << std::endl;
+ return 1;
+ }
+ cst_sct3<> cst;
+ auto start = timer::now();
+ cout << "constructing cst..." << std::endl;
+ construct(cst, argv[1], 1);
+ cout << "construction cst time in seconds: " << duration_cast<seconds>(timer::now()-start).count() << std::endl;
+
+ std::ofstream ofs("cst-space-usage.html");
+ std::cout << "writing storage visualization to cst-space-usage.html" << std::endl;
+ sdsl::write_structure<HTML_FORMAT>(cst,ofs);
+}
diff --git a/examples/store_to_file.cpp b/examples/store_to_file.cpp
new file mode 100644
index 0000000..869a48e
--- /dev/null
+++ b/examples/store_to_file.cpp
@@ -0,0 +1,44 @@
+#include <sdsl/vectors.hpp>
+#include <fstream>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ cout << (has_serialize<bit_vector>::value) << endl;
+ cout << (has_serialize<uint64_t>::value) << endl;
+
+ {
+ ofstream out("data.sdsl");
+ bit_vector b = {1,0,0,0,1,1,0};
+ serialize(b, out);
+ }
+ {
+ ifstream in("data.sdsl");
+ bit_vector b;
+ load(b, in);
+ cout << b << endl;
+ }
+ {
+ uint64_t x = 42;
+ store_to_file(x, "data.sdsl");
+ }
+ {
+ uint64_t x = 0;
+ load_from_file(x, "data.sdsl");
+ cout << x << endl;
+ }
+ {
+ std::vector<uint32_t> x(10, 5);
+ store_to_file(x, "data.sdsl");
+ }
+ {
+ std::vector<uint32_t> x;
+ load_from_file(x, "data.sdsl");
+ cout << x.size() << endl;
+ for (size_t i=0; i<x.size(); ++i)
+ cout << x[i] << endl;
+ }
+}
diff --git a/examples/text-statistics.cpp b/examples/text-statistics.cpp
new file mode 100644
index 0000000..bff1028
--- /dev/null
+++ b/examples/text-statistics.cpp
@@ -0,0 +1,41 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+typedef cst_sct3<> cst_t;
+typedef cst_t::char_type char_type;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: "<< argv[0] << " file" << endl;
+ cout << "(1) Generates the CST of file." << endl;
+ cout << "(2) Calculates the avg LCP value and the runs in the BWT." << endl;
+ return 1;
+ }
+ cst_t cst;
+ construct(cst, argv[1], 1);
+
+ long double runs = 1;
+ long double avg_lcp = 0;
+ if (cst.csa.size()) {
+ char_type prev_bwt = cst.csa.bwt[0];
+ for (uint64_t i=1; i<cst.csa.size(); ++i) {
+ char_type bwt = cst.csa.bwt[i];
+ if (prev_bwt != bwt) {
+ runs += 1.0;
+ }
+ prev_bwt = bwt;
+ avg_lcp += cst.lcp[i];
+ }
+ avg_lcp /= cst.csa.size();
+ for (size_t k=0; k<=5; k++) {
+ cout << "H_" << k << ": " << Hk(cst,k).first << endl;
+ }
+ cout << "avg LCP: " << avg_lcp << endl;
+ cout << "runs in BWT: " << runs << endl;
+
+ }
+}
diff --git a/examples/uint64-array2int_vector.cpp b/examples/uint64-array2int_vector.cpp
new file mode 100644
index 0000000..7029404
--- /dev/null
+++ b/examples/uint64-array2int_vector.cpp
@@ -0,0 +1,75 @@
+/*
+ * Transforms a sequence of 64-bit integers into a bit-compressed integer vector.
+ * The first command line parameter argv[1] specifies the file, which contains the sequence
+ * of integers.
+ * The bit-compressed integer vector is stored in a file called `argv[1].int_vector`.
+ */
+#include <sdsl/util.hpp>
+#include <sdsl/int_vector.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " int_file" << endl;
+ return 1;
+ }
+
+ size_t x = util::file_size(argv[1]);
+ const int BPI=8;
+ cout<<"file size in bytes = "<<x<<endl;
+ if (x % BPI != 0) {
+ cout << "Error: x%"<<BPI<<" != 0"<<endl;
+ return 1;
+ }
+// (1) scan file and determine the largest value
+ int_vector_buffer<64> ivb(string(argv[1]), std::ios::in, 6400000, 64, true);
+ if (!ivb.is_open()) {
+ cout<<"ERROR: could not open file "<<argv[1]<<endl;
+ return 1;
+ }
+ uint64_t max=0;
+ for (size_t i=0; i<ivb.size(); ++i) {
+ if (ivb[i] > max)
+ max = ivb[i];
+ }
+ cout<<"Max value: "<<max<<endl;
+ uint8_t width = bits::hi(max)+1;
+ cout<<"width="<<(int)width<<endl;
+
+// (2) scan file, bit-compress values and write to outfile
+ string ofile = string(argv[1])+".int_vector";
+ int_vector_buffer<> ivb2(ofile, std::ios::out, 6400000, width);
+ if (!ivb2.is_open()) {
+ cout<<"ERROR: could not open output file "<<argv[1]<<endl;
+ return 1;
+ }
+ for (size_t i=0; i<ivb.size(); ++i) {
+ ivb2[i] = ivb[i];
+ }
+ ivb.close();
+ ivb2.close();
+
+ int_vector<> v;
+ load_from_file(v, ofile);
+ cout<<"v.size()="<<v.size()<<endl;
+ cout<<"v[0]="<<v[0]<<endl;
+ const bool do_check = false;
+ if (do_check) {
+ int_vector<> check;
+ load_vector_from_file(check, argv[1], BPI);
+ if (check.size() != v.size()) {
+ cout<<"Vectors differ in size: "<<check.size()<<"!="<<v.size()<<endl;
+ return 1;
+ }
+ for (size_t i=0; i<check.size(); ++i) {
+ if (check[i] != v[i]) {
+ cout<<"vectors differ in position "<<i<<": "<<check[i]<<"!="<<v[i]<<endl;
+ }
+ }
+ }
+}
diff --git a/examples/write_structure.cpp b/examples/write_structure.cpp
new file mode 100644
index 0000000..bf4f59f
--- /dev/null
+++ b/examples/write_structure.cpp
@@ -0,0 +1,19 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <fstream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ csa_wt<> csa;
+ construct_im(csa, "This is how it works", 1);
+ // write only one object to std::cout
+ write_structure<HTML_FORMAT>(csa, cout);
+ wt_int<> wt;
+ construct_im(wt, int_vector<>(1000,3));
+ // write multiple objects into one file
+ ofstream out("write_structure.html");
+ write_structure<HTML_FORMAT>(out, csa, wt);
+}
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
new file mode 100644
index 0000000..8b45b68
--- /dev/null
+++ b/external/CMakeLists.txt
@@ -0,0 +1,4 @@
+
+add_subdirectory(gtest-1.6.0)
+add_subdirectory(libdivsufsort-2.0.1)
+
diff --git a/external/gtest-1.6.0/.gitignore b/external/gtest-1.6.0/.gitignore
new file mode 100644
index 0000000..d05f9c0
--- /dev/null
+++ b/external/gtest-1.6.0/.gitignore
@@ -0,0 +1,5 @@
+.svn
+*/.svn
+*/*/.svn
+*/*/*/.svn
+*/*/*/*/.svn
diff --git a/external/gtest-1.6.0/CHANGES b/external/gtest-1.6.0/CHANGES
new file mode 100644
index 0000000..1cfe07a
--- /dev/null
+++ b/external/gtest-1.6.0/CHANGES
@@ -0,0 +1,153 @@
+Changes for 1.7.0:
+
+* New feature: death tests are supported on OpenBSD and in iOS
+ simulator now.
+* New feature: Test::RecordProperty() can now be used outside of the
+ lifespan of a test method, in which case it will be attributed to
+ the current test case or the test program in the XML report.
+* New feature (potentially breaking): --gtest_list_tests now prints
+ the type parameters and value parameters for each test.
+* Improvement: char pointers and char arrays are now escaped properly
+ in failure messages.
+* Improvement: failure summary in XML reports now includes file and
+ line information.
+* Improvement: the <testsuites> XML element now has a timestamp attribute.
+* Improvement: When --gtest_filter is specified, XML report now doesn't
+ contain information about tests that are filtered out.
+* Fixed the bug where long --gtest_filter flag values are truncated in
+ death tests.
+* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a
+ function instead of a macro in order to work better with Clang.
+* Compatibility fixes with C++ 11 and various platforms.
+* Bug/warning fixes.
+
+Changes for 1.6.0:
+
+* New feature: ADD_FAILURE_AT() for reporting a test failure at the
+ given source location -- useful for writing testing utilities.
+* New feature: the universal value printer is moved from Google Mock
+ to Google Test.
+* New feature: type parameters and value parameters are reported in
+ the XML report now.
+* A gtest_disable_pthreads CMake option.
+* Colored output works in GNU Screen sessions now.
+* Parameters of value-parameterized tests are now printed in the
+ textual output.
+* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are
+ now correctly reported.
+* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to
+ ostream.
+* More complete handling of exceptions.
+* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter
+ name is already used by another library.
+* --gtest_catch_exceptions is now true by default, allowing a test
+ program to continue after an exception is thrown.
+* Value-parameterized test fixtures can now derive from Test and
+ WithParamInterface<T> separately, easing conversion of legacy tests.
+* Death test messages are clearly marked to make them more
+ distinguishable from other messages.
+* Compatibility fixes for Android, Google Native Client, MinGW, HP UX,
+ PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear),
+ IBM XL C++ (Visual Age C++), and C++0x.
+* Bug fixes and implementation clean-ups.
+* Potentially incompatible changes: disables the harmful 'make install'
+ command in autotools.
+
+Changes for 1.5.0:
+
+ * New feature: assertions can be safely called in multiple threads
+ where the pthreads library is available.
+ * New feature: predicates used inside EXPECT_TRUE() and friends
+ can now generate custom failure messages.
+ * New feature: Google Test can now be compiled as a DLL.
+ * New feature: fused source files are included.
+ * New feature: prints help when encountering unrecognized Google Test flags.
+ * Experimental feature: CMake build script (requires CMake 2.6.4+).
+ * Experimental feature: the Pump script for meta programming.
+ * double values streamed to an assertion are printed with enough precision
+ to differentiate any two different values.
+ * Google Test now works on Solaris and AIX.
+ * Build and test script improvements.
+ * Bug fixes and implementation clean-ups.
+
+ Potentially breaking changes:
+
+ * Stopped supporting VC++ 7.1 with exceptions disabled.
+ * Dropped support for 'make install'.
+
+Changes for 1.4.0:
+
+ * New feature: the event listener API
+ * New feature: test shuffling
+ * New feature: the XML report format is closer to junitreport and can
+ be parsed by Hudson now.
+ * New feature: when a test runs under Visual Studio, its failures are
+ integrated in the IDE.
+ * New feature: /MD(d) versions of VC++ projects.
+ * New feature: elapsed time for the tests is printed by default.
+ * New feature: comes with a TR1 tuple implementation such that Boost
+ is no longer needed for Combine().
+ * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
+ * New feature: the Xcode project can now produce static gtest
+ libraries in addition to a framework.
+ * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
+ Symbian, gcc, and C++Builder.
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.3.0:
+
+ * New feature: death tests on Windows, Cygwin, and Mac.
+ * New feature: ability to use Google Test assertions in other testing
+ frameworks.
+ * New feature: ability to run disabled test via
+ --gtest_also_run_disabled_tests.
+ * New feature: the --help flag for printing the usage.
+ * New feature: access to Google Test flag values in user code.
+ * New feature: a script that packs Google Test into one .h and one
+ .cc file for easy deployment.
+ * New feature: support for distributing test functions to multiple
+ machines (requires support from the test runner).
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.2.1:
+
+ * Compatibility fixes for Linux IA-64 and IBM z/OS.
+ * Added support for using Boost and other TR1 implementations.
+ * Changes to the build scripts to support upcoming release of Google C++
+ Mocking Framework.
+ * Added Makefile to the distribution package.
+ * Improved build instructions in README.
+
+Changes for 1.2.0:
+
+ * New feature: value-parameterized tests.
+ * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
+ macros.
+ * Changed the XML report format to match JUnit/Ant's.
+ * Added tests to the Xcode project.
+ * Added scons/SConscript for building with SCons.
+ * Added src/gtest-all.cc for building Google Test from a single file.
+ * Fixed compatibility with Solaris and z/OS.
+ * Enabled running Python tests on systems with python 2.3 installed,
+ e.g. Mac OS X 10.4.
+ * Bug fixes.
+
+Changes for 1.1.0:
+
+ * New feature: type-parameterized tests.
+ * New feature: exception assertions.
+ * New feature: printing elapsed time of tests.
+ * Improved the robustness of death tests.
+ * Added an Xcode project and samples.
+ * Adjusted the output format on Windows to be understandable by Visual Studio.
+ * Minor bug fixes.
+
+Changes for 1.0.1:
+
+ * Added project files for Visual Studio 7.1.
+ * Fixed issues with compiling on Mac OS X.
+ * Fixed issues with compiling on Cygwin.
+
+Changes for 1.0.0:
+
+ * Initial Open Source release of Google Test
diff --git a/external/gtest-1.6.0/CMakeLists.txt b/external/gtest-1.6.0/CMakeLists.txt
new file mode 100644
index 0000000..2159f2c
--- /dev/null
+++ b/external/gtest-1.6.0/CMakeLists.txt
@@ -0,0 +1,255 @@
+########################################################################
+# CMake build script for Google Test.
+#
+# To run the tests for Google Test itself on Linux, use 'make test' or
+# ctest. You can select which tests to run using 'ctest -R regex'.
+# For more options, run 'ctest --help'.
+
+# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
+# make it prominent in the GUI.
+option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
+
+# When other libraries are using a shared version of runtime libraries,
+# Google Test also has to use one.
+option(
+ gtest_force_shared_crt
+ "Use shared (DLL) run-time lib even when Google Test is built as static lib."
+ OFF)
+
+option(gtest_build_tests "Build all of gtest's own tests." OFF)
+
+option(gtest_build_samples "Build gtest's sample programs." OFF)
+
+option(gtest_disable_pthreads "Disable uses of pthreads in gtest." ON)
+
+# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build().
+include(cmake/hermetic_build.cmake OPTIONAL)
+
+if (COMMAND pre_project_set_up_hermetic_build)
+ pre_project_set_up_hermetic_build()
+endif()
+
+########################################################################
+#
+# Project-wide settings
+
+# Name of the project.
+#
+# CMake files in this project can refer to the root source directory
+# as ${gtest_SOURCE_DIR} and to the root binary directory as
+# ${gtest_BINARY_DIR}.
+# Language "C" is required for find_package(Threads).
+project(gtest CXX C)
+cmake_minimum_required(VERSION 2.6.2)
+
+if (COMMAND set_up_hermetic_build)
+ set_up_hermetic_build()
+endif()
+
+# Define helper functions and macros used by Google Test.
+include(cmake/internal_utils.cmake)
+
+config_compiler_and_linker() # Defined in internal_utils.cmake.
+
+# Where Google Test's .h files can be found.
+include_directories(
+ ${gtest_SOURCE_DIR}/include
+ ${gtest_SOURCE_DIR})
+
+# Where Google Test's libraries can be found.
+link_directories(${gtest_BINARY_DIR}/src)
+
+########################################################################
+#
+# Defines the gtest & gtest_main libraries. User tests should link
+# with one of them.
+
+# Google Test libraries. We build them using more strict warnings than what
+# are used for other targets, to ensure that gtest can be compiled by a user
+# aggressive about warnings.
+cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
+cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
+target_link_libraries(gtest_main gtest)
+
+add_subdirectory(include)
+
+#install(TARGETS gtest LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+#install(TARGETS gtest_main LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
+
+########################################################################
+#
+# Samples on how to link user tests with gtest or gtest_main.
+#
+# They are not built by default. To build them, set the
+# gtest_build_samples option to ON. You can do it by running ccmake
+# or specifying the -Dgtest_build_samples=ON flag when running cmake.
+
+if (gtest_build_samples)
+ cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc)
+ cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc)
+ cxx_executable(sample3_unittest samples gtest_main)
+ cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc)
+ cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc)
+ cxx_executable(sample6_unittest samples gtest_main)
+ cxx_executable(sample7_unittest samples gtest_main)
+ cxx_executable(sample8_unittest samples gtest_main)
+ cxx_executable(sample9_unittest samples gtest)
+ cxx_executable(sample10_unittest samples gtest)
+endif()
+
+########################################################################
+#
+# Google Test's own tests.
+#
+# You can skip this section if you aren't interested in testing
+# Google Test itself.
+#
+# The tests are not built by default. To build them, set the
+# gtest_build_tests option to ON. You can do it by running ccmake
+# or specifying the -Dgtest_build_tests=ON flag when running cmake.
+
+if (gtest_build_tests)
+ # This must be set in the root directory for the tests to be run by
+ # 'make test' or ctest.
+ enable_testing()
+
+ ############################################################
+ # C++ tests built with standard compiler flags.
+
+ cxx_test(gtest-death-test_test gtest_main)
+ cxx_test(gtest_environment_test gtest)
+ cxx_test(gtest-filepath_test gtest_main)
+ cxx_test(gtest-linked_ptr_test gtest_main)
+ cxx_test(gtest-listener_test gtest_main)
+ cxx_test(gtest_main_unittest gtest_main)
+ cxx_test(gtest-message_test gtest_main)
+ cxx_test(gtest_no_test_unittest gtest)
+ cxx_test(gtest-options_test gtest_main)
+ cxx_test(gtest-param-test_test gtest
+ test/gtest-param-test2_test.cc)
+ cxx_test(gtest-port_test gtest_main)
+ cxx_test(gtest_pred_impl_unittest gtest_main)
+ cxx_test(gtest-printers_test gtest_main)
+ cxx_test(gtest_prod_test gtest_main
+ test/production.cc)
+ cxx_test(gtest_repeat_test gtest)
+ cxx_test(gtest_sole_header_test gtest_main)
+ cxx_test(gtest_stress_test gtest)
+ cxx_test(gtest-test-part_test gtest_main)
+ cxx_test(gtest_throw_on_failure_ex_test gtest)
+ cxx_test(gtest-typed-test_test gtest_main
+ test/gtest-typed-test2_test.cc)
+ cxx_test(gtest_unittest gtest_main)
+ cxx_test(gtest-unittest-api_test gtest)
+
+ ############################################################
+ # C++ tests built with non-standard compiler flags.
+
+ # MSVC 7.1 does not support STL with exceptions disabled.
+ if (NOT MSVC OR MSVC_VERSION GREATER 1310)
+ cxx_library(gtest_no_exception "${cxx_no_exception}"
+ src/gtest-all.cc)
+ cxx_library(gtest_main_no_exception "${cxx_no_exception}"
+ src/gtest-all.cc src/gtest_main.cc)
+ endif()
+ cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
+ src/gtest-all.cc src/gtest_main.cc)
+
+ cxx_test_with_flags(gtest-death-test_ex_nocatch_test
+ "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
+ gtest test/gtest-death-test_ex_test.cc)
+ cxx_test_with_flags(gtest-death-test_ex_catch_test
+ "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
+ gtest test/gtest-death-test_ex_test.cc)
+
+ cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
+ gtest_main_no_rtti test/gtest_unittest.cc)
+
+ cxx_shared_library(gtest_dll "${cxx_default}"
+ src/gtest-all.cc src/gtest_main.cc)
+
+ cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}"
+ gtest_dll test/gtest_all_test.cc)
+ set_target_properties(gtest_dll_test_
+ PROPERTIES
+ COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+
+ if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600)
+ # The C++ Standard specifies tuple_element<int, class>.
+ # Yet MSVC 10's <utility> declares tuple_element<size_t, class>.
+ # That declaration conflicts with our own standard-conforming
+ # tuple implementation. Therefore using our own tuple with
+ # MSVC 10 doesn't compile.
+ cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}"
+ src/gtest-all.cc src/gtest_main.cc)
+
+ cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}"
+ gtest_main_use_own_tuple test/gtest-tuple_test.cc)
+
+ cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}"
+ gtest_main_use_own_tuple
+ test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
+ endif()
+
+ ############################################################
+ # Python tests.
+
+ cxx_executable(gtest_break_on_failure_unittest_ test gtest)
+ py_test(gtest_break_on_failure_unittest)
+
+ # MSVC 7.1 does not support STL with exceptions disabled.
+ if (NOT MSVC OR MSVC_VERSION GREATER 1310)
+ cxx_executable_with_flags(
+ gtest_catch_exceptions_no_ex_test_
+ "${cxx_no_exception}"
+ gtest_main_no_exception
+ test/gtest_catch_exceptions_test_.cc)
+ endif()
+
+ cxx_executable_with_flags(
+ gtest_catch_exceptions_ex_test_
+ "${cxx_exception}"
+ gtest_main
+ test/gtest_catch_exceptions_test_.cc)
+ py_test(gtest_catch_exceptions_test)
+
+ cxx_executable(gtest_color_test_ test gtest)
+ py_test(gtest_color_test)
+
+ cxx_executable(gtest_env_var_test_ test gtest)
+ py_test(gtest_env_var_test)
+
+ cxx_executable(gtest_filter_unittest_ test gtest)
+ py_test(gtest_filter_unittest)
+
+ cxx_executable(gtest_help_test_ test gtest_main)
+ py_test(gtest_help_test)
+
+ cxx_executable(gtest_list_tests_unittest_ test gtest)
+ py_test(gtest_list_tests_unittest)
+
+ cxx_executable(gtest_output_test_ test gtest)
+ py_test(gtest_output_test)
+
+ cxx_executable(gtest_shuffle_test_ test gtest)
+ py_test(gtest_shuffle_test)
+
+ # MSVC 7.1 does not support STL with exceptions disabled.
+ if (NOT MSVC OR MSVC_VERSION GREATER 1310)
+ cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception)
+ set_target_properties(gtest_throw_on_failure_test_
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_no_exception}")
+ py_test(gtest_throw_on_failure_test)
+ endif()
+
+ cxx_executable(gtest_uninitialized_test_ test gtest)
+ py_test(gtest_uninitialized_test)
+
+ cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
+ cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
+ py_test(gtest_xml_outfiles_test)
+
+ cxx_executable(gtest_xml_output_unittest_ test gtest)
+ py_test(gtest_xml_output_unittest)
+endif()
diff --git a/external/gtest-1.6.0/CONTRIBUTORS b/external/gtest-1.6.0/CONTRIBUTORS
new file mode 100644
index 0000000..feae2fc
--- /dev/null
+++ b/external/gtest-1.6.0/CONTRIBUTORS
@@ -0,0 +1,37 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Testing Framework project. People
+# who commit code to the project are encouraged to add their names
+# here. Please keep the list sorted by first names.
+
+Ajay Joshi <jaj at google.com>
+Balázs Dán <balazs.dan at gmail.com>
+Bharat Mediratta <bharat at menalto.com>
+Chandler Carruth <chandlerc at google.com>
+Chris Prince <cprince at google.com>
+Chris Taylor <taylorc at google.com>
+Dan Egnor <egnor at google.com>
+Eric Roman <eroman at chromium.org>
+Hady Zalek <hady.zalek at gmail.com>
+Jeffrey Yasskin <jyasskin at google.com>
+Jói Sigurðsson <joi at google.com>
+Keir Mierle <mierle at gmail.com>
+Keith Ray <keith.ray at gmail.com>
+Kenton Varda <kenton at google.com>
+Manuel Klimek <klimek at google.com>
+Markus Heule <markus.heule at gmail.com>
+Mika Raento <mikie at iki.fi>
+Miklós Fazekas <mfazekas at szemafor.com>
+Pasi Valminen <pasi.valminen at gmail.com>
+Patrick Hanna <phanna at google.com>
+Patrick Riley <pfr at google.com>
+Peter Kaminski <piotrk at google.com>
+Preston Jackson <preston.a.jackson at gmail.com>
+Rainer Klaffenboeck <rainer.klaffenboeck at dynatrace.com>
+Russ Cox <rsc at google.com>
+Russ Rufer <russ at pentad.com>
+Sean Mcafee <eefacm at gmail.com>
+Sigurður Ásgeirsson <siggi at google.com>
+Tracy Bialik <tracy at pentad.com>
+Vadim Berman <vadimb at google.com>
+Vlad Losev <vladl at google.com>
+Zhanyong Wan <wan at google.com>
diff --git a/external/gtest-1.6.0/LICENSE b/external/gtest-1.6.0/LICENSE
new file mode 100644
index 0000000..1941a11
--- /dev/null
+++ b/external/gtest-1.6.0/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/external/gtest-1.6.0/Makefile.am b/external/gtest-1.6.0/Makefile.am
new file mode 100644
index 0000000..788c475
--- /dev/null
+++ b/external/gtest-1.6.0/Makefile.am
@@ -0,0 +1,305 @@
+# Automake file
+
+ACLOCAL_AMFLAGS = -I m4
+
+# Nonstandard package files for distribution
+EXTRA_DIST = \
+ CHANGES \
+ CONTRIBUTORS \
+ LICENSE \
+ include/gtest/gtest-param-test.h.pump \
+ include/gtest/internal/gtest-param-util-generated.h.pump \
+ include/gtest/internal/gtest-tuple.h.pump \
+ include/gtest/internal/gtest-type-util.h.pump \
+ make/Makefile \
+ scripts/fuse_gtest_files.py \
+ scripts/gen_gtest_pred_impl.py \
+ scripts/pump.py \
+ scripts/test/Makefile
+
+# gtest source files that we don't compile directly. They are
+# #included by gtest-all.cc.
+GTEST_SRC = \
+ src/gtest-death-test.cc \
+ src/gtest-filepath.cc \
+ src/gtest-internal-inl.h \
+ src/gtest-port.cc \
+ src/gtest-printers.cc \
+ src/gtest-test-part.cc \
+ src/gtest-typed-test.cc \
+ src/gtest.cc
+
+EXTRA_DIST += $(GTEST_SRC)
+
+# Sample files that we don't compile.
+EXTRA_DIST += \
+ samples/prime_tables.h \
+ samples/sample2_unittest.cc \
+ samples/sample3_unittest.cc \
+ samples/sample4_unittest.cc \
+ samples/sample5_unittest.cc \
+ samples/sample6_unittest.cc \
+ samples/sample7_unittest.cc \
+ samples/sample8_unittest.cc \
+ samples/sample9_unittest.cc
+
+# C++ test files that we don't compile directly.
+EXTRA_DIST += \
+ test/gtest-death-test_ex_test.cc \
+ test/gtest-death-test_test.cc \
+ test/gtest-filepath_test.cc \
+ test/gtest-linked_ptr_test.cc \
+ test/gtest-listener_test.cc \
+ test/gtest-message_test.cc \
+ test/gtest-options_test.cc \
+ test/gtest-param-test2_test.cc \
+ test/gtest-param-test2_test.cc \
+ test/gtest-param-test_test.cc \
+ test/gtest-param-test_test.cc \
+ test/gtest-param-test_test.h \
+ test/gtest-port_test.cc \
+ test/gtest-printers_test.cc \
+ test/gtest-test-part_test.cc \
+ test/gtest-tuple_test.cc \
+ test/gtest-typed-test2_test.cc \
+ test/gtest-typed-test_test.cc \
+ test/gtest-typed-test_test.h \
+ test/gtest-unittest-api_test.cc \
+ test/gtest_break_on_failure_unittest_.cc \
+ test/gtest_catch_exceptions_test_.cc \
+ test/gtest_color_test_.cc \
+ test/gtest_env_var_test_.cc \
+ test/gtest_environment_test.cc \
+ test/gtest_filter_unittest_.cc \
+ test/gtest_help_test_.cc \
+ test/gtest_list_tests_unittest_.cc \
+ test/gtest_main_unittest.cc \
+ test/gtest_no_test_unittest.cc \
+ test/gtest_output_test_.cc \
+ test/gtest_pred_impl_unittest.cc \
+ test/gtest_prod_test.cc \
+ test/gtest_repeat_test.cc \
+ test/gtest_shuffle_test_.cc \
+ test/gtest_sole_header_test.cc \
+ test/gtest_stress_test.cc \
+ test/gtest_throw_on_failure_ex_test.cc \
+ test/gtest_throw_on_failure_test_.cc \
+ test/gtest_uninitialized_test_.cc \
+ test/gtest_unittest.cc \
+ test/gtest_unittest.cc \
+ test/gtest_xml_outfile1_test_.cc \
+ test/gtest_xml_outfile2_test_.cc \
+ test/gtest_xml_output_unittest_.cc \
+ test/production.cc \
+ test/production.h
+
+# Python tests that we don't run.
+EXTRA_DIST += \
+ test/gtest_break_on_failure_unittest.py \
+ test/gtest_catch_exceptions_test.py \
+ test/gtest_color_test.py \
+ test/gtest_env_var_test.py \
+ test/gtest_filter_unittest.py \
+ test/gtest_help_test.py \
+ test/gtest_list_tests_unittest.py \
+ test/gtest_output_test.py \
+ test/gtest_output_test_golden_lin.txt \
+ test/gtest_shuffle_test.py \
+ test/gtest_test_utils.py \
+ test/gtest_throw_on_failure_test.py \
+ test/gtest_uninitialized_test.py \
+ test/gtest_xml_outfiles_test.py \
+ test/gtest_xml_output_unittest.py \
+ test/gtest_xml_test_utils.py
+
+# CMake script
+EXTRA_DIST += \
+ CMakeLists.txt \
+ cmake/internal_utils.cmake
+
+# MSVC project files
+EXTRA_DIST += \
+ msvc/gtest-md.sln \
+ msvc/gtest-md.vcproj \
+ msvc/gtest.sln \
+ msvc/gtest.vcproj \
+ msvc/gtest_main-md.vcproj \
+ msvc/gtest_main.vcproj \
+ msvc/gtest_prod_test-md.vcproj \
+ msvc/gtest_prod_test.vcproj \
+ msvc/gtest_unittest-md.vcproj \
+ msvc/gtest_unittest.vcproj
+
+# xcode project files
+EXTRA_DIST += \
+ xcode/Config/DebugProject.xcconfig \
+ xcode/Config/FrameworkTarget.xcconfig \
+ xcode/Config/General.xcconfig \
+ xcode/Config/ReleaseProject.xcconfig \
+ xcode/Config/StaticLibraryTarget.xcconfig \
+ xcode/Config/TestTarget.xcconfig \
+ xcode/Resources/Info.plist \
+ xcode/Scripts/runtests.sh \
+ xcode/Scripts/versiongenerate.py \
+ xcode/gtest.xcodeproj/project.pbxproj
+
+# xcode sample files
+EXTRA_DIST += \
+ xcode/Samples/FrameworkSample/Info.plist \
+ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \
+ xcode/Samples/FrameworkSample/runtests.sh \
+ xcode/Samples/FrameworkSample/widget.cc \
+ xcode/Samples/FrameworkSample/widget.h \
+ xcode/Samples/FrameworkSample/widget_test.cc
+
+# C++Builder project files
+EXTRA_DIST += \
+ codegear/gtest.cbproj \
+ codegear/gtest.groupproj \
+ codegear/gtest_all.cc \
+ codegear/gtest_link.cc \
+ codegear/gtest_main.cbproj \
+ codegear/gtest_unittest.cbproj
+
+# Distribute and install M4 macro
+m4datadir = $(datadir)/aclocal
+m4data_DATA = m4/gtest.m4
+EXTRA_DIST += $(m4data_DATA)
+
+# We define the global AM_CPPFLAGS as everything we compile includes from these
+# directories.
+AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include
+
+# Modifies compiler and linker flags for pthreads compatibility.
+if HAVE_PTHREADS
+ AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
+ AM_LIBS = @PTHREAD_LIBS@
+else
+ AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0
+endif
+
+# Build rules for libraries.
+lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la
+
+lib_libgtest_la_SOURCES = src/gtest-all.cc
+
+pkginclude_HEADERS = \
+ include/gtest/gtest-death-test.h \
+ include/gtest/gtest-message.h \
+ include/gtest/gtest-param-test.h \
+ include/gtest/gtest-printers.h \
+ include/gtest/gtest-spi.h \
+ include/gtest/gtest-test-part.h \
+ include/gtest/gtest-typed-test.h \
+ include/gtest/gtest.h \
+ include/gtest/gtest_pred_impl.h \
+ include/gtest/gtest_prod.h
+
+pkginclude_internaldir = $(pkgincludedir)/internal
+pkginclude_internal_HEADERS = \
+ include/gtest/internal/gtest-death-test-internal.h \
+ include/gtest/internal/gtest-filepath.h \
+ include/gtest/internal/gtest-internal.h \
+ include/gtest/internal/gtest-linked_ptr.h \
+ include/gtest/internal/gtest-param-util-generated.h \
+ include/gtest/internal/gtest-param-util.h \
+ include/gtest/internal/gtest-port.h \
+ include/gtest/internal/gtest-string.h \
+ include/gtest/internal/gtest-tuple.h \
+ include/gtest/internal/gtest-type-util.h
+
+lib_libgtest_main_la_SOURCES = src/gtest_main.cc
+lib_libgtest_main_la_LIBADD = lib/libgtest.la
+
+# Bulid rules for samples and tests. Automake's naming for some of
+# these variables isn't terribly obvious, so this is a brief
+# reference:
+#
+# TESTS -- Programs run automatically by "make check"
+# check_PROGRAMS -- Programs built by "make check" but not necessarily run
+
+noinst_LTLIBRARIES = samples/libsamples.la
+
+samples_libsamples_la_SOURCES = \
+ samples/sample1.cc \
+ samples/sample1.h \
+ samples/sample2.cc \
+ samples/sample2.h \
+ samples/sample3-inl.h \
+ samples/sample4.cc \
+ samples/sample4.h
+
+TESTS=
+TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \
+ GTEST_BUILD_DIR="$(top_builddir)/test"
+check_PROGRAMS=
+
+# A simple sample on using gtest.
+TESTS += samples/sample1_unittest
+check_PROGRAMS += samples/sample1_unittest
+samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc
+samples_sample1_unittest_LDADD = lib/libgtest_main.la \
+ lib/libgtest.la \
+ samples/libsamples.la
+
+# Another sample. It also verifies that libgtest works.
+TESTS += samples/sample10_unittest
+check_PROGRAMS += samples/sample10_unittest
+samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc
+samples_sample10_unittest_LDADD = lib/libgtest.la
+
+# This tests most constructs of gtest and verifies that libgtest_main
+# and libgtest work.
+TESTS += test/gtest_all_test
+check_PROGRAMS += test/gtest_all_test
+test_gtest_all_test_SOURCES = test/gtest_all_test.cc
+test_gtest_all_test_LDADD = lib/libgtest_main.la \
+ lib/libgtest.la
+
+# Tests that fused gtest files compile and work.
+FUSED_GTEST_SRC = \
+ fused-src/gtest/gtest-all.cc \
+ fused-src/gtest/gtest.h \
+ fused-src/gtest/gtest_main.cc
+
+if HAVE_PYTHON
+TESTS += test/fused_gtest_test
+check_PROGRAMS += test/fused_gtest_test
+test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \
+ samples/sample1.cc samples/sample1_unittest.cc
+test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src"
+
+# Build rules for putting fused Google Test files into the distribution
+# package. The user can also create those files by manually running
+# scripts/fuse_gtest_files.py.
+$(test_fused_gtest_test_SOURCES): fused-gtest
+
+fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
+ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \
+ scripts/fuse_gtest_files.py
+ mkdir -p "$(srcdir)/fused-src"
+ chmod -R u+w "$(srcdir)/fused-src"
+ rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc"
+ rm -f "$(srcdir)/fused-src/gtest/gtest.h"
+ "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src"
+ cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/"
+
+maintainer-clean-local:
+ rm -rf "$(srcdir)/fused-src"
+endif
+
+# Death tests may produce core dumps in the build directory. In case
+# this happens, clean them to keep distcleancheck happy.
+CLEANFILES = core
+
+# Disables 'make install' as installing a compiled version of Google
+# Test can lead to undefined behavior due to violation of the
+# One-Definition Rule.
+
+install-exec-local:
+ echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system."
+ false
+
+install-data-local:
+ echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system."
+ false
diff --git a/external/gtest-1.6.0/README b/external/gtest-1.6.0/README
new file mode 100644
index 0000000..26f35a8
--- /dev/null
+++ b/external/gtest-1.6.0/README
@@ -0,0 +1,435 @@
+Google C++ Testing Framework
+============================
+
+http://code.google.com/p/googletest/
+
+Overview
+--------
+
+Google's framework for writing C++ tests on a variety of platforms
+(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
+xUnit architecture. Supports automatic test discovery, a rich set of
+assertions, user-defined assertions, death tests, fatal and non-fatal
+failures, various options for running the tests, and XML test report
+generation.
+
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development. There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+join us!
+
+Requirements for End Users
+--------------------------
+
+Google Test is designed to have fairly minimal requirements to build
+and use with your projects, but there are some. Currently, we support
+Linux, Windows, Mac OS X, and Cygwin. We will also make our best
+effort to support other platforms (e.g. Solaris, AIX, and z/OS).
+However, since core members of the Google Test project have no access
+to these platforms, Google Test may have outstanding issues there. If
+you notice any problems on your platform, please notify
+googletestframework at googlegroups.com. Patches for fixing them are
+even more welcome!
+
+### Linux Requirements ###
+
+These are the base requirements to build and use Google Test from a source
+package (as described below):
+ * GNU-compatible Make or gmake
+ * POSIX-standard shell
+ * POSIX(-2) Regular Expressions (regex.h)
+ * A C++98-standard-compliant compiler
+
+### Windows Requirements ###
+
+ * Microsoft Visual C++ 7.1 or newer
+
+### Cygwin Requirements ###
+
+ * Cygwin 1.5.25-14 or newer
+
+### Mac OS X Requirements ###
+
+ * Mac OS X 10.4 Tiger or newer
+ * Developer Tools Installed
+
+Also, you'll need CMake 2.6.4 or higher if you want to build the
+samples using the provided CMake script, regardless of the platform.
+
+Requirements for Contributors
+-----------------------------
+
+We welcome patches. If you plan to contribute a patch, you need to
+build Google Test and its own tests from an SVN checkout (described
+below), which has further requirements:
+
+ * Python version 2.3 or newer (for running some of the tests and
+ re-generating certain source files from templates)
+ * CMake 2.6.4 or newer
+
+Getting the Source
+------------------
+
+There are two primary ways of getting Google Test's source code: you
+can download a stable source release in your preferred archive format,
+or directly check out the source from our Subversion (SVN) repositary.
+The SVN checkout requires a few extra steps and some extra software
+packages on your system, but lets you track the latest development and
+make patches much more easily, so we highly encourage it.
+
+### Source Package ###
+
+Google Test is released in versioned source packages which can be
+downloaded from the download page [1]. Several different archive
+formats are provided, but the only difference is the tools used to
+manipulate them, and the size of the resulting file. Download
+whichever you are most comfortable with.
+
+ [1] http://code.google.com/p/googletest/downloads/list
+
+Once the package is downloaded, expand it using whichever tools you
+prefer for that type. This will result in a new directory with the
+name "gtest-X.Y.Z" which contains all of the source code. Here are
+some examples on Linux:
+
+ tar -xvzf gtest-X.Y.Z.tar.gz
+ tar -xvjf gtest-X.Y.Z.tar.bz2
+ unzip gtest-X.Y.Z.zip
+
+### SVN Checkout ###
+
+To check out the main branch (also known as the "trunk") of Google
+Test, run the following Subversion command:
+
+ svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
+
+Setting up the Build
+--------------------
+
+To build Google Test and your tests that use it, you need to tell your
+build system where to find its headers and source files. The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
+
+### Generic Build Instructions ###
+
+Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
+create a library build target (or a project as called by Visual Studio
+and Xcode) to compile
+
+ ${GTEST_DIR}/src/gtest-all.cc
+
+with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR}
+in the normal header search path. Assuming a Linux-like system and gcc,
+something like the following will do:
+
+ g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
+ -pthread -c ${GTEST_DIR}/src/gtest-all.cc
+ ar -rv libgtest.a gtest-all.o
+
+(We need -pthread as Google Test uses threads.)
+
+Next, you should compile your test source file with
+${GTEST_DIR}/include in the system header search path, and link it
+with gtest and any other necessary libraries:
+
+ g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
+ -o your_test
+
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Test on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
+Test's own tests. Instead, it just builds the Google Test library and
+a sample test. You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+ cd ${GTEST_DIR}/make
+ make
+ ./sample1_unittest
+
+If you see errors, try to tweak the contents of make/Makefile to make
+them go away. There are instructions in make/Makefile on how to do
+it.
+
+### Using CMake ###
+
+Google Test comes with a CMake build script (CMakeLists.txt) that can
+be used on a wide range of platforms ("C" stands for cross-platofrm.).
+If you don't have CMake installed already, you can download it for
+free from http://www.cmake.org/.
+
+CMake works by generating native makefiles or build projects that can
+be used in the compiler environment of your choice. The typical
+workflow starts with:
+
+ mkdir mybuild # Create a directory to hold the build output.
+ cd mybuild
+ cmake ${GTEST_DIR} # Generate native build scripts.
+
+If you want to build Google Test's samples, you should replace the
+last command with
+
+ cmake -Dgtest_build_samples=ON ${GTEST_DIR}
+
+If you are on a *nix system, you should now see a Makefile in the
+current directory. Just type 'make' to build gtest.
+
+If you use Windows and have Vistual Studio installed, a gtest.sln file
+and several .vcproj files will be created. You can then build them
+using Visual Studio.
+
+On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
+
+### Legacy Build Scripts ###
+
+Before settling on CMake, we have been providing hand-maintained build
+projects/scripts for Visual Studio, Xcode, and Autotools. While we
+continue to provide them for convenience, they are not actively
+maintained any more. We highly recommend that you follow the
+instructions in the previous two sections to integrate Google Test
+with your existing build system.
+
+If you still need to use the legacy build scripts, here's how:
+
+The msvc\ folder contains two solutions with Visual C++ projects.
+Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
+are ready to build Google Test the same way you build any Visual
+Studio project. Files that have names ending with -md use DLL
+versions of Microsoft runtime libraries (the /MD or the /MDd compiler
+option). Files without that suffix use static versions of the runtime
+libraries (the /MT or the /MTd option). Please note that one must use
+the same option to compile both gtest and the test code. If you use
+Visual Studio 2005 or above, we recommend the -md version as /MD is
+the default for new projects in these versions of Visual Studio.
+
+On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
+Xcode. Build the "gtest" target. The universal binary framework will
+end up in your selected build directory (selected in the Xcode
+"Preferences..." -> "Building" pane and defaults to xcode/build).
+Alternatively, at the command line, enter:
+
+ xcodebuild
+
+This will build the "Release" configuration of gtest.framework in your
+default build location. See the "xcodebuild" man page for more
+information about building different configurations and building in
+different locations.
+
+If you wish to use the Google Test Xcode project with Xcode 4.x and
+above, you need to either:
+ * update the SDK configuration options in xcode/Config/General.xconfig.
+ Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If
+ you choose this route you lose the ability to target earlier versions
+ of MacOS X.
+ * Install an SDK for an earlier version. This doesn't appear to be
+ supported by Apple, but has been reported to work
+ (http://stackoverflow.com/questions/5378518).
+
+Tweaking Google Test
+--------------------
+
+Google Test can be used in diverse environments. The default
+configuration may not work (or may not work well) out of the box in
+some environments. However, you can easily tweak Google Test by
+defining control macros on the compiler command line. Generally,
+these macros are named like GTEST_XYZ and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list,
+see file include/gtest/internal/gtest-port.h.
+
+### Choosing a TR1 Tuple Library ###
+
+Some Google Test features require the C++ Technical Report 1 (TR1)
+tuple library, which is not yet available with all compilers. The
+good news is that Google Test implements a subset of TR1 tuple that's
+enough for its own need, and will automatically use this when the
+compiler doesn't provide TR1 tuple.
+
+Usually you don't need to care about which tuple library Google Test
+uses. However, if your project already uses TR1 tuple, you need to
+tell Google Test to use the same TR1 tuple library the rest of your
+project uses, or the two tuple implementations will clash. To do
+that, add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=0
+
+to the compiler flags while compiling Google Test and your tests. If
+you want to force Google Test to use its own tuple library, just add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
+
+If you don't want Google Test to use tuple at all, add
+
+ -DGTEST_HAS_TR1_TUPLE=0
+
+and all features using tuple will be disabled.
+
+### Multi-threaded Tests ###
+
+Google Test is thread-safe where the pthread library is available.
+After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE
+macro to see whether this is the case (yes if the macro is #defined to
+1, no if it's undefined.).
+
+If Google Test doesn't correctly detect whether pthread is available
+in your environment, you can force it with
+
+ -DGTEST_HAS_PTHREAD=1
+
+or
+
+ -DGTEST_HAS_PTHREAD=0
+
+When Google Test uses pthread, you may need to add flags to your
+compiler and/or linker to select the pthread library, or you'll get
+link errors. If you use the CMake script or the deprecated Autotools
+script, this is taken care of for you. If you use your own build
+script, you'll need to read your compiler and linker's manual to
+figure out what flags to add.
+
+### As a Shared Library (DLL) ###
+
+Google Test is compact, so most users can build and link it as a
+static library for the simplicity. You can choose to use Google Test
+as a shared library (known as a DLL on Windows) if you prefer.
+
+To compile *gtest* as a shared library, add
+
+ -DGTEST_CREATE_SHARED_LIBRARY=1
+
+to the compiler flags. You'll also need to tell the linker to produce
+a shared library instead - consult your linker's manual for how to do
+it.
+
+To compile your *tests* that use the gtest shared library, add
+
+ -DGTEST_LINKED_AS_SHARED_LIBRARY=1
+
+to the compiler flags.
+
+Note: while the above steps aren't technically necessary today when
+using some compilers (e.g. GCC), they may become necessary in the
+future, if we decide to improve the speed of loading the library (see
+http://gcc.gnu.org/wiki/Visibility for details). Therefore you are
+recommended to always add the above flags when using Google Test as a
+shared library. Otherwise a future release of Google Test may break
+your build script.
+
+### Avoiding Macro Name Clashes ###
+
+In C++, macros don't obey namespaces. Therefore two libraries that
+both define a macro of the same name will clash if you #include both
+definitions. In case a Google Test macro clashes with another
+library, you can force Google Test to rename its macro to avoid the
+conflict.
+
+Specifically, if both Google Test and some other code define macro
+FOO, you can add
+
+ -DGTEST_DONT_DEFINE_FOO=1
+
+to the compiler flags to tell Google Test to change the macro's name
+from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
+For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
+
+ GTEST_TEST(SomeTest, DoesThis) { ... }
+
+instead of
+
+ TEST(SomeTest, DoesThis) { ... }
+
+in order to define a test.
+
+Upgrating from an Earlier Version
+---------------------------------
+
+We strive to keep Google Test releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits. This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Test.
+
+### Upgrading from 1.3.0 or Earlier ###
+
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library. See the instructions in section "Choosing a TR1 Tuple
+Library".
+
+### Upgrading from 1.4.0 or Earlier ###
+
+The Autotools build script (configure + make) is no longer officially
+supportted. You are encouraged to migrate to your own build system or
+use CMake. If you still need to use Autotools, you can find
+instructions in the README file from Google Test 1.4.0.
+
+On platforms where the pthread library is available, Google Test uses
+it in order to be thread-safe. See the "Multi-threaded Tests" section
+for what this means to your build script.
+
+If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
+Test will no longer compile. This should affect very few people, as a
+large portion of STL (including <string>) doesn't compile in this mode
+anyway. We decided to stop supporting it in order to greatly simplify
+Google Test's implementation.
+
+Developing Google Test
+----------------------
+
+This section discusses how to make your own changes to Google Test.
+
+### Testing Google Test Itself ###
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you can use CMake:
+
+ mkdir mybuild
+ cd mybuild
+ cmake -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Make sure you have Python installed, as some of Google Test's tests
+are written in Python. If the cmake command complains about not being
+able to find Python ("Could NOT find PythonInterp (missing:
+PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
+executable can be found:
+
+ cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Next, you can build Google Test and all of its own tests. On *nix,
+this is usually done by 'make'. To run the tests, do
+
+ make test
+
+All tests should pass.
+
+### Regenerating Source Files ###
+
+Some of Google Test's source files are generated from templates (not
+in the C++ sense) using a script. A template file is named FOO.pump,
+where FOO is the name of the file it will generate. For example, the
+file include/gtest/internal/gtest-type-util.h.pump is used to generate
+gtest-type-util.h in the same directory.
+
+Normally you don't need to worry about regenerating the source files,
+unless you need to modify them. In that case, you should modify the
+corresponding .pump files instead and run the pump.py Python script to
+regenerate them. You can find pump.py in the scripts/ directory.
+Read the Pump manual [2] for how to use it.
+
+ [2] http://code.google.com/p/googletest/wiki/PumpManual
+
+### Contributing a Patch ###
+
+We welcome patches. Please read the Google Test developer's guide [3]
+for how you can contribute. In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+ [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
+
+Happy testing!
diff --git a/external/gtest-1.6.0/build-aux/.keep b/external/gtest-1.6.0/build-aux/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/external/gtest-1.6.0/build/.gitignore b/external/gtest-1.6.0/build/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/external/gtest-1.6.0/build/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/external/gtest-1.6.0/cmake/internal_utils.cmake b/external/gtest-1.6.0/cmake/internal_utils.cmake
new file mode 100644
index 0000000..8cb2189
--- /dev/null
+++ b/external/gtest-1.6.0/cmake/internal_utils.cmake
@@ -0,0 +1,227 @@
+# Defines functions and macros useful for building Google Test and
+# Google Mock.
+#
+# Note:
+#
+# - This file will be run twice when building Google Mock (once via
+# Google Test's CMakeLists.txt, and once via Google Mock's).
+# Therefore it shouldn't have any side effects other than defining
+# the functions and macros.
+#
+# - The functions/macros defined in this file may depend on Google
+# Test and Google Mock's option() definitions, and thus must be
+# called *after* the options have been defined.
+
+# Tweaks CMake's default compiler/linker settings to suit Google Test's needs.
+#
+# This must be a macro(), as inside a function string() can only
+# update variables in the function scope.
+macro(fix_default_compiler_settings_)
+ if (MSVC)
+ # For MSVC, CMake sets certain flags to defaults we want to override.
+ # This replacement code is taken from sample in the CMake Wiki at
+ # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace.
+ foreach (flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
+ # When Google Test is built as a shared library, it should also use
+ # shared runtime libraries. Otherwise, it may end up with multiple
+ # copies of runtime library data in different modules, resulting in
+ # hard-to-find crashes. When it is built as a static library, it is
+ # preferable to use CRT as static libraries, as we don't have to rely
+ # on CRT DLLs being available. CMake always defaults to using shared
+ # CRT libraries, so we override that default here.
+ string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
+ endif()
+
+ # We prefer more strict warning checking for building Google Test.
+ # Replaces /W3 with /W4 in defaults.
+ string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}")
+ endforeach()
+ endif()
+endmacro()
+
+# Defines the compiler/linker flags used to build Google Test and
+# Google Mock. You can tweak these definitions to suit your need. A
+# variable's value is empty before it's explicitly assigned to.
+macro(config_compiler_and_linker)
+ if (NOT gtest_disable_pthreads)
+ # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
+ find_package(Threads)
+ endif()
+
+ fix_default_compiler_settings_()
+ if (MSVC)
+ # Newlines inside flags variables break CMake's NMake generator.
+ # TODO(vladl at google.com): Add -RTCs and -RTCu to debug builds.
+ set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi")
+ if (MSVC_VERSION LESS 1400)
+ # Suppress spurious warnings MSVC 7.1 sometimes issues.
+ # Forcing value to bool.
+ set(cxx_base_flags "${cxx_base_flags} -wd4800")
+ # Copy constructor and assignment operator could not be generated.
+ set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512")
+ # Compatibility warnings not applicable to Google Test.
+ # Resolved overload was found by argument-dependent lookup.
+ set(cxx_base_flags "${cxx_base_flags} -wd4675")
+ endif()
+ set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
+ set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
+ set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
+ set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
+ set(cxx_no_rtti_flags "-GR-")
+ elseif (CMAKE_COMPILER_IS_GNUCXX)
+ set(cxx_base_flags "-Wall -Wshadow")
+ set(cxx_exception_flags "-fexceptions")
+ set(cxx_no_exception_flags "-fno-exceptions")
+ # Until version 4.3.2, GCC doesn't define a macro to indicate
+ # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
+ # explicitly.
+ set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
+ set(cxx_strict_flags
+ "-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
+ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+ set(cxx_exception_flags "-features=except")
+ # Sun Pro doesn't provide macros to indicate whether exceptions and
+ # RTTI are enabled, so we define GTEST_HAS_* explicitly.
+ set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
+ set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
+ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR
+ CMAKE_CXX_COMPILER_ID STREQUAL "XL")
+ # CMake 2.8 changes Visual Age's compiler ID to "XL".
+ set(cxx_exception_flags "-qeh")
+ set(cxx_no_exception_flags "-qnoeh")
+ # Until version 9.0, Visual Age doesn't define a macro to indicate
+ # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
+ # explicitly.
+ set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
+ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP")
+ set(cxx_base_flags "-AA -mt")
+ set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1")
+ set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0")
+ # RTTI can not be disabled in HP aCC compiler.
+ set(cxx_no_rtti_flags "")
+ endif()
+
+ if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed.
+ set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
+ else()
+ set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0")
+ endif()
+
+ # For building gtest's own tests and samples.
+ set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}")
+ set(cxx_no_exception
+ "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
+ set(cxx_default "${cxx_exception}")
+ set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
+ set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1")
+
+ # For building the gtest libraries.
+ set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
+endmacro()
+
+# Defines the gtest & gtest_main libraries. User tests should link
+# with one of them.
+function(cxx_library_with_type name type cxx_flags)
+ # type can be either STATIC or SHARED to denote a static or shared library.
+ # ARGN refers to additional arguments after 'cxx_flags'.
+ add_library(${name} ${type} ${ARGN})
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_flags}")
+ if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED")
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
+ endif()
+ if (CMAKE_USE_PTHREADS_INIT)
+ target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+endfunction()
+
+########################################################################
+#
+# Helper functions for creating build targets.
+
+function(cxx_shared_library name cxx_flags)
+ cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
+endfunction()
+
+function(cxx_library name cxx_flags)
+ cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN})
+endfunction()
+
+# cxx_executable_with_flags(name cxx_flags libs srcs...)
+#
+# creates a named C++ executable that depends on the given libraries and
+# is built from the given source files with the given compiler flags.
+function(cxx_executable_with_flags name cxx_flags libs)
+ add_executable(${name} ${ARGN})
+ if (cxx_flags)
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_flags}")
+ endif()
+ if (BUILD_SHARED_LIBS)
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+ endif()
+ # To support mixing linking in static and dynamic libraries, link each
+ # library in with an extra call to target_link_libraries.
+ foreach (lib "${libs}")
+ target_link_libraries(${name} ${lib})
+ endforeach()
+endfunction()
+
+# cxx_executable(name dir lib srcs...)
+#
+# creates a named target that depends on the given libs and is built
+# from the given source files. dir/name.cc is implicitly included in
+# the source file list.
+function(cxx_executable name dir libs)
+ cxx_executable_with_flags(
+ ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN})
+endfunction()
+
+# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
+find_package(PythonInterp)
+
+# cxx_test_with_flags(name cxx_flags libs srcs...)
+#
+# creates a named C++ test that depends on the given libs and is built
+# from the given source files with the given compiler flags.
+function(cxx_test_with_flags name cxx_flags libs)
+ cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
+ add_test(${name} ${name})
+endfunction()
+
+# cxx_test(name libs srcs...)
+#
+# creates a named test target that depends on the given libs and is
+# built from the given source files. Unlike cxx_test_with_flags,
+# test/name.cc is already implicitly included in the source file list.
+function(cxx_test name libs)
+ cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
+ "test/${name}.cc" ${ARGN})
+endfunction()
+
+# py_test(name)
+#
+# creates a Python test with the given name whose main module is in
+# test/name.py. It does nothing if Python is not installed.
+function(py_test name)
+ # We are not supporting Python tests on Linux yet as they consider
+ # all Linux environments to be google3 and try to use google3 features.
+ if (PYTHONINTERP_FOUND)
+ # ${CMAKE_BINARY_DIR} is known at configuration time, so we can
+ # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known
+ # only at ctest runtime (by calling ctest -c <Configuration>), so
+ # we have to escape $ to delay variable substitution here.
+ add_test(${name}
+ ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
+ --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
+ endif()
+endfunction()
diff --git a/external/gtest-1.6.0/codegear/gtest.cbproj b/external/gtest-1.6.0/codegear/gtest.cbproj
new file mode 100644
index 0000000..95c3054
--- /dev/null
+++ b/external/gtest-1.6.0/codegear/gtest.cbproj
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
+ <Config Condition="'$(Config)'==''">Release</Config>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+ <Base>true</Base>
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+ <Base>true</Base>
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+ <OutputExt>lib</OutputExt>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <Defines>NO_STRICT</Defines>
+ <DynamicRTL>true</DynamicRTL>
+ <UsePackages>true</UsePackages>
+ <ProjectType>CppStaticLibrary</ProjectType>
+ <BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi; [...]
+ <BCC_wpar>false</BCC_wpar>
+ <IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
+ <AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
+ <TLIB_PageSize>32</TLIB_PageSize>
+ <ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
+ <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+ <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+ <ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
+ <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+ <DCC_Define>DEBUG</DCC_Define>
+ <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+ <IntermediateOutputDir>Debug</IntermediateOutputDir>
+ <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+ <BCC_StackFrames>true</BCC_StackFrames>
+ <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>Full</TASM_Debugging>
+ <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <Defines>NDEBUG;$(Defines)</Defines>
+ <IntermediateOutputDir>Release</IntermediateOutputDir>
+ <ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>None</TASM_Debugging>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
+ <Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
+ <BorlandProject>
+<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo [...]
+
+
+ <Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
+ </Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlInc [...]
+ </ProjectExtensions>
+ <Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
+ <ItemGroup>
+ <None Include="..\include\gtest\gtest-death-test.h">
+ <BuildOrder>3</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-message.h">
+ <BuildOrder>4</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-param-test.h">
+ <BuildOrder>5</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-spi.h">
+ <BuildOrder>6</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-test-part.h">
+ <BuildOrder>7</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-typed-test.h">
+ <BuildOrder>8</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest.h">
+ <BuildOrder>0</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest_pred_impl.h">
+ <BuildOrder>1</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest_prod.h">
+ <BuildOrder>2</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-death-test-internal.h">
+ <BuildOrder>9</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-filepath.h">
+ <BuildOrder>10</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-internal.h">
+ <BuildOrder>11</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-linked_ptr.h">
+ <BuildOrder>12</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-param-util-generated.h">
+ <BuildOrder>14</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-param-util.h">
+ <BuildOrder>13</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-port.h">
+ <BuildOrder>15</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-string.h">
+ <BuildOrder>16</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-type-util.h">
+ <BuildOrder>17</BuildOrder>
+ </None>
+ <CppCompile Include="gtest_all.cc">
+ <BuildOrder>18</BuildOrder>
+ </CppCompile>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_1</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_2</Key>
+ </BuildConfiguration>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/external/gtest-1.6.0/codegear/gtest.groupproj b/external/gtest-1.6.0/codegear/gtest.groupproj
new file mode 100644
index 0000000..faf31ca
--- /dev/null
+++ b/external/gtest-1.6.0/codegear/gtest.groupproj
@@ -0,0 +1,54 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{c1d923e0-6cba-4332-9b6f-3420acbf5091}</ProjectGuid>
+ </PropertyGroup>
+ <ItemGroup />
+ <ItemGroup>
+ <Projects Include="gtest.cbproj" />
+ <Projects Include="gtest_main.cbproj" />
+ <Projects Include="gtest_unittest.cbproj" />
+ </ItemGroup>
+ <ProjectExtensions>
+ <Borland.Personality>Default.Personality</Borland.Personality>
+ <Borland.ProjectType />
+ <BorlandProject>
+<BorlandProject xmlns=""><Default.Personality></Default.Personality></BorlandProject></BorlandProject>
+ </ProjectExtensions>
+ <Target Name="gtest">
+ <MSBuild Projects="gtest.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest:Clean">
+ <MSBuild Projects="gtest.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest:Make">
+ <MSBuild Projects="gtest.cbproj" Targets="Make" />
+ </Target>
+ <Target Name="gtest_main">
+ <MSBuild Projects="gtest_main.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest_main:Clean">
+ <MSBuild Projects="gtest_main.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest_main:Make">
+ <MSBuild Projects="gtest_main.cbproj" Targets="Make" />
+ </Target>
+ <Target Name="gtest_unittest">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest_unittest:Clean">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest_unittest:Make">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
+ </Target>
+ <Target Name="Build">
+ <CallTarget Targets="gtest;gtest_main;gtest_unittest" />
+ </Target>
+ <Target Name="Clean">
+ <CallTarget Targets="gtest:Clean;gtest_main:Clean;gtest_unittest:Clean" />
+ </Target>
+ <Target Name="Make">
+ <CallTarget Targets="gtest:Make;gtest_main:Make;gtest_unittest:Make" />
+ </Target>
+ <Import Condition="Exists('$(MSBuildBinPath)\Borland.Group.Targets')" Project="$(MSBuildBinPath)\Borland.Group.Targets" />
+</Project>
\ No newline at end of file
diff --git a/external/gtest-1.6.0/codegear/gtest_all.cc b/external/gtest-1.6.0/codegear/gtest_all.cc
new file mode 100644
index 0000000..121b2d8
--- /dev/null
+++ b/external/gtest-1.6.0/codegear/gtest_all.cc
@@ -0,0 +1,38 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Josh Kelley (joshkel at gmail.com)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// C++Builder's IDE cannot build a static library from files with hyphens
+// in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 .
+// This file serves as a workaround.
+
+#include "src/gtest-all.cc"
diff --git a/external/gtest-1.6.0/codegear/gtest_link.cc b/external/gtest-1.6.0/codegear/gtest_link.cc
new file mode 100644
index 0000000..918eccd
--- /dev/null
+++ b/external/gtest-1.6.0/codegear/gtest_link.cc
@@ -0,0 +1,40 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Josh Kelley (joshkel at gmail.com)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Links gtest.lib and gtest_main.lib into the current project in C++Builder.
+// This means that these libraries can't be renamed, but it's the only way to
+// ensure that Debug versus Release test builds are linked against the
+// appropriate Debug or Release build of the libraries.
+
+#pragma link "gtest.lib"
+#pragma link "gtest_main.lib"
diff --git a/external/gtest-1.6.0/codegear/gtest_main.cbproj b/external/gtest-1.6.0/codegear/gtest_main.cbproj
new file mode 100644
index 0000000..d76ce13
--- /dev/null
+++ b/external/gtest-1.6.0/codegear/gtest_main.cbproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
+ <Config Condition="'$(Config)'==''">Release</Config>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+ <Base>true</Base>
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+ <Base>true</Base>
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+ <OutputExt>lib</OutputExt>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <Defines>NO_STRICT</Defines>
+ <DynamicRTL>true</DynamicRTL>
+ <UsePackages>true</UsePackages>
+ <ProjectType>CppStaticLibrary</ProjectType>
+ <BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi; [...]
+ <BCC_wpar>false</BCC_wpar>
+ <IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
+ <AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
+ <TLIB_PageSize>32</TLIB_PageSize>
+ <ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
+ <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+ <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+ <ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
+ <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+ <DCC_Define>DEBUG</DCC_Define>
+ <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+ <IntermediateOutputDir>Debug</IntermediateOutputDir>
+ <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+ <BCC_StackFrames>true</BCC_StackFrames>
+ <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>Full</TASM_Debugging>
+ <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <Defines>NDEBUG;$(Defines)</Defines>
+ <IntermediateOutputDir>Release</IntermediateOutputDir>
+ <ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>None</TASM_Debugging>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
+ <Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
+ <BorlandProject>
+<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo [...]
+ <Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
+ </Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlInc [...]
+ </ProjectExtensions>
+ <Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
+ <ItemGroup>
+ <CppCompile Include="..\src\gtest_main.cc">
+ <BuildOrder>0</BuildOrder>
+ </CppCompile>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_1</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_2</Key>
+ </BuildConfiguration>
+ </ItemGroup>
+</Project>
diff --git a/external/gtest-1.6.0/codegear/gtest_unittest.cbproj b/external/gtest-1.6.0/codegear/gtest_unittest.cbproj
new file mode 100644
index 0000000..dc5db8e
--- /dev/null
+++ b/external/gtest-1.6.0/codegear/gtest_unittest.cbproj
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{eea63393-5ac5-4b9c-8909-d75fef2daa41}</ProjectGuid>
+ <Config Condition="'$(Config)'==''">Release</Config>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+ <Base>true</Base>
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+ <Base>true</Base>
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <OutputExt>exe</OutputExt>
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+ <Defines>NO_STRICT</Defines>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <DynamicRTL>true</DynamicRTL>
+ <ILINK_ObjectSearchPath>..\test</ILINK_ObjectSearchPath>
+ <UsePackages>true</UsePackages>
+ <ProjectType>CppConsoleApplication</ProjectType>
+ <NoVCL>true</NoVCL>
+ <BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSy [...]
+ <BCC_wpar>false</BCC_wpar>
+ <IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</IncludePath>
+ <ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</ILINK_LibraryPath>
+ <Multithreaded>true</Multithreaded>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
+ <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+ <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+ <ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
+ <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+ <DCC_Define>DEBUG</DCC_Define>
+ <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+ <IntermediateOutputDir>Debug</IntermediateOutputDir>
+ <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+ <BCC_StackFrames>true</BCC_StackFrames>
+ <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>Full</TASM_Debugging>
+ <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <Defines>NDEBUG;$(Defines)</Defines>
+ <IntermediateOutputDir>Release</IntermediateOutputDir>
+ <ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>None</TASM_Debugging>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
+ <Borland.ProjectType>CppConsoleApplication</Borland.ProjectType>
+ <BorlandProject>
+<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo [...]
+
+
+ <Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
+ </Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlInc [...]
+ </ProjectExtensions>
+ <Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
+ <ItemGroup>
+ <CppCompile Include="..\test\gtest_unittest.cc">
+ <BuildOrder>0</BuildOrder>
+ </CppCompile>
+ <CppCompile Include="gtest_link.cc">
+ <BuildOrder>1</BuildOrder>
+ </CppCompile>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_1</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_2</Key>
+ </BuildConfiguration>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/external/gtest-1.6.0/configure.ac b/external/gtest-1.6.0/configure.ac
new file mode 100644
index 0000000..cc592e1
--- /dev/null
+++ b/external/gtest-1.6.0/configure.ac
@@ -0,0 +1,68 @@
+m4_include(m4/acx_pthread.m4)
+
+# At this point, the Xcode project assumes the version string will be three
+# integers separated by periods and surrounded by square brackets (e.g.
+# "[1.0.1]"). It also asumes that there won't be any closing parenthesis
+# between "AC_INIT(" and the closing ")" including comments and strings.
+AC_INIT([Google C++ Testing Framework],
+ [1.7.0],
+ [googletestframework at googlegroups.com],
+ [gtest])
+
+# Provide various options to initialize the Autoconf and configure processes.
+AC_PREREQ([2.59])
+AC_CONFIG_SRCDIR([./LICENSE])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_HEADERS([build-aux/config.h])
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config])
+
+# Initialize Automake with various options. We require at least v1.9, prevent
+# pedantic complaints about package files, and enable various distribution
+# targets.
+AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects])
+
+# Check for programs used in building Google Test.
+AC_PROG_CC
+AC_PROG_CXX
+AC_LANG([C++])
+AC_PROG_LIBTOOL
+
+# TODO(chandlerc at google.com): Currently we aren't running the Python tests
+# against the interpreter detected by AM_PATH_PYTHON, and so we condition
+# HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's
+# version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env"
+# hashbang.
+PYTHON= # We *do not* allow the user to specify a python interpreter
+AC_PATH_PROG([PYTHON],[python],[:])
+AS_IF([test "$PYTHON" != ":"],
+ [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])])
+AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"])
+
+# Configure pthreads.
+AC_ARG_WITH([pthreads],
+ [AS_HELP_STRING([--with-pthreads],
+ [use pthreads (default is yes)])],
+ [with_pthreads=$withval],
+ [with_pthreads=check])
+
+have_pthreads=no
+AS_IF([test "x$with_pthreads" != "xno"],
+ [ACX_PTHREAD(
+ [],
+ [AS_IF([test "x$with_pthreads" != "xcheck"],
+ [AC_MSG_FAILURE(
+ [--with-pthreads was specified, but unable to be used])])])
+ have_pthreads="$acx_pthread_ok"])
+AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" = "xyes"])
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_LIBS)
+
+# TODO(chandlerc at google.com) Check for the necessary system headers.
+
+# TODO(chandlerc at google.com) Check the types, structures, and other compiler
+# and architecture characteristics.
+
+# Output the generated files. No further autoconf macros may be used.
+AC_OUTPUT
diff --git a/external/gtest-1.6.0/include/CMakeLists.txt b/external/gtest-1.6.0/include/CMakeLists.txt
new file mode 100644
index 0000000..fc1e0b6
--- /dev/null
+++ b/external/gtest-1.6.0/include/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_subdirectory(gtest)
diff --git a/external/gtest-1.6.0/include/gtest/CMakeLists.txt b/external/gtest-1.6.0/include/gtest/CMakeLists.txt
new file mode 100644
index 0000000..57af9f6
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+file(GLOB gtestFiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
+foreach(gtestFile ${gtestFiles})
+ configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/${gtestFile}" "${CMAKE_CURRENT_BINARY_DIR}/${gtestFile}" COPYONLY )
+# install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${gtestFile}" DESTINATION include/gtest)
+endforeach(gtestFile)
+
+add_subdirectory(internal)
diff --git a/external/gtest-1.6.0/include/gtest/gtest-death-test.h b/external/gtest-1.6.0/include/gtest/gtest-death-test.h
new file mode 100644
index 0000000..09defbd
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-death-test.h
@@ -0,0 +1,298 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests. It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include "gtest/internal/gtest-death-test-internal.h"
+
+namespace testing
+{
+
+// This flag controls the style of death tests. Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal
+{
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process. Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests. IMPORTANT: This is an internal utility. Using it may break the
+// implementation of death tests. User code MUST NOT use it.
+GTEST_API_ bool InDeathTestChild();
+
+} // namespace internal
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+// 1. It generates a warning if there is more than one active
+// thread. This is because it's safe to fork() or clone() only
+// when there is a single thread.
+//
+// 2. The parent process clone()s a sub-process and runs the death
+// test in it; the sub-process exits with code 0 at the end of the
+// death test, if it hasn't exited already.
+//
+// 3. The parent process waits for the sub-process to terminate.
+//
+// 4. The parent process checks the exit code and error message of
+// the sub-process.
+//
+// Examples:
+//
+// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+// for (int i = 0; i < 5; i++) {
+// EXPECT_DEATH(server.ProcessRequest(i),
+// "Invalid request .* in ProcessRequest()")
+// << "Failed to die on request " << i;
+// }
+//
+// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+// bool KilledBySIGHUP(int exit_code) {
+// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+// }
+//
+// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// On the regular expressions used in death tests:
+//
+// On POSIX-compliant systems (*nix), we use the <regex.h> library,
+// which uses the POSIX extended regex syntax.
+//
+// On other platforms (e.g. Windows), we only support a simple regex
+// syntax implemented as part of Google Test. This limited
+// implementation should be enough most of the time when writing
+// death tests; though it lacks many features you can find in PCRE
+// or POSIX extended regex syntax. For example, we don't support
+// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+// repetition count ("x{5,7}"), among others.
+//
+// Below is the syntax that we do support. We chose it to be a
+// subset of both PCRE and POSIX extended regex, so it's easy to
+// learn wherever you come from. In the following: 'A' denotes a
+// literal character, period (.), or a single \\ escape sequence;
+// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
+// natural numbers.
+//
+// c matches any literal character c
+// \\d matches any decimal digit
+// \\D matches any character that's not a decimal digit
+// \\f matches \f
+// \\n matches \n
+// \\r matches \r
+// \\s matches any ASCII whitespace, including \n
+// \\S matches any character that's not a whitespace
+// \\t matches \t
+// \\v matches \v
+// \\w matches any letter, _, or decimal digit
+// \\W matches any character that \\w doesn't match
+// \\c matches any literal character c, which must be a punctuation
+// . matches any single character except \n
+// A? matches 0 or 1 occurrences of A
+// A* matches 0 or many occurrences of A
+// A+ matches 1 or many occurrences of A
+// ^ matches the beginning of a string (not that of each line)
+// $ matches the end of a string (not that of each line)
+// xy matches x followed by y
+//
+// If you accidentally use PCRE or POSIX extended regex features
+// not implemented by us, you will get a run-time failure. In that
+// case, please try to rewrite your regular expression within the
+// above syntax.
+//
+// This implementation is *not* meant to be as highly tuned or robust
+// as a compiled regex library, but should perform well enough for a
+// death test, which already incurs significant overhead by launching
+// a child process.
+//
+// Known caveats:
+//
+// A "threadsafe" style death test obtains the path to the test
+// program from argv[0] and re-executes it in the sub-process. For
+// simplicity, the current implementation doesn't search the PATH
+// when launching the sub-process. This means that the user must
+// invoke the test program via a path that contains at least one
+// path separator (e.g. path/to/foo_test and
+// /absolute/path/to/bar_test are fine, but foo_test is not). This
+// is rarely a problem as people usually don't put the test binary
+// directory in PATH.
+//
+// TODO(wan at google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+# define ASSERT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+# define ASSERT_DEATH(statement, regex) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_DEATH(statement, regex) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class GTEST_API_ ExitedWithCode
+{
+ public:
+ explicit ExitedWithCode(int exit_code);
+ bool operator()(int exit_status) const;
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ExitedWithCode& other);
+
+ const int exit_code_;
+};
+
+# if !GTEST_OS_WINDOWS
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class GTEST_API_ KilledBySignal
+{
+ public:
+ explicit KilledBySignal(int signum);
+ bool operator()(int exit_status) const;
+ private:
+ const int signum_;
+};
+# endif // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+// if (sideeffect) {
+// *sideeffect = 12;
+// }
+// LOG(DFATAL) << "death";
+// return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// int sideeffect = 0;
+// // Only asserts in dbg.
+// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+// // opt-mode has sideeffect visible.
+// EXPECT_EQ(12, sideeffect);
+// #else
+// // dbg-mode no visible sideeffect.
+// EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects. A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+// // Side-effects here will have an effect after this statement in
+// // opt mode, but none in debug mode.
+// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+# ifdef NDEBUG
+
+# define EXPECT_DEBUG_DEATH(statement, regex) \
+ GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+# define ASSERT_DEBUG_DEATH(statement, regex) \
+ GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+# else
+
+# define EXPECT_DEBUG_DEATH(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+
+# define ASSERT_DEBUG_DEATH(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+
+# endif // NDEBUG for EXPECT_DEBUG_DEATH
+#endif // GTEST_HAS_DEATH_TEST
+
+// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
+// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
+// death tests are supported; otherwise they just issue a warning. This is
+// useful when you are combining death test assertions with normal test
+// assertions in one test.
+#if GTEST_HAS_DEATH_TEST
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+#else
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
+#endif
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-message.h b/external/gtest-1.6.0/include/gtest/gtest-message.h
new file mode 100644
index 0000000..a2d5668
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-message.h
@@ -0,0 +1,255 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+
+#include "gtest/internal/gtest-port.h"
+
+// Ensures that there is at least one operator<< in the global namespace.
+// See Message& operator<<(...) below for why.
+void operator<<(const testing::internal::Secret&, int);
+
+namespace testing
+{
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+// 1. You stream a bunch of values to a Message object.
+// It will remember the text in a stringstream.
+// 2. Then you stream the Message object to an ostream.
+// This causes the text in the Message to be streamed
+// to the ostream.
+//
+// For example;
+//
+// testing::Message foo;
+// foo << 1 << " != " << 2;
+// std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from. In particular, its
+// destructor is not virtual.
+//
+// Note that stringstream behaves differently in gcc and in MSVC. You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do). The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class GTEST_API_ Message
+{
+ private:
+ // The type of basic IO manipulators (endl, ends, and flush) for
+ // narrow streams.
+ typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+ // Constructs an empty Message.
+ Message();
+
+ // Copy constructor.
+ Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
+ *ss_ << msg.GetString();
+ }
+
+ // Constructs a Message from a C-string.
+ explicit Message(const char* str) : ss_(new ::std::stringstream) {
+ *ss_ << str;
+ }
+
+#if GTEST_OS_SYMBIAN
+ // Streams a value (either a pointer or not) to this object.
+ template <typename T>
+ inline Message& operator <<(const T& value) {
+ StreamHelper(typename internal::is_pointer<T>::type(), value);
+ return *this;
+ }
+#else
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator <<(const T& val) {
+ // Some libraries overload << for STL containers. These
+ // overloads are defined in the global namespace instead of ::std.
+ //
+ // C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+ // overloads are visible in either the std namespace or the global
+ // namespace, but not other namespaces, including the testing
+ // namespace which Google Test's Message class is in.
+ //
+ // To allow STL containers (and other types that has a << operator
+ // defined in the global namespace) to be used in Google Test
+ // assertions, testing::Message must access the custom << operator
+ // from the global namespace. With this using declaration,
+ // overloads of << defined in the global namespace and those
+ // visible via Koenig lookup are both exposed in this function.
+ using ::operator <<;
+ *ss_ << val;
+ return *this;
+ }
+
+ // Streams a pointer value to this object.
+ //
+ // This function is an overload of the previous one. When you
+ // stream a pointer to a Message, this definition will be used as it
+ // is more specialized. (The C++ Standard, section
+ // [temp.func.order].) If you stream a non-pointer, then the
+ // previous definition will be used.
+ //
+ // The reason for this overload is that streaming a NULL pointer to
+ // ostream is undefined behavior. Depending on the compiler, you
+ // may get "0", "(nil)", "(null)", or an access violation. To
+ // ensure consistent result across compilers, we always treat NULL
+ // as "(null)".
+ template <typename T>
+ inline Message& operator <<(T* const& pointer) { // NOLINT
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ *ss_ << pointer;
+ }
+ return *this;
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // Since the basic IO manipulators are overloaded for both narrow
+ // and wide streams, we have to provide this specialized definition
+ // of operator <<, even though its body is the same as the
+ // templatized version above. Without this definition, streaming
+ // endl or other basic IO manipulators to Message will confuse the
+ // compiler.
+ Message& operator <<(BasicNarrowIoManip val) {
+ *ss_ << val;
+ return *this;
+ }
+
+ // Instead of 1/0, we want to see true/false for bool values.
+ Message& operator <<(bool b) {
+ return *this << (b ? "true" : "false");
+ }
+
+ // These two overloads allow streaming a wide C string to a Message
+ // using the UTF-8 encoding.
+ Message& operator <<(const wchar_t* wide_c_str);
+ Message& operator <<(wchar_t* wide_c_str);
+
+#if GTEST_HAS_STD_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::std::wstring& wstr);
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::wstring& wstr);
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+ // Gets the text streamed to this object so far as an std::string.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ std::string GetString() const;
+
+ private:
+
+#if GTEST_OS_SYMBIAN
+ // These are needed as the Nokia Symbian Compiler cannot decide between
+ // const T& and const T* in a function template. The Nokia compiler _can_
+ // decide between class template specializations for T and T*, so a
+ // tr1::type_traits-like is_pointer works, and we can overload on that.
+ template <typename T>
+ inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ *ss_ << pointer;
+ }
+ }
+ template <typename T>
+ inline void StreamHelper(internal::false_type /*is_pointer*/,
+ const T& value) {
+ // See the comments in Message& operator <<(const T&) above for why
+ // we need this using statement.
+ using ::operator <<;
+ *ss_ << value;
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // We'll hold the text streamed to this object here.
+ const internal::scoped_ptr< ::std::stringstream> ss_;
+
+ // We declare (but don't implement) this to prevent the compiler
+ // from implementing the assignment operator.
+ void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb)
+{
+ return os << sb.GetString();
+}
+
+namespace internal
+{
+
+// Converts a streamable value to an std::string. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+template <typename T>
+std::string StreamableToString(const T& streamable)
+{
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-param-test.h b/external/gtest-1.6.0/include/gtest/gtest-param-test.h
new file mode 100644
index 0000000..82ffdc5
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-param-test.h
@@ -0,0 +1,1494 @@
+// This file was GENERATED by command:
+// pump.py gtest-param-test.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl at google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*>
+{
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah)
+{
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah)
+{
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test
+{
+ // You can inherit all the usual members for a non-parameterized test
+ // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int>
+{
+ // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo)
+{
+ // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah)
+{
+ // GetParam works just the same here as if you inherit from TestWithParam.
+ EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif // 0
+
+#include "gtest/internal/gtest-port.h"
+
+#if !GTEST_OS_SYMBIAN
+# include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-param-util-generated.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing
+{
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step)
+{
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end)
+{
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end)
+{
+ typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
+ ::value_type ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T(&array)[N])
+{
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container)
+{
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1)
+{
+ return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2)
+{
+ return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3)
+{
+ return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4)
+{
+ return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5)
+{
+ return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6)
+{
+ return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7)
+{
+ return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+ v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8)
+{
+ return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+ v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9)
+{
+ return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10)
+{
+ return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11)
+{
+ return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12)
+{
+ return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13)
+{
+ return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14)
+{
+ return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15)
+{
+ return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16)
+{
+ return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17)
+{
+ return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18)
+{
+ return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19)
+{
+ return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20)
+{
+ return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21)
+{
+ return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22)
+{
+ return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23)
+{
+ return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24)
+{
+ return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25)
+{
+ return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26)
+{
+ return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27)
+{
+ return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28)
+{
+ return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29)
+{
+ return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30)
+{
+ return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31)
+{
+ return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32)
+{
+ return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33)
+{
+ return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34)
+{
+ return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35)
+{
+ return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36)
+{
+ return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37)
+{
+ return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38)
+{
+ return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+ v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38, T39 v39)
+{
+ return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+ v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+ T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+ T36 v36, T37 v37, T38 v38, T39 v39, T40 v40)
+{
+ return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+ v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41)
+{
+ return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+ v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42)
+{
+ return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+ v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43)
+{
+ return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+ v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44)
+{
+ return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+ v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41, T42 v42, T43 v43, T44 v44, T45 v45)
+{
+ return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+ v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44, typename T45,
+typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46)
+{
+ return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44, typename T45,
+typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47)
+{
+ return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44, typename T45,
+typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+ T48 v48)
+{
+ return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+ v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44, typename T45,
+typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+ T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+ T47 v47, T48 v48, T49 v49)
+{
+ return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+ v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+typename T6, typename T7, typename T8, typename T9, typename T10,
+typename T11, typename T12, typename T13, typename T14, typename T15,
+typename T16, typename T17, typename T18, typename T19, typename T20,
+typename T21, typename T22, typename T23, typename T24, typename T25,
+typename T26, typename T27, typename T28, typename T29, typename T30,
+typename T31, typename T32, typename T33, typename T34, typename T35,
+typename T36, typename T37, typename T38, typename T39, typename T40,
+typename T41, typename T42, typename T43, typename T44, typename T45,
+typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+ T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+ T46 v46, T47 v47, T48 v48, T49 v49, T50 v50)
+{
+ return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+ v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool()
+{
+ return Values(false, true);
+}
+
+# if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<tuple<bool, bool> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+ const Generator1& g1, const Generator2& g2)
+{
+ return internal::CartesianProductHolder2<Generator1, Generator2>(
+ g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3)
+{
+ return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+ g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4)
+{
+ return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4>(
+ g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5)
+{
+ return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5>(
+ g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6)
+{
+ return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6>(
+ g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+typename Generator4, typename Generator5, typename Generator6,
+typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7)
+{
+ return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7>(
+ g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+typename Generator4, typename Generator5, typename Generator6,
+typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8)
+{
+ return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8>(
+ g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+typename Generator4, typename Generator5, typename Generator6,
+typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8,
+ Generator9> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9)
+{
+ return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+typename Generator4, typename Generator5, typename Generator6,
+typename Generator7, typename Generator8, typename Generator9,
+typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9,
+ const Generator10& g10)
+{
+ return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+# endif // GTEST_HAS_COMBINE
+
+
+
+# define TEST_P(test_case_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ : public test_case_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+ virtual void TestBody(); \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_case_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+ int gtest_##prefix##test_case_name##_dummy_ = \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+ #prefix, \
+ >est_##prefix##test_case_name##_EvalGenerator_, \
+ __FILE__, __LINE__)
+
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-param-test.h.pump b/external/gtest-1.6.0/include/gtest/gtest-param-test.h.pump
new file mode 100644
index 0000000..2dc9303
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-param-test.h.pump
@@ -0,0 +1,487 @@
+$$ -*- mode: c++; -*-
+$var n = 50 $$ Maximum length of Values arguments we want to support.
+$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl at google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test {
+ // You can inherit all the usual members for a non-parameterized test
+ // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
+ // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo) {
+ // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah) {
+ // GetParam works just the same here as if you inherit from TestWithParam.
+ EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif // 0
+
+#include "gtest/internal/gtest-port.h"
+
+#if !GTEST_OS_SYMBIAN
+# include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-param-util-generated.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+ typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
+ ::value_type ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container) {
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to $n parameters.
+//
+$range i 1..n
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename T$j]]>
+internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) {
+ return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]);
+}
+
+]]
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+ return Values(false, true);
+}
+
+# if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to $maxtuple arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<tuple<bool, bool> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename Generator$j]]>
+internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine(
+ $for j, [[const Generator$j& g$j]]) {
+ return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>(
+ $for j, [[g$j]]);
+}
+
+]]
+# endif // GTEST_HAS_COMBINE
+
+
+
+# define TEST_P(test_case_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ : public test_case_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+ virtual void TestBody(); \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_case_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+ int gtest_##prefix##test_case_name##_dummy_ = \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+ #prefix, \
+ >est_##prefix##test_case_name##_EvalGenerator_, \
+ __FILE__, __LINE__)
+
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-printers.h b/external/gtest-1.6.0/include/gtest/gtest-printers.h
new file mode 100644
index 0000000..3820dce
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-printers.h
@@ -0,0 +1,910 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// A user can teach this function how to print a class type T by
+// defining either operator<<() or PrintTo() in the namespace that
+// defines T. More specifically, the FIRST defined function in the
+// following list will be used (assuming T is defined in namespace
+// foo):
+//
+// 1. foo::PrintTo(const T&, ostream*)
+// 2. operator<<(ostream&, const T&) defined in either foo or the
+// global namespace.
+//
+// If none of the above is defined, it will print the debug string of
+// the value if it is a protocol buffer, or print the raw bytes in the
+// value otherwise.
+//
+// To aid debugging: when T is a reference type, the address of the
+// value is also printed; when T is a (const) char pointer, both the
+// pointer value and the NUL-terminated string it points to are
+// printed.
+//
+// We also provide some convenient wrappers:
+//
+// // Prints a value to a string. For a (const or not) char
+// // pointer, the NUL-terminated string (but not the pointer) is
+// // printed.
+// std::string ::testing::PrintToString(const T& value);
+//
+// // Prints a value tersely: for a reference type, the referenced
+// // value (but not the address) is printed; for a (const or not) char
+// // pointer, the NUL-terminated string (but not the pointer) is
+// // printed.
+// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
+//
+// // Prints value using the type inferred by the compiler. The difference
+// // from UniversalTersePrint() is that this function prints both the
+// // pointer and the NUL-terminated string for a (const or not) char pointer.
+// void ::testing::internal::UniversalPrint(const T& value, ostream*);
+//
+// // Prints the fields of a tuple tersely to a string vector, one
+// // element for each field. Tuple support must be enabled in
+// // gtest-port.h.
+// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
+// const Tuple& value);
+//
+// Known limitation:
+//
+// The print primitives print the elements of an STL-style container
+// using the compiler-inferred type of *iter where iter is a
+// const_iterator of the container. When const_iterator is an input
+// iterator but not a forward iterator, this inferred type may not
+// match value_type, and the print output may be incorrect. In
+// practice, this is rarely a problem as for most containers
+// const_iterator is a forward iterator. We'll fix this if there's an
+// actual need for it. Note that this fix cannot rely on value_type
+// being defined as many user-defined container types don't have
+// value_type.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#include <ostream> // NOLINT
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+#include "gtest/internal/gtest-port.h"
+#include "gtest/internal/gtest-internal.h"
+
+namespace testing
+{
+
+// Definitions in the 'internal' and 'internal2' name spaces are
+// subject to change without notice. DO NOT USE THEM IN USER CODE!
+namespace internal2
+{
+
+// Prints the given number of bytes in the given object to the given
+// ostream.
+GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
+ size_t count,
+ ::std::ostream* os);
+
+// For selecting which printer to use when a given type has neither <<
+// nor PrintTo().
+enum TypeKind {
+ kProtobuf, // a protobuf type
+ kConvertibleToInteger, // a type implicitly convertible to BiggestInt
+ // (e.g. a named or unnamed enum type)
+ kOtherType // anything else
+};
+
+// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
+// by the universal printer to print a value of type T when neither
+// operator<< nor PrintTo() is defined for T, where kTypeKind is the
+// "kind" of T as defined by enum TypeKind.
+template <typename T, TypeKind kTypeKind>
+class TypeWithoutFormatter
+{
+ public:
+ // This default version is called when kTypeKind is kOtherType.
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
+ sizeof(value), os);
+ }
+};
+
+// We print a protobuf using its ShortDebugString() when the string
+// doesn't exceed this many characters; otherwise we print it using
+// DebugString() for better readability.
+const size_t kProtobufOneLinerMaxLength = 50;
+
+template <typename T>
+class TypeWithoutFormatter<T, kProtobuf>
+{
+ public:
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ const ::testing::internal::string short_str = value.ShortDebugString();
+ const ::testing::internal::string pretty_str =
+ short_str.length() <= kProtobufOneLinerMaxLength ?
+ short_str : ("\n" + value.DebugString());
+ *os << ("<" + pretty_str + ">");
+ }
+};
+
+template <typename T>
+class TypeWithoutFormatter<T, kConvertibleToInteger>
+{
+ public:
+ // Since T has no << operator or PrintTo() but can be implicitly
+ // converted to BiggestInt, we print it as a BiggestInt.
+ //
+ // Most likely T is an enum type (either named or unnamed), in which
+ // case printing it as an integer is the desired behavior. In case
+ // T is not an enum, printing it as an integer is the best we can do
+ // given that it has no user-defined printer.
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ const internal::BiggestInt kBigInt = value;
+ *os << kBigInt;
+ }
+};
+
+// Prints the given value to the given ostream. If the value is a
+// protocol message, its debug string is printed; if it's an enum or
+// of a type implicitly convertible to BiggestInt, it's printed as an
+// integer; otherwise the bytes in the value are printed. This is
+// what UniversalPrinter<T>::Print() does when it knows nothing about
+// type T and T has neither << operator nor PrintTo().
+//
+// A user can override this behavior for a class type Foo by defining
+// a << operator in the namespace where Foo is defined.
+//
+// We put this operator in namespace 'internal2' instead of 'internal'
+// to simplify the implementation, as much code in 'internal' needs to
+// use << in STL, which would conflict with our own << were it defined
+// in 'internal'.
+//
+// Note that this operator<< takes a generic std::basic_ostream<Char,
+// CharTraits> type instead of the more restricted std::ostream. If
+// we define it to take an std::ostream instead, we'll get an
+// "ambiguous overloads" compiler error when trying to print a type
+// Foo that supports streaming to std::basic_ostream<Char,
+// CharTraits>, as the compiler cannot tell whether
+// operator<<(std::ostream&, const T&) or
+// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
+// specific.
+template <typename Char, typename CharTraits, typename T>
+::std::basic_ostream<Char, CharTraits>& operator<<(
+ ::std::basic_ostream<Char, CharTraits>& os, const T& x)
+{
+ TypeWithoutFormatter<T,
+ (internal::IsAProtocolMessage<T>::value ? kProtobuf :
+ internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
+ kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
+ return os;
+}
+
+} // namespace internal2
+} // namespace testing
+
+// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
+// magic needed for implementing UniversalPrinter won't work.
+namespace testing_internal
+{
+
+// Used to print a value that is not an STL-style container when the
+// user doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os)
+{
+ // With the following statement, during unqualified name lookup,
+ // testing::internal2::operator<< appears as if it was declared in
+ // the nearest enclosing namespace that contains both
+ // ::testing_internal and ::testing::internal2, i.e. the global
+ // namespace. For more details, refer to the C++ Standard section
+ // 7.3.4-1 [namespace.udir]. This allows us to fall back onto
+ // testing::internal2::operator<< in case T doesn't come with a <<
+ // operator.
+ //
+ // We cannot write 'using ::testing::internal2::operator<<;', which
+ // gcc 3.3 fails to compile due to a compiler bug.
+ using namespace ::testing::internal2; // NOLINT
+
+ // Assuming T is defined in namespace foo, in the next statement,
+ // the compiler will consider all of:
+ //
+ // 1. foo::operator<< (thanks to Koenig look-up),
+ // 2. ::operator<< (as the current namespace is enclosed in ::),
+ // 3. testing::internal2::operator<< (thanks to the using statement above).
+ //
+ // The operator<< whose type matches T best will be picked.
+ //
+ // We deliberately allow #2 to be a candidate, as sometimes it's
+ // impossible to define #1 (e.g. when foo is ::std, defining
+ // anything in it is undefined behavior unless you are a compiler
+ // vendor.).
+ *os << value;
+}
+
+} // namespace testing_internal
+
+namespace testing
+{
+namespace internal
+{
+
+// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
+// value to the given ostream. The caller must ensure that
+// 'ostream_ptr' is not NULL, or the behavior is undefined.
+//
+// We define UniversalPrinter as a class template (as opposed to a
+// function template), as we need to partially specialize it for
+// reference types, which cannot be done with function templates.
+template <typename T>
+class UniversalPrinter;
+
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os);
+
+// Used to print an STL-style container when the user doesn't define
+// a PrintTo() for it.
+template <typename C>
+void DefaultPrintTo(IsContainer /* dummy */,
+ false_type /* is not a pointer */,
+ const C& container, ::std::ostream* os)
+{
+ const size_t kMaxCount = 32; // The maximum number of elements to print.
+ *os << '{';
+ size_t count = 0;
+ for (typename C::const_iterator it = container.begin();
+ it != container.end(); ++it, ++count) {
+ if (count > 0) {
+ *os << ',';
+ if (count == kMaxCount) { // Enough has been printed.
+ *os << " ...";
+ break;
+ }
+ }
+ *os << ' ';
+ // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
+ // handle *it being a native array.
+ internal::UniversalPrint(*it, os);
+ }
+
+ if (count > 0) {
+ *os << ' ';
+ }
+ *os << '}';
+}
+
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it. (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space. Their representation is
+// implementation-defined. Therefore they will be printed as raw
+// bytes.)
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+ true_type /* is a pointer */,
+ T* p, ::std::ostream* os)
+{
+ if (p == NULL) {
+ *os << "NULL";
+ } else {
+ // C++ doesn't allow casting from a function pointer to any object
+ // pointer.
+ //
+ // IsTrue() silences warnings: "Condition is always true",
+ // "unreachable code".
+ if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
+ // T is not a function type. We just call << to print p,
+ // relying on ADL to pick up user-defined << for their pointer
+ // types, if any.
+ *os << p;
+ } else {
+ // T is a function type, so '*os << p' doesn't do what we want
+ // (it just prints p as bool). We want to print p as a const
+ // void*. However, we cannot cast it to const void* directly,
+ // even using reinterpret_cast, as earlier versions of gcc
+ // (e.g. 3.4.5) cannot compile the cast when p is a function
+ // pointer. Casting to UInt64 first solves the problem.
+ *os << reinterpret_cast<const void*>(
+ reinterpret_cast<internal::UInt64>(p));
+ }
+ }
+}
+
+// Used to print a non-container, non-pointer value when the user
+// doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+ false_type /* is not a pointer */,
+ const T& value, ::std::ostream* os)
+{
+ ::testing_internal::DefaultPrintNonContainerTo(value, os);
+}
+
+// Prints the given value using the << operator if it has one;
+// otherwise prints the bytes in it. This is what
+// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
+// or overloaded for type T.
+//
+// A user can override this behavior for a class type Foo by defining
+// an overload of PrintTo() in the namespace where Foo is defined. We
+// give the user this option as sometimes defining a << operator for
+// Foo is not desirable (e.g. the coding style may prevent doing it,
+// or there is already a << operator but it doesn't do what the user
+// wants).
+template <typename T>
+void PrintTo(const T& value, ::std::ostream* os)
+{
+ // DefaultPrintTo() is overloaded. The type of its first two
+ // arguments determine which version will be picked. If T is an
+ // STL-style container, the version for container will be called; if
+ // T is a pointer, the pointer version will be called; otherwise the
+ // generic version will be called.
+ //
+ // Note that we check for container types here, prior to we check
+ // for protocol message types in our operator<<. The rationale is:
+ //
+ // For protocol messages, we want to give people a chance to
+ // override Google Mock's format by defining a PrintTo() or
+ // operator<<. For STL containers, other formats can be
+ // incompatible with Google Mock's format for the container
+ // elements; therefore we check for container types here to ensure
+ // that our format is used.
+ //
+ // The second argument of DefaultPrintTo() is needed to bypass a bug
+ // in Symbian's C++ compiler that prevents it from picking the right
+ // overload between:
+ //
+ // PrintTo(const T& x, ...);
+ // PrintTo(T* x, ...);
+ DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
+}
+
+// The following list of PrintTo() overloads tells
+// UniversalPrinter<T>::Print() how to print standard types (built-in
+// types, strings, plain arrays, and pointers).
+
+// Overloads for various char types.
+GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
+GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
+inline void PrintTo(char c, ::std::ostream* os)
+{
+ // When printing a plain char, we always treat it as unsigned. This
+ // way, the output won't be affected by whether the compiler thinks
+ // char is signed or not.
+ PrintTo(static_cast<unsigned char>(c), os);
+}
+
+// Overloads for other simple built-in types.
+inline void PrintTo(bool x, ::std::ostream* os)
+{
+ *os << (x ? "true" : "false");
+}
+
+// Overload for wchar_t type.
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its decimal code (except for L'\0').
+// The L'\0' char is printed as "L'\\0'". The decimal code is printed
+// as signed integer when wchar_t is implemented by the compiler
+// as a signed type and is printed as an unsigned integer when wchar_t
+// is implemented as an unsigned type.
+GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
+
+// Overloads for C strings.
+GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
+inline void PrintTo(char* s, ::std::ostream* os)
+{
+ PrintTo(ImplicitCast_<const char*>(s), os);
+}
+
+// signed/unsigned char is often used for representing binary data, so
+// we print pointers to it as void* to be safe.
+inline void PrintTo(const signed char* s, ::std::ostream* os)
+{
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(signed char* s, ::std::ostream* os)
+{
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(const unsigned char* s, ::std::ostream* os)
+{
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(unsigned char* s, ::std::ostream* os)
+{
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+
+// MSVC can be configured to define wchar_t as a typedef of unsigned
+// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
+// type. When wchar_t is a typedef, defining an overload for const
+// wchar_t* would cause unsigned short* be printed as a wide string,
+// possibly causing invalid memory accesses.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Overloads for wide C strings
+GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
+inline void PrintTo(wchar_t* s, ::std::ostream* os)
+{
+ PrintTo(ImplicitCast_<const wchar_t*>(s), os);
+}
+#endif
+
+// Overload for C arrays. Multi-dimensional arrays are printed
+// properly.
+
+// Prints the given number of elements in an array, without printing
+// the curly braces.
+template <typename T>
+void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os)
+{
+ UniversalPrint(a[0], os);
+ for (size_t i = 1; i != count; i++) {
+ *os << ", ";
+ UniversalPrint(a[i], os);
+ }
+}
+
+// Overloads for ::string and ::std::string.
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_API_ void PrintStringTo(const ::string& s, ::std::ostream* os);
+inline void PrintTo(const ::string& s, ::std::ostream* os)
+{
+ PrintStringTo(s, os);
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+GTEST_API_ void PrintStringTo(const ::std::string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::string& s, ::std::ostream* os)
+{
+ PrintStringTo(s, os);
+}
+
+// Overloads for ::wstring and ::std::wstring.
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::wstring& s, ::std::ostream* os);
+inline void PrintTo(const ::wstring& s, ::std::ostream* os)
+{
+ PrintWideStringTo(s, os);
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::std::wstring& s, ::std::ostream* os);
+inline void PrintTo(const ::std::wstring& s, ::std::ostream* os)
+{
+ PrintWideStringTo(s, os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_TR1_TUPLE
+// Overload for ::std::tr1::tuple. Needed for printing function arguments,
+// which are packed as tuples.
+
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os);
+
+// Overloaded PrintTo() for tuples of various arities. We support
+// tuples of up-to 10 fields. The following implementation works
+// regardless of whether tr1::tuple is implemented using the
+// non-standard variadic template feature or not.
+
+inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1>
+void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2>
+void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
+ ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
+ ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
+ ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
+ ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
+ ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+void PrintTo(
+ const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
+ ::std::ostream* os)
+{
+ PrintTupleTo(t, os);
+}
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Overload for std::pair.
+template <typename T1, typename T2>
+void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os)
+{
+ *os << '(';
+ // We cannot use UniversalPrint(value.first, os) here, as T1 may be
+ // a reference type. The same for printing value.second.
+ UniversalPrinter<T1>::Print(value.first, os);
+ *os << ", ";
+ UniversalPrinter<T2>::Print(value.second, os);
+ *os << ')';
+}
+
+// Implements printing a non-reference type T by letting the compiler
+// pick the right overload of PrintTo() for T.
+template <typename T>
+class UniversalPrinter
+{
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4180) // Temporarily disables warning 4180.
+#endif // _MSC_VER
+
+ // Note: we deliberately don't call this PrintTo(), as that name
+ // conflicts with ::testing::internal::PrintTo in the body of the
+ // function.
+ static void Print(const T& value, ::std::ostream* os) {
+ // By default, ::testing::internal::PrintTo() is used for printing
+ // the value.
+ //
+ // Thanks to Koenig look-up, if T is a class and has its own
+ // PrintTo() function defined in its namespace, that function will
+ // be visible here. Since it is more specific than the generic ones
+ // in ::testing::internal, it will be picked by the compiler in the
+ // following statement - exactly what we want.
+ PrintTo(value, os);
+ }
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif // _MSC_VER
+};
+
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os)
+{
+ if (len == 0) {
+ *os << "{}";
+ } else {
+ *os << "{ ";
+ const size_t kThreshold = 18;
+ const size_t kChunkSize = 8;
+ // If the array has more than kThreshold elements, we'll have to
+ // omit some details by printing only the first and the last
+ // kChunkSize elements.
+ // TODO(wan at google.com): let the user control the threshold using a flag.
+ if (len <= kThreshold) {
+ PrintRawArrayTo(begin, len, os);
+ } else {
+ PrintRawArrayTo(begin, kChunkSize, os);
+ *os << ", ..., ";
+ PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+ }
+ *os << " }";
+ }
+}
+// This overload prints a (const) char array compactly.
+GTEST_API_ void UniversalPrintArray(
+ const char* begin, size_t len, ::std::ostream* os);
+
+// This overload prints a (const) wchar_t array compactly.
+GTEST_API_ void UniversalPrintArray(
+ const wchar_t* begin, size_t len, ::std::ostream* os);
+
+// Implements printing an array type T[N].
+template <typename T, size_t N>
+class UniversalPrinter<T[N]>
+{
+ public:
+ // Prints the given array, omitting some elements when there are too
+ // many.
+ static void Print(const T(&a)[N], ::std::ostream* os) {
+ UniversalPrintArray(a, N, os);
+ }
+};
+
+// Implements printing a reference type T&.
+template <typename T>
+class UniversalPrinter<T&>
+{
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4180) // Temporarily disables warning 4180.
+#endif // _MSC_VER
+
+ static void Print(const T& value, ::std::ostream* os) {
+ // Prints the address of the value. We use reinterpret_cast here
+ // as static_cast doesn't compile when T is a function type.
+ *os << "@" << reinterpret_cast<const void*>(&value) << " ";
+
+ // Then prints the value itself.
+ UniversalPrint(value, os);
+ }
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif // _MSC_VER
+};
+
+// Prints a value tersely: for a reference type, the referenced value
+// (but not the address) is printed; for a (const) char pointer, the
+// NUL-terminated string (but not the pointer) is printed.
+
+template <typename T>
+class UniversalTersePrinter
+{
+ public:
+ static void Print(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+ }
+};
+template <typename T>
+class UniversalTersePrinter<T&>
+{
+ public:
+ static void Print(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+ }
+};
+template <typename T, size_t N>
+class UniversalTersePrinter<T[N]>
+{
+ public:
+ static void Print(const T(&value)[N], ::std::ostream* os) {
+ UniversalPrinter<T[N]>::Print(value, os);
+ }
+};
+template <>
+class UniversalTersePrinter<const char*>
+{
+ public:
+ static void Print(const char* str, ::std::ostream* os) {
+ if (str == NULL) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char*>
+{
+ public:
+ static void Print(char* str, ::std::ostream* os) {
+ UniversalTersePrinter<const char*>::Print(str, os);
+ }
+};
+
+#if GTEST_HAS_STD_WSTRING
+template <>
+class UniversalTersePrinter<const wchar_t*>
+{
+ public:
+ static void Print(const wchar_t* str, ::std::ostream* os) {
+ if (str == NULL) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::wstring(str), os);
+ }
+ }
+};
+#endif
+
+template <>
+class UniversalTersePrinter<wchar_t*>
+{
+ public:
+ static void Print(wchar_t* str, ::std::ostream* os) {
+ UniversalTersePrinter<const wchar_t*>::Print(str, os);
+ }
+};
+
+template <typename T>
+void UniversalTersePrint(const T& value, ::std::ostream* os)
+{
+ UniversalTersePrinter<T>::Print(value, os);
+}
+
+// Prints a value using the type inferred by the compiler. The
+// difference between this and UniversalTersePrint() is that for a
+// (const) char pointer, this prints both the pointer and the
+// NUL-terminated string.
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os)
+{
+ // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
+ // UniversalPrinter with T directly.
+ typedef T T1;
+ UniversalPrinter<T1>::Print(value, os);
+}
+
+#if GTEST_HAS_TR1_TUPLE
+typedef ::std::vector<string> Strings;
+
+// This helper template allows PrintTo() for tuples and
+// UniversalTersePrintTupleFieldsToStrings() to be defined by
+// induction on the number of tuple fields. The idea is that
+// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
+// fields in tuple t, and can be defined in terms of
+// TuplePrefixPrinter<N - 1>.
+
+// The inductive case.
+template <size_t N>
+struct TuplePrefixPrinter {
+ // Prints the first N fields of a tuple.
+ template <typename Tuple>
+ static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+ TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
+ *os << ", ";
+ UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
+ ::Print(::std::tr1::get<N - 1>(t), os);
+ }
+
+ // Tersely prints the first N fields of a tuple to a string vector,
+ // one element for each field.
+ template <typename Tuple>
+ static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+ TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
+ ::std::stringstream ss;
+ UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
+ strings->push_back(ss.str());
+ }
+};
+
+// Base cases.
+template <>
+struct TuplePrefixPrinter<0> {
+ template <typename Tuple>
+ static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
+
+ template <typename Tuple>
+ static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
+};
+// We have to specialize the entire TuplePrefixPrinter<> class
+// template here, even though the definition of
+// TersePrintPrefixToStrings() is the same as the generic version, as
+// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
+// support specializing a method template of a class template.
+template <>
+struct TuplePrefixPrinter<1> {
+ template <typename Tuple>
+ static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+ UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
+ Print(::std::tr1::get<0>(t), os);
+ }
+
+ template <typename Tuple>
+ static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+ ::std::stringstream ss;
+ UniversalTersePrint(::std::tr1::get<0>(t), &ss);
+ strings->push_back(ss.str());
+ }
+};
+
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os)
+{
+ *os << "(";
+ TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
+ PrintPrefixTo(t, os);
+ *os << ")";
+}
+
+// Prints the fields of a tuple tersely to a string vector, one
+// element for each field. See the comment before
+// UniversalTersePrint() for how we define "tersely".
+template <typename Tuple>
+Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value)
+{
+ Strings result;
+ TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
+ TersePrintPrefixToStrings(value, &result);
+ return result;
+}
+#endif // GTEST_HAS_TR1_TUPLE
+
+} // namespace internal
+
+template <typename T>
+::std::string PrintToString(const T& value)
+{
+ ::std::stringstream ss;
+ internal::UniversalTersePrinter<T>::Print(value, &ss);
+ return ss.str();
+}
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-spi.h b/external/gtest-1.6.0/include/gtest/gtest-spi.h
new file mode 100644
index 0000000..b657c7c
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-spi.h
@@ -0,0 +1,236 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include "gtest/gtest.h"
+
+namespace testing
+{
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class GTEST_API_ ScopedFakeTestPartResultReporter
+ : public TestPartResultReporterInterface
+{
+ public:
+ // The two possible mocking modes of this object.
+ enum InterceptMode {
+ INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
+ INTERCEPT_ALL_THREADS // Intercepts all failures.
+ };
+
+ // The c'tor sets this object as the test part result reporter used
+ // by Google Test. The 'result' parameter specifies where to report the
+ // results. This reporter will only catch failures generated in the current
+ // thread. DEPRECATED
+ explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+ // Same as above, but you can choose the interception scope of this object.
+ ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+ TestPartResultArray* result);
+
+ // The d'tor restores the previous test part result reporter.
+ virtual ~ScopedFakeTestPartResultReporter();
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+ void Init();
+
+ const InterceptMode intercept_mode_;
+ TestPartResultReporterInterface* old_reporter_;
+ TestPartResultArray* const result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal
+{
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+class GTEST_API_ SingleFailureChecker
+{
+ public:
+ // The constructor remembers the arguments.
+ SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const string& substr);
+ ~SingleFailureChecker();
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResult::Type type_;
+ const string substr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures. It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - 'statement' cannot reference local non-static variables or
+// non-static members of the current object.
+// - 'statement' cannot return a value.
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ALL_THREADS, >est_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures. It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. If we do that, the code won't compile when the user gives
+// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
+// expands to code containing an unprotected comma. The
+// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
+// catches that.
+//
+// For the same reason, we have to write
+// if (::testing::internal::AlwaysTrue()) { statement; }
+// instead of
+// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+// to avoid an MSVC warning on unreachable code.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
+ >est_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-test-part.h b/external/gtest-1.6.0/include/gtest/gtest-test-part.h
new file mode 100644
index 0000000..9f4398e
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-test-part.h
@@ -0,0 +1,185 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule at google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+
+namespace testing
+{
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult
+{
+ public:
+ // The possible outcomes of a test part (i.e. an assertion or an
+ // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+ enum Type {
+ kSuccess, // Succeeded.
+ kNonFatalFailure, // Failed but the test can continue.
+ kFatalFailure // Failed and the test should be terminated.
+ };
+
+ // C'tor. TestPartResult does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestPartResult object.
+ TestPartResult(Type a_type,
+ const char* a_file_name,
+ int a_line_number,
+ const char* a_message)
+ : type_(a_type),
+ file_name_(a_file_name == NULL ? "" : a_file_name),
+ line_number_(a_line_number),
+ summary_(ExtractSummary(a_message)),
+ message_(a_message) {
+ }
+
+ // Gets the outcome of the test part.
+ Type type() const { return type_; }
+
+ // Gets the name of the source file where the test part took place, or
+ // NULL if it's unknown.
+ const char* file_name() const {
+ return file_name_.empty() ? NULL : file_name_.c_str();
+ }
+
+ // Gets the line in the source file where the test part took place,
+ // or -1 if it's unknown.
+ int line_number() const { return line_number_; }
+
+ // Gets the summary of the failure message.
+ const char* summary() const { return summary_.c_str(); }
+
+ // Gets the message associated with the test part.
+ const char* message() const { return message_.c_str(); }
+
+ // Returns true iff the test part passed.
+ bool passed() const { return type_ == kSuccess; }
+
+ // Returns true iff the test part failed.
+ bool failed() const { return type_ != kSuccess; }
+
+ // Returns true iff the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+ // Returns true iff the test part fatally failed.
+ bool fatally_failed() const { return type_ == kFatalFailure; }
+
+ private:
+ Type type_;
+
+ // Gets the summary of the failure message by omitting the stack
+ // trace in it.
+ static std::string ExtractSummary(const char* message);
+
+ // The name of the source file where the test part took place, or
+ // "" if the source file is unknown.
+ std::string file_name_;
+ // The line in the source file where the test part took place, or -1
+ // if the line number is unknown.
+ int line_number_;
+ std::string summary_; // The test failure summary.
+ std::string message_; // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray
+{
+ public:
+ TestPartResultArray() {}
+
+ // Appends the given TestPartResult to the array.
+ void Append(const TestPartResult& result);
+
+ // Returns the TestPartResult at the given index (0-based).
+ const TestPartResult& GetTestPartResult(int index) const;
+
+ // Returns the number of TestPartResult objects in the array.
+ int size() const;
+
+ private:
+ std::vector<TestPartResult> array_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface
+{
+ public:
+ virtual ~TestPartResultReporterInterface() {}
+
+ virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal
+{
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+ : public TestPartResultReporterInterface
+{
+ public:
+ HasNewFatalFailureHelper();
+ virtual ~HasNewFatalFailureHelper();
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+ bool has_new_fatal_failure_;
+ TestPartResultReporterInterface* original_reporter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest-typed-test.h b/external/gtest-1.6.0/include/gtest/gtest-typed-test.h
new file mode 100644
index 0000000..14d20f9
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest-typed-test.h
@@ -0,0 +1,263 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list. You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test
+{
+ public:
+ ...
+ typedef std::list<T> List;
+ static T shared_;
+ T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list. The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah)
+{
+ // Inside a test, refer to TypeParam to get the type parameter.
+ // Since we are inside a derived class template, C++ requires use to
+ // visit the members of FooTest via 'this'.
+ TypeParam n = this->value_;
+
+ // To visit static members of the fixture, add the TestFixture::
+ // prefix.
+ n += TestFixture::shared_;
+
+ // To refer to typedefs in the fixture, add the "typename
+ // TestFixture::" prefix.
+ typename TestFixture::List values;
+ values.push_back(n);
+ ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type. Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are. The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have. Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly. Here's an example:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test
+{
+ ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah)
+{
+ // Inside a test, refer to TypeParam to get the type parameter.
+ TypeParam n = 0;
+ ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them. The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+ DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want. If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name. Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif // 0
+
+#include "gtest/internal/gtest-port.h"
+#include "gtest/internal/gtest-type-util.h"
+
+// Implements typed tests.
+
+#if GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define TYPED_TEST_CASE(CaseName, Types) \
+ typedef ::testing::internal::TypeList< Types >::type \
+ GTEST_TYPE_PARAMS_(CaseName)
+
+# define TYPED_TEST(CaseName, TestName) \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTest< \
+ CaseName, \
+ ::testing::internal::TemplateSel< \
+ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+ GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+ "", #CaseName, #TestName, 0); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in. The exact
+// name of the namespace is subject to change without notice.
+# define GTEST_CASE_NAMESPACE_(TestCaseName) \
+ gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+ gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+ gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+# define TYPED_TEST_CASE_P(CaseName) \
+ static ::testing::internal::TypedTestCasePState \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+# define TYPED_TEST_P(CaseName, TestName) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+ __FILE__, __LINE__, #CaseName, #TestName); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+ __FILE__, __LINE__, #__VA_ARGS__)
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTestCase<CaseName, \
+ GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+ ::testing::internal::TypeList< Types >::type>::Register(\
+ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest.h b/external/gtest-1.6.0/include/gtest/gtest.h
new file mode 100644
index 0000000..e163f59
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest.h
@@ -0,0 +1,2319 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test. It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy at prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+#include <limits>
+#include <ostream>
+#include <vector>
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+#include "gtest/gtest-death-test.h"
+#include "gtest/gtest-message.h"
+#include "gtest/gtest-param-test.h"
+#include "gtest/gtest-printers.h"
+#include "gtest/gtest_prod.h"
+#include "gtest/gtest-test-part.h"
+#include "gtest/gtest-typed-test.h"
+
+// Depending on the platform, different string classes are available.
+// On Linux, in addition to ::std::string, Google also makes use of
+// class ::string, which has the same interface as ::std::string, but
+// has a different implementation.
+//
+// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// ::string is available AND is a distinct type to ::std::string, or
+// define it to 0 to indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// heuristically.
+
+namespace testing
+{
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flag specifies the random number seed.
+GTEST_DECLARE_int32_(random_seed);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// When this flag is specified, tests' order is randomized on every iteration.
+GTEST_DECLARE_bool_(shuffle);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// When this flag is set with a "host:port" string, on supported
+// platforms test results are streamed to the specified port on
+// the specified host machine.
+GTEST_DECLARE_string_(stream_result_to);
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal
+{
+
+class AssertHelper;
+class DefaultGlobalTestPartResultReporter;
+class ExecDeathTest;
+class NoExecDeathTest;
+class FinalSuccessChecker;
+class GTestFlagSaver;
+class StreamingListenerTest;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class UnitTestRecordPropertyTestHelper;
+class WindowsDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const std::string& message);
+
+} // namespace internal
+
+// The friend relationship of some of these classes is cyclic.
+// If we don't forward declare them the compiler might confuse the classes
+// in friendship clauses with same named classes on the scope.
+class Test;
+class TestCase;
+class TestInfo;
+class UnitTest;
+
+// A class for indicating whether an assertion was successful. When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that describes how it failed.
+//
+// To create an instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// This class is useful for two purposes:
+// 1. Defining predicate functions to be used with Boolean test assertions
+// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
+// 2. Defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// For example, if you define IsEven predicate:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
+// will print the message
+//
+// Value of: IsEven(Fib(5))
+// Actual: false (5 is odd)
+// Expected: true
+//
+// instead of a more opaque
+//
+// Value of: IsEven(Fib(5))
+// Actual: false
+// Expected: true
+//
+// in case IsEven is a simple Boolean predicate.
+//
+// If you expect your predicate to be reused and want to support informative
+// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
+// about half as often as positive ones in our tests), supply messages for
+// both success and failure cases:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess() << n << " is even";
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
+//
+// Value of: IsEven(Fib(6))
+// Actual: true (8 is even)
+// Expected: false
+//
+// NB: Predicates that support negative Boolean assertions have reduced
+// performance in positive ones so be careful not to use them in tests
+// that have lots (tens of thousands) of positive Boolean assertions.
+//
+// To use this class with EXPECT_PRED_FORMAT assertions such as:
+//
+// // Verifies that Foo() returns an even number.
+// EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you need to define:
+//
+// testing::AssertionResult IsEven(const char* expr, int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure()
+// << "Expected: " << expr << " is even\n Actual: it's " << n;
+// }
+//
+// If Foo() returns 5, you will see the following message:
+//
+// Expected: Foo() is even
+// Actual: it's 5
+//
+class GTEST_API_ AssertionResult
+{
+ public:
+ // Copy constructor.
+ // Used in EXPECT_TRUE/FALSE(assertion_result).
+ AssertionResult(const AssertionResult& other);
+ // Used in the EXPECT_TRUE/FALSE(bool_expression).
+ explicit AssertionResult(bool success) : success_(success) {}
+
+ // Returns true iff the assertion succeeded.
+ operator bool() const { return success_; } // NOLINT
+
+ // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+ AssertionResult operator!() const;
+
+ // Returns the text streamed into this AssertionResult. Test assertions
+ // use it when they fail (i.e., the predicate's outcome doesn't match the
+ // assertion's expectation). When nothing has been streamed into the
+ // object, returns an empty string.
+ const char* message() const {
+ return message_.get() != NULL ? message_->c_str() : "";
+ }
+ // TODO(vladl at google.com): Remove this after making sure no clients use it.
+ // Deprecated; please use message() instead.
+ const char* failure_message() const { return message(); }
+
+ // Streams a custom failure message into this object.
+ template <typename T> AssertionResult& operator<<(const T& value) {
+ AppendMessage(Message() << value);
+ return *this;
+ }
+
+ // Allows streaming basic output manipulators such as endl or flush into
+ // this object.
+ AssertionResult& operator<<(
+ ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) {
+ AppendMessage(Message() << basic_manipulator);
+ return *this;
+ }
+
+ private:
+ // Appends the contents of message to message_.
+ void AppendMessage(const Message& a_message) {
+ if (message_.get() == NULL)
+ message_.reset(new ::std::string);
+ message_->append(a_message.GetString().c_str());
+ }
+
+ // Stores result of the assertion predicate.
+ bool success_;
+ // Stores the message describing the condition in case the expectation
+ // construct is not satisfied with the predicate's outcome.
+ // Referenced via a pointer to avoid taking too much stack frame space
+ // with test assertions.
+ internal::scoped_ptr< ::std::string> message_;
+
+ GTEST_DISALLOW_ASSIGN_(AssertionResult);
+};
+
+// Makes a successful assertion result.
+GTEST_API_ AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result.
+GTEST_API_ AssertionResult AssertionFailure();
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << msg.
+GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { ... }
+// virtual void TearDown() { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test
+{
+ public:
+ friend class TestInfo;
+
+ // Defines types for pointers to functions that set up and tear down
+ // a test case.
+ typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+ typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+ // The d'tor is virtual as we intend to inherit from Test.
+ virtual ~Test();
+
+ // Sets up the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::SetUpTestCase() before running the first
+ // test in test case Foo. Hence a sub-class can define its own
+ // SetUpTestCase() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestCase() {}
+
+ // Tears down the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::TearDownTestCase() after running the last
+ // test in test case Foo. Hence a sub-class can define its own
+ // TearDownTestCase() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestCase() {}
+
+ // Returns true iff the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Returns true iff the current test has a non-fatal failure.
+ static bool HasNonfatalFailure();
+
+ // Returns true iff the current test has a (either fatal or
+ // non-fatal) failure.
+ static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+ // Logs a property for the current test, test case, or for the entire
+ // invocation of the test program when used outside of the context of a
+ // test case. Only the last value for a given key is remembered. These
+ // are public static so they can be called from utility functions that are
+ // not members of the test fixture. Calls to RecordProperty made during
+ // lifespan of the test (from the moment its constructor starts to the
+ // moment its destructor finishes) will be output in XML as attributes of
+ // the <testcase> element. Properties recorded from fixture's
+ // SetUpTestCase or TearDownTestCase are logged as attributes of the
+ // corresponding <testsuite> element. Calls to RecordProperty made in the
+ // global context (before or after invocation of RUN_ALL_TESTS and from
+ // SetUp/TearDown method of Environment objects registered with Google
+ // Test) will be output as attributes of the <testsuites> element.
+ static void RecordProperty(const std::string& key, const std::string& value);
+ static void RecordProperty(const std::string& key, int value);
+
+ protected:
+ // Creates a Test object.
+ Test();
+
+ // Sets up the test fixture.
+ virtual void SetUp();
+
+ // Tears down the test fixture.
+ virtual void TearDown();
+
+ private:
+ // Returns true iff the current test has the same fixture class as
+ // the first test in the current test case.
+ static bool HasSameFixtureClass();
+
+ // Runs the test after the test fixture has been set up.
+ //
+ // A sub-class must implement this to define the test logic.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+ // Instead, use the TEST or TEST_F macro.
+ virtual void TestBody() = 0;
+
+ // Sets up, executes, and tears down the test.
+ void Run();
+
+ // Deletes self. We deliberately pick an unusual name for this
+ // internal method to avoid clashing with names used in user TESTs.
+ void DeleteSelf_() { delete this; }
+
+ // Uses a GTestFlagSaver to save and restore all Google Test flags.
+ const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+ // Often a user mis-spells SetUp() as Setup() and spends a long time
+ // wondering why it is never called by Google Test. The declaration of
+ // the following method is solely for catching such an error at
+ // compile time:
+ //
+ // - The return type is deliberately chosen to be not void, so it
+ // will be a conflict if a user declares void Setup() in his test
+ // fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if a user calls it from his test fixture.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION.
+ //
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+ // We disallow copying Tests.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+typedef internal::TimeInMillis TimeInMillis;
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty
+{
+ public:
+ // C'tor. TestProperty does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestProperty object.
+ TestProperty(const std::string& a_key, const std::string& a_value) :
+ key_(a_key), value_(a_value) {
+ }
+
+ // Gets the user supplied key.
+ const char* key() const {
+ return key_.c_str();
+ }
+
+ // Gets the user supplied value.
+ const char* value() const {
+ return value_.c_str();
+ }
+
+ // Sets a new value, overriding the one supplied in the constructor.
+ void SetValue(const std::string& new_value) {
+ value_ = new_value;
+ }
+
+ private:
+ // The key supplied by the user.
+ std::string key_;
+ // The value supplied by the user.
+ std::string value_;
+};
+
+// The result of a single Test. This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class GTEST_API_ TestResult
+{
+ public:
+ // Creates an empty TestResult.
+ TestResult();
+
+ // D'tor. Do not inherit from TestResult.
+ ~TestResult();
+
+ // Gets the number of all test parts. This is the sum of the number
+ // of successful test parts and the number of failed test parts.
+ int total_part_count() const;
+
+ // Returns the number of the test properties.
+ int test_property_count() const;
+
+ // Returns true iff the test passed (i.e. no test part failed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test failed.
+ bool Failed() const;
+
+ // Returns true iff the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns true iff the test has a non-fatal failure.
+ bool HasNonfatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns the i-th test part result among all the results. i can range
+ // from 0 to test_property_count() - 1. If i is not in that range, aborts
+ // the program.
+ const TestPartResult& GetTestPartResult(int i) const;
+
+ // Returns the i-th test property. i can range from 0 to
+ // test_property_count() - 1. If i is not in that range, aborts the
+ // program.
+ const TestProperty& GetTestProperty(int i) const;
+
+ private:
+ friend class TestInfo;
+ friend class TestCase;
+ friend class UnitTest;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::ExecDeathTest;
+ friend class internal::TestResultAccessor;
+ friend class internal::UnitTestImpl;
+ friend class internal::WindowsDeathTest;
+
+ // Gets the vector of TestPartResults.
+ const std::vector<TestPartResult>& test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the vector of TestProperties.
+ const std::vector<TestProperty>& test_properties() const {
+ return test_properties_;
+ }
+
+ // Sets the elapsed time.
+ void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+ // Adds a test property to the list. The property is validated and may add
+ // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+ // key names). If a property is already recorded for the same key, the
+ // value will be updated, rather than storing multiple values for the same
+ // key. xml_element specifies the element for which the property is being
+ // recorded and is used for validation.
+ void RecordProperty(const std::string& xml_element,
+ const TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testcase tags. Returns true if the property is valid.
+ // TODO(russr): Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const std::string& xml_element,
+ const TestProperty& test_property);
+
+ // Adds a test part result to the list.
+ void AddTestPartResult(const TestPartResult& test_part_result);
+
+ // Returns the death test count.
+ int death_test_count() const { return death_test_count_; }
+
+ // Increments the death test count, returning the new count.
+ int increment_death_test_count() { return ++death_test_count_; }
+
+ // Clears the test part results.
+ void ClearTestPartResults();
+
+ // Clears the object.
+ void Clear();
+
+ // Protects mutable state of the property vector and of owned
+ // properties, whose values may be updated.
+ internal::Mutex test_properites_mutex_;
+
+ // The vector of TestPartResults
+ std::vector<TestPartResult> test_part_results_;
+ // The vector of TestProperties
+ std::vector<TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+}; // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+// Test case name
+// Test name
+// Whether the test should be run
+// A function pointer that creates the test object when invoked
+// Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class GTEST_API_ TestInfo
+{
+ public:
+ // Destructs a TestInfo object. This function is not virtual, so
+ // don't inherit from TestInfo.
+ ~TestInfo();
+
+ // Returns the test case name.
+ const char* test_case_name() const { return test_case_name_.c_str(); }
+
+ // Returns the test name.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the name of the parameter type, or NULL if this is not a typed
+ // or a type-parameterized test.
+ const char* type_param() const {
+ if (type_param_.get() != NULL)
+ return type_param_->c_str();
+ return NULL;
+ }
+
+ // Returns the text representation of the value parameter, or NULL if this
+ // is not a value-parameterized test.
+ const char* value_param() const {
+ if (value_param_.get() != NULL)
+ return value_param_->c_str();
+ return NULL;
+ }
+
+ // Returns true if this test should run, that is if the test is not
+ // disabled (or it is disabled but the also_run_disabled_tests flag has
+ // been specified) and its full name matches the user-specified filter.
+ //
+ // Google Test allows the user to filter the tests by their full names.
+ // The full name of a test Bar in test case Foo is defined as
+ // "Foo.Bar". Only the tests that match the filter will run.
+ //
+ // A filter is a colon-separated list of glob (not regex) patterns,
+ // optionally followed by a '-' and a colon-separated list of
+ // negative patterns (tests to exclude). A test is run if it
+ // matches one of the positive patterns and does not match any of
+ // the negative patterns.
+ //
+ // For example, *A*:Foo.* is a filter that matches any string that
+ // contains the character 'A' or starts with "Foo.".
+ bool should_run() const { return should_run_; }
+
+ // Returns true iff this test will appear in the XML report.
+ bool is_reportable() const {
+ // For now, the XML report includes all tests matching the filter.
+ // In the future, we may trim tests that are excluded because of
+ // sharding.
+ return matches_filter_;
+ }
+
+ // Returns the result of the test.
+ const TestResult* result() const { return &result_; }
+
+ private:
+#if GTEST_HAS_DEATH_TEST
+ friend class internal::DefaultDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+ friend class Test;
+ friend class TestCase;
+ friend class internal::UnitTestImpl;
+ friend class internal::StreamingListenerTest;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_case_name,
+ const char* name,
+ const char* type_param,
+ const char* value_param,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
+
+ // Constructs a TestInfo object. The newly constructed instance assumes
+ // ownership of the factory object.
+ TestInfo(const std::string& test_case_name,
+ const std::string& name,
+ const char* a_type_param, // NULL if not a type-parameterized test
+ const char* a_value_param, // NULL if not a value-parameterized test
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+
+ // Increments the number of death tests encountered in this test so
+ // far.
+ int increment_death_test_count() {
+ return result_.increment_death_test_count();
+ }
+
+ // Creates the test object, runs it, records its result, and then
+ // deletes it.
+ void Run();
+
+ static void ClearTestResult(TestInfo* test_info) {
+ test_info->result_.Clear();
+ }
+
+ // These fields are immutable properties of the test.
+ const std::string test_case_name_; // Test case name
+ const std::string name_; // Test name
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const internal::scoped_ptr<const ::std::string> type_param_;
+ // Text representation of the value parameter, or NULL if this is not a
+ // value-parameterized test.
+ const internal::scoped_ptr<const ::std::string> value_param_;
+ const internal::TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True iff this test should run
+ bool is_disabled_; // True iff this test is disabled
+ bool matches_filter_; // True if this test matches the
+ // user-specified filter.
+ internal::TestFactoryBase* const factory_; // The factory that creates
+ // the test object
+
+ // This field is mutable and needs to be reset before running the
+ // test for the second time.
+ TestResult result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// A test case, which consists of a vector of TestInfos.
+//
+// TestCase is not copyable.
+class GTEST_API_ TestCase
+{
+ public:
+ // Creates a TestCase with the given name.
+ //
+ // TestCase does NOT have a default constructor. Always use this
+ // constructor to create a TestCase object.
+ //
+ // Arguments:
+ //
+ // name: name of the test case
+ // a_type_param: the name of the test's type parameter, or NULL if
+ // this is not a type-parameterized test.
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase(const char* name, const char* a_type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Destructor of TestCase.
+ virtual ~TestCase();
+
+ // Gets the name of the TestCase.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the name of the parameter type, or NULL if this is not a
+ // type-parameterized test case.
+ const char* type_param() const {
+ if (type_param_.get() != NULL)
+ return type_param_->c_str();
+ return NULL;
+ }
+
+ // Returns true if any test in this test case should run.
+ bool should_run() const { return should_run_; }
+
+ // Gets the number of successful tests in this test case.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests in this test case.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests in this test case.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Get the number of tests in this test case that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test case.
+ int total_test_count() const;
+
+ // Returns true iff the test case passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test case failed.
+ bool Failed() const { return failed_test_count() > 0; }
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ const TestInfo* GetTestInfo(int i) const;
+
+ // Returns the TestResult that holds test properties recorded during
+ // execution of SetUpTestCase and TearDownTestCase.
+ const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
+
+ private:
+ friend class Test;
+ friend class internal::UnitTestImpl;
+
+ // Gets the (mutable) vector of TestInfos in this TestCase.
+ std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+ // Gets the (immutable) vector of TestInfos in this TestCase.
+ const std::vector<TestInfo*>& test_info_list() const {
+ return test_info_list_;
+ }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ TestInfo* GetMutableTestInfo(int i);
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Adds a TestInfo to this test case. Will delete the TestInfo upon
+ // destruction of the TestCase object.
+ void AddTestInfo(TestInfo* test_info);
+
+ // Clears the results of all tests in this test case.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test case.
+ static void ClearTestCaseResult(TestCase* test_case) {
+ test_case->ClearResult();
+ }
+
+ // Runs every test in this TestCase.
+ void Run();
+
+ // Runs SetUpTestCase() for this TestCase. This wrapper is needed
+ // for catching exceptions thrown from SetUpTestCase().
+ void RunSetUpTestCase() { (*set_up_tc_)(); }
+
+ // Runs TearDownTestCase() for this TestCase. This wrapper is
+ // needed for catching exceptions thrown from TearDownTestCase().
+ void RunTearDownTestCase() { (*tear_down_tc_)(); }
+
+ // Returns true iff test passed.
+ static bool TestPassed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Passed();
+ }
+
+ // Returns true iff test failed.
+ static bool TestFailed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Failed();
+ }
+
+ // Returns true iff the test is disabled and will be reported in the XML
+ // report.
+ static bool TestReportableDisabled(const TestInfo* test_info) {
+ return test_info->is_reportable() && test_info->is_disabled_;
+ }
+
+ // Returns true iff test is disabled.
+ static bool TestDisabled(const TestInfo* test_info) {
+ return test_info->is_disabled_;
+ }
+
+ // Returns true iff this test will appear in the XML report.
+ static bool TestReportable(const TestInfo* test_info) {
+ return test_info->is_reportable();
+ }
+
+ // Returns true if the given test should run.
+ static bool ShouldRunTest(const TestInfo* test_info) {
+ return test_info->should_run();
+ }
+
+ // Shuffles the tests in this test case.
+ void ShuffleTests(internal::Random* random);
+
+ // Restores the test order to before the first shuffle.
+ void UnshuffleTests();
+
+ // Name of the test case.
+ std::string name_;
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const internal::scoped_ptr<const ::std::string> type_param_;
+ // The vector of TestInfos in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestInfo*> test_info_list_;
+ // Provides a level of indirection for the test list to allow easy
+ // shuffling and restoring the test order. The i-th element in this
+ // vector is the index of the i-th test in the shuffled test list.
+ std::vector<int> test_indices_;
+ // Pointer to the function that sets up the test case.
+ Test::SetUpTestCaseFunc set_up_tc_;
+ // Pointer to the function that tears down the test case.
+ Test::TearDownTestCaseFunc tear_down_tc_;
+ // True iff any test in this test case should run.
+ bool should_run_;
+ // Elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+ // Holds test properties recorded during execution of SetUpTestCase and
+ // TearDownTestCase.
+ TestResult ad_hoc_test_result_;
+
+ // We disallow copying TestCases.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+// 1. You cannot safely throw from a destructor. This is a problem
+// as in some cases Google Test is used where exceptions are enabled, and
+// we may want to implement ASSERT_* using exceptions where they are
+// available.
+// 2. You cannot use ASSERT_* directly in a constructor or
+// destructor.
+class Environment
+{
+ public:
+ // The d'tor is virtual as we need to subclass Environment.
+ virtual ~Environment() {}
+
+ // Override this to define how to set up the environment.
+ virtual void SetUp() {}
+
+ // Override this to define how to tear down the environment.
+ virtual void TearDown() {}
+ private:
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// The interface for tracing execution of tests. The methods are organized in
+// the order the corresponding events are fired.
+class TestEventListener
+{
+ public:
+ virtual ~TestEventListener() {}
+
+ // Fired before any test activity starts.
+ virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
+
+ // Fired before each iteration of tests starts. There may be more than
+ // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
+ // index, starting from 0.
+ virtual void OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired before environment set-up for each iteration of tests starts.
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment set-up for each iteration of tests ends.
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
+
+ // Fired before the test case starts.
+ virtual void OnTestCaseStart(const TestCase& test_case) = 0;
+
+ // Fired before the test starts.
+ virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+ // Fired after a failed assertion or a SUCCEED() invocation.
+ virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
+
+ // Fired after the test ends.
+ virtual void OnTestEnd(const TestInfo& test_info) = 0;
+
+ // Fired after the test case ends.
+ virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
+
+ // Fired before environment tear-down for each iteration of tests starts.
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment tear-down for each iteration of tests ends.
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
+
+ // Fired after each iteration of tests finishes.
+ virtual void OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired after all test activities have ended.
+ virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
+};
+
+// The convenience class for users who need to override just one or two
+// methods and are not concerned that a possible change to a signature of
+// the methods they override will not be caught during the build. For
+// comments about each method please see the definition of TestEventListener
+// above.
+class EmptyTestEventListener : public TestEventListener
+{
+ public:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {}
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+ virtual void OnTestStart(const TestInfo& /*test_info*/) {}
+ virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
+ virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {}
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+};
+
+// TestEventListeners lets users add listeners to track events in Google Test.
+class GTEST_API_ TestEventListeners
+{
+ public:
+ TestEventListeners();
+ ~TestEventListeners();
+
+ // Appends an event listener to the end of the list. Google Test assumes
+ // the ownership of the listener (i.e. it will delete the listener when
+ // the test program finishes).
+ void Append(TestEventListener* listener);
+
+ // Removes the given event listener from the list and returns it. It then
+ // becomes the caller's responsibility to delete the listener. Returns
+ // NULL if the listener is not found in the list.
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Returns the standard listener responsible for the default console
+ // output. Can be removed from the listeners list to shut down default
+ // console output. Note that removing this object from the listener list
+ // with Release transfers its ownership to the caller and makes this
+ // function return NULL the next time.
+ TestEventListener* default_result_printer() const {
+ return default_result_printer_;
+ }
+
+ // Returns the standard listener responsible for the default XML output
+ // controlled by the --gtest_output=xml flag. Can be removed from the
+ // listeners list by users who want to shut down the default XML output
+ // controlled by this flag and substitute it with custom one. Note that
+ // removing this object from the listener list with Release transfers its
+ // ownership to the caller and makes this function return NULL the next
+ // time.
+ TestEventListener* default_xml_generator() const {
+ return default_xml_generator_;
+ }
+
+ private:
+ friend class TestCase;
+ friend class TestInfo;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::NoExecDeathTest;
+ friend class internal::TestEventListenersAccessor;
+ friend class internal::UnitTestImpl;
+
+ // Returns repeater that broadcasts the TestEventListener events to all
+ // subscribers.
+ TestEventListener* repeater();
+
+ // Sets the default_result_printer attribute to the provided listener.
+ // The listener is also added to the listener list and previous
+ // default_result_printer is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultResultPrinter(TestEventListener* listener);
+
+ // Sets the default_xml_generator attribute to the provided listener. The
+ // listener is also added to the listener list and previous
+ // default_xml_generator is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultXmlGenerator(TestEventListener* listener);
+
+ // Controls whether events will be forwarded by the repeater to the
+ // listeners in the list.
+ bool EventForwardingEnabled() const;
+ void SuppressEventForwarding();
+
+ // The actual list of listeners.
+ internal::TestEventRepeater* repeater_;
+ // Listener responsible for the standard result output.
+ TestEventListener* default_result_printer_;
+ // Listener responsible for the creation of the XML output file.
+ TestEventListener* default_xml_generator_;
+
+ // We disallow copying TestEventListeners.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
+};
+
+// A UnitTest consists of a vector of TestCases.
+//
+// This is a singleton class. The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called. This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class GTEST_API_ UnitTest
+{
+ public:
+ // Gets the singleton UnitTest object. The first time this method
+ // is called, a UnitTest object is constructed and returned.
+ // Consecutive calls will return the same object.
+ static UnitTest* GetInstance();
+
+ // Runs all tests in this UnitTest object and prints the result.
+ // Returns 0 if successful, or 1 otherwise.
+ //
+ // This method can only be called from the main thread.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ int Run() GTEST_MUST_USE_RESULT_;
+
+ // Returns the working directory when the first TEST() or TEST_F()
+ // was executed. The UnitTest object owns the string.
+ const char* original_working_dir() const;
+
+ // Returns the TestCase object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestCase* current_test_case() const
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Returns the random seed used at the start of the current test run.
+ int random_seed() const;
+
+#if GTEST_HAS_PARAM_TEST
+ // Returns the ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
+ GTEST_LOCK_EXCLUDED_(mutex_);
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const;
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const;
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const;
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ const TestCase* GetTestCase(int i) const;
+
+ // Returns the TestResult containing information on test failures and
+ // properties logged outside of individual test cases.
+ const TestResult& ad_hoc_test_result() const;
+
+ // Returns the list of event listeners that can be used to track events
+ // inside Google Test.
+ TestEventListeners& listeners();
+
+ private:
+ // Registers and returns a global test environment. When a test
+ // program is run, all global test environments will be set-up in
+ // the order they were registered. After all tests in the program
+ // have finished, all global test environments will be torn-down in
+ // the *reverse* order they were registered.
+ //
+ // The UnitTest object takes ownership of the given environment.
+ //
+ // This method can only be called from the main thread.
+ Environment* AddEnvironment(Environment* env);
+
+ // Adds a TestPartResult to the current TestResult object. All
+ // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+ // eventually call this to report their results. The user code
+ // should use the assertion macros instead of calling this directly.
+ void AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const std::string& message,
+ const std::string& os_stack_trace)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Adds a TestProperty to the current TestResult object when invoked from
+ // inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+ // from SetUpTestCase or TearDownTestCase, or to the global property set
+ // when invoked elsewhere. If the result already contains a property with
+ // the same key, the value will be updated.
+ void RecordProperty(const std::string& key, const std::string& value);
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ TestCase* GetMutableTestCase(int i);
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+
+ // These classes and funcions are friends as they need to access private
+ // members of UnitTest.
+ friend class Test;
+ friend class internal::AssertHelper;
+ friend class internal::ScopedTrace;
+ friend class internal::StreamingListenerTest;
+ friend class internal::UnitTestRecordPropertyTestHelper;
+ friend Environment* AddGlobalTestEnvironment(Environment* env);
+ friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+ friend void internal::ReportFailureInUnknownLocation(
+ TestPartResult::Type result_type,
+ const std::string& message);
+
+ // Creates an empty UnitTest.
+ UnitTest();
+
+ // D'tor
+ virtual ~UnitTest();
+
+ // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+ // Google Test trace stack.
+ void PushGTestTrace(const internal::TraceInfo& trace)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace()
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Protects mutable state in *impl_. This is mutable as some const
+ // methods need to lock it too.
+ mutable internal::Mutex mutex_;
+
+ // Opaque implementation object. This field is never changed once
+ // the object is constructed. We don't mark it as const here, as
+ // doing so will cause a warning in the constructor of UnitTest.
+ // Mutable state in *impl_ is protected by mutex_.
+ internal::UnitTestImpl* impl_;
+
+ // We disallow copying UnitTest.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main(). If you use gtest_main, you need to call this before main()
+// starts for it to take effect. For example, you can define a global
+// variable like this:
+//
+// testing::Environment* const foo_env =
+// testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env)
+{
+ return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+GTEST_API_ void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal
+{
+
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value. In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object. If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison
+{
+ public:
+ static ::std::string Format(const ToPrint& value) {
+ return ::testing::PrintToString(value);
+ }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand>
+{
+ public:
+ static ::std::string Format(const ToPrint* value) {
+ return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+ }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
+ template <typename OtherOperand> \
+ class FormatForComparison<CharType*, OtherOperand> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(static_cast<const void*>(value)); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+ template <> \
+ class FormatForComparison<CharType*, OtherStringType> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(value); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
+#endif
+
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(
+ const T1& value, const T2& /* other_operand */)
+{
+ return FormatForComparison<T1, T2>::Format(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual)
+{
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4389) // Temporarily disables warning on
+ // signed/unsigned mismatch.
+#endif
+
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ. The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal. The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper
+{
+ public:
+ // This templatized version is for the general case.
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // With this overloaded version, we allow anonymous enums to be used
+ // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+ // enums can be implicitly cast to BiggestInt.
+ //
+ // Even though its body looks the same as the above version, we
+ // cannot merge the two, as it will make anonymous enums unhappy.
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal, like NULL, false, or 0.
+template <>
+class EqHelper<true>
+{
+ public:
+ // We define two overloaded versions of Compare(). The first
+ // version will be picked when the second argument to ASSERT_EQ() is
+ // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+ // EXPECT_EQ(false, a_bool).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(
+ const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual,
+ // The following line prevents this overload from being considered if T2
+ // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr)
+ // expands to Compare("", "", NULL, my_ptr), which requires a conversion
+ // to match the Secret* in the other overload, which would otherwise make
+ // this template match better.
+ typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // This version will be picked when the second argument to ASSERT_EQ() is a
+ // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+ template <typename T>
+ static AssertionResult Compare(
+ const char* expected_expression,
+ const char* actual_expression,
+ // We used to have a second template parameter instead of Secret*. That
+ // template parameter would deduce to 'long', making this a better match
+ // than the first overload even without the first overload's EnableIf.
+ // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
+ // non-pointer argument" (even a deduced integral argument), so the old
+ // implementation caused warnings in user code.
+ Secret* /* expected (NULL) */,
+ T* actual) {
+ // We already know that 'expected' is a null pointer.
+ return CmpHelperEQ(expected_expression, actual_expression,
+ static_cast<T*>(NULL), actual);
+ }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ return AssertionFailure() \
+ << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ }\
+}\
+GTEST_API_ AssertionResult CmpHelper##op_name(\
+ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=);
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=);
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, <);
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=);
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, >);
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+} // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves. They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal
+{
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+ const char* actual_expression,
+ RawType expected,
+ RawType actual)
+{
+ const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ ::std::stringstream expected_ss;
+ expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << expected;
+
+ ::std::stringstream actual_ss;
+ actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << actual;
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ StringStreamToString(&expected_ss),
+ StringStreamToString(&actual_ss),
+ false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class GTEST_API_ AssertHelper
+{
+ public:
+ // Constructor.
+ AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message);
+ ~AssertHelper();
+
+ // Message assignment is a semantic trick to enable assertion
+ // streaming; see the GTEST_MESSAGE_ macro below.
+ void operator=(const Message& message) const;
+
+ private:
+ // We put our data in a struct so that the size of the AssertHelper class can
+ // be as small as possible. This is important because gcc is incapable of
+ // re-using stack space even for temporary variables, so every EXPECT_EQ
+ // reserves stack space for another AssertHelper.
+ struct AssertHelperData {
+ AssertHelperData(TestPartResult::Type t,
+ const char* srcfile,
+ int line_num,
+ const char* msg)
+ : type(t), file(srcfile), line(line_num), message(msg) { }
+
+ TestPartResult::Type const type;
+ const char* const file;
+ int const line;
+ std::string const message;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
+ };
+
+ AssertHelperData* const data_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+} // namespace internal
+
+#if GTEST_HAS_PARAM_TEST
+// The pure interface class that all value-parameterized tests inherit from.
+// A value-parameterized class must inherit from both ::testing::Test and
+// ::testing::WithParamInterface. In most cases that just means inheriting
+// from ::testing::TestWithParam, but more complicated test hierarchies
+// may need to inherit from Test and WithParamInterface at different levels.
+//
+// This interface has support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+// protected:
+// FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual ~FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual void SetUp() {
+// // Can use GetParam() here.
+// }
+// virtual void TearDown {
+// // Can use GetParam() here.
+// }
+// };
+// TEST_P(FooTest, DoesBar) {
+// // Can use GetParam() method here.
+// Foo foo;
+// ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class WithParamInterface
+{
+ public:
+ typedef T ParamType;
+ virtual ~WithParamInterface() {}
+
+ // The current parameter value. Is also available in the test fixture's
+ // constructor. This member function is non-static, even though it only
+ // references static data, to reduce the opportunity for incorrect uses
+ // like writing 'WithParamInterface<bool>::GetParam()' for a test that
+ // uses a fixture whose parameter type is int.
+ const ParamType& GetParam() const {
+ GTEST_CHECK_(parameter_ != NULL)
+ << "GetParam() can only be called inside a value-parameterized test "
+ << "-- did you intend to write TEST_P instead of TEST_F?";
+ return *parameter_;
+ }
+
+ private:
+ // Sets parameter value. The caller is responsible for making sure the value
+ // remains alive and unchanged throughout the current test.
+ static void SetParam(const ParamType* parameter) {
+ parameter_ = parameter;
+ }
+
+ // Static value used for accessing parameter during a test lifetime.
+ static const ParamType* parameter_;
+
+ // TestClass must be a subclass of WithParamInterface<T> and Test.
+ template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* WithParamInterface<T>::parameter_ = NULL;
+
+// Most value-parameterized classes can ignore the existence of
+// WithParamInterface, and can just inherit from ::testing::TestWithParam.
+
+template <typename T>
+class TestWithParam : public Test, public WithParamInterface<T>
+{
+};
+
+#endif // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied. If not,
+// it behaves like ADD_FAILURE. In particular:
+//
+// EXPECT_TRUE verifies that a Boolean condition is true.
+// EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure. People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a nonfatal failure at the given source file location with
+// a generic message.
+#define ADD_FAILURE_AT(file, line) \
+ GTEST_MESSAGE_AT_(file, line, "Failed", \
+ ::testing::TestPartResult::kNonFatalFailure)
+
+// Generates a fatal failure with a generic message.
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+# define FAIL() GTEST_FAIL()
+#endif
+
+// Generates a success with a generic message.
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+# define SUCCEED() GTEST_SUCCEED()
+#endif
+
+// Macros for testing exceptions.
+//
+// * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+// Tests that the statement throws the expected exception.
+// * {ASSERT|EXPECT}_NO_THROW(statement):
+// Tests that the statement doesn't throw any exception.
+// * {ASSERT|EXPECT}_ANY_THROW(statement):
+// Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions. Condition can be either a Boolean expression or an
+// AssertionResult. For more information on how to use AssertionResult with
+// these macros see comments on that class.
+#define EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+#include "gtest/gtest_pred_impl.h"
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values. The values must be compatible built-in types,
+// or you will get a compiler error. By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+// 1. It is possible to make a user-defined type work with
+// {ASSERT|EXPECT}_??(), but that requires overloading the
+// comparison operators and is thus discouraged by the Google C++
+// Usage Guide. Therefore, you are advised to use the
+// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+// equal.
+//
+// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+// pointers (in particular, C strings). Therefore, if you use it
+// with two C strings, you are testing how their locations in memory
+// are related, not how their content is related. To compare two C
+// strings by content, use {ASSERT|EXPECT}_STR*().
+//
+// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+// what the actual value is when it fails, and similarly for the
+// other comparisons.
+//
+// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+// evaluate their arguments, which is undefined.
+//
+// 5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+// EXPECT_NE(5, Foo());
+// EXPECT_EQ(NULL, a_pointer);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define EXPECT_NE(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define GTEST_ASSERT_EQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define GTEST_ASSERT_NE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define GTEST_ASSERT_LE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define GTEST_ASSERT_LT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define GTEST_ASSERT_GE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define GTEST_ASSERT_GT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
+// ASSERT_XY(), which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_ASSERT_EQ
+# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_NE
+# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LE
+# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LT
+# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GE
+# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GT
+# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
+#endif
+
+// C-string Comparisons. All tests treat NULL and any non-NULL string
+// as different. Two NULLs are equal.
+//
+// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
+// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
+// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+// Tests that two double values are almost equal.
+// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+// Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands. See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2);
+GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+# define EXPECT_HRESULT_SUCCEEDED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define ASSERT_HRESULT_SUCCEEDED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define EXPECT_HRESULT_FAILED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+# define ASSERT_HRESULT_FAILED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+// EXPECT_NO_FATAL_FAILURE(Process());
+// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope. The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, ::testing::Message() << (message))
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
+// the same type. The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template. This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated. For example, given:
+//
+// template <typename T> class Foo {
+// public:
+// void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+// };
+//
+// the code:
+//
+// void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated. Instead, you need:
+//
+// void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+bool StaticAssertTypeEq()
+{
+ (void)internal::StaticAssertTypeEqHelper<T1, T2>();
+ return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test". For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro. Example:
+//
+// TEST(FooTest, InitializesCorrectly) {
+// Foo foo;
+// EXPECT_TRUE(foo.StatusIsOK());
+// }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test. This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X. The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code. GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define GTEST_TEST(test_case_name, test_name)\
+ GTEST_TEST_(test_case_name, test_name, \
+ ::testing::Test, ::testing::internal::GetTestTypeId())
+
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#endif
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name. The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier. The user should put
+// his test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(0, a_.size());
+// EXPECT_EQ(1, b_.size());
+// }
+
+#define TEST_F(test_fixture, test_name)\
+ GTEST_TEST_(test_fixture, test_name, test_fixture, \
+ ::testing::internal::GetTypeId<test_fixture>())
+
+} // namespace testing
+
+// Use this function in main() to run all tests. It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+//
+// This function was formerly a macro; thus, it is in the global
+// namespace and has an all-caps name.
+int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
+
+inline int RUN_ALL_TESTS()
+{
+ return ::testing::UnitTest::GetInstance()->Run();
+}
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest_pred_impl.h b/external/gtest-1.6.0/include/gtest/gtest_pred_impl.h
new file mode 100644
index 0000000..001eca7
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest_pred_impl.h
@@ -0,0 +1,363 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework at googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \
+ ; \
+ else \
+ on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+ const char* e1,
+ Pred pred,
+ const T1& v1)
+{
+ if (pred(v1)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, v1), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+ #v1, \
+ pred, \
+ v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ Pred pred,
+ const T1& v1,
+ const T2& v2)
+{
+ if (pred(v1, v2)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+ #v1, \
+ #v2, \
+ pred, \
+ v1, \
+ v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3)
+{
+ if (pred(v1, v2, v3)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ pred, \
+ v1, \
+ v2, \
+ v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4)
+{
+ if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5)
+{
+ if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+ return AssertionFailure() << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ", "
+ << e5 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4
+ << "\n" << e5 << " evaluates to " << v5;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ #v5, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4, \
+ v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/external/gtest-1.6.0/include/gtest/gtest_prod.h b/external/gtest-1.6.0/include/gtest/gtest_prod.h
new file mode 100644
index 0000000..da80ddc
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/gtest_prod.h
@@ -0,0 +1,58 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class. For example:
+//
+// class MyClass {
+// private:
+// void MyMethod();
+// FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+// // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/CMakeLists.txt b/external/gtest-1.6.0/include/gtest/internal/CMakeLists.txt
new file mode 100644
index 0000000..95d885d
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/CMakeLists.txt
@@ -0,0 +1,7 @@
+
+file(GLOB gtestFiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
+foreach(gtestFile ${gtestFiles})
+ configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/${gtestFile}" "${CMAKE_CURRENT_BINARY_DIR}/${gtestFile}" COPYONLY )
+# install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${gtestFile}" DESTINATION include/gtest/internal)
+endforeach(gtestFile)
+
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-death-test-internal.h b/external/gtest-1.6.0/include/gtest/internal/gtest-death-test-internal.h
new file mode 100644
index 0000000..be43ae4
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-death-test-internal.h
@@ -0,0 +1,326 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan at google.com (Zhanyong Wan), eefacm at gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include "gtest/internal/gtest-internal.h"
+
+#include <stdio.h>
+
+namespace testing
+{
+namespace internal
+{
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status: The integer exit information in the format specified
+// by wait(2)
+// exit code: The integer code passed to exit(3), _exit(2), or
+// returned from main()
+class GTEST_API_ DeathTest
+{
+ public:
+ // Create returns false if there was an error determining the
+ // appropriate action to take for the current death test; for example,
+ // if the gtest_death_test_style flag is set to an invalid value.
+ // The LastMessage method will return a more detailed message in that
+ // case. Otherwise, the DeathTest pointer pointed to by the "test"
+ // argument is set. If the death test should be skipped, the pointer
+ // is set to NULL; otherwise, it is set to the address of a new concrete
+ // DeathTest object that controls the execution of the current test.
+ static bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+ DeathTest();
+ virtual ~DeathTest() { }
+
+ // A helper class that aborts a death test when it's deleted.
+ class ReturnSentinel
+ {
+ public:
+ explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+ ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+ private:
+ DeathTest* const test_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+ } GTEST_ATTRIBUTE_UNUSED_;
+
+ // An enumeration of possible roles that may be taken when a death
+ // test is encountered. EXECUTE means that the death test logic should
+ // be executed immediately. OVERSEE means that the program should prepare
+ // the appropriate environment for a child process to execute the death
+ // test, then wait for it to complete.
+ enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+ // An enumeration of the three reasons that a test might be aborted.
+ enum AbortReason {
+ TEST_ENCOUNTERED_RETURN_STATEMENT,
+ TEST_THREW_EXCEPTION,
+ TEST_DID_NOT_DIE
+ };
+
+ // Assumes one of the above roles.
+ virtual TestRole AssumeRole() = 0;
+
+ // Waits for the death test to finish and returns its status.
+ virtual int Wait() = 0;
+
+ // Returns true if the death test passed; that is, the test process
+ // exited during the test, its exit status matches a user-supplied
+ // predicate, and its stderr output matches a user-supplied regular
+ // expression.
+ // The user-supplied predicate may be a macro expression rather
+ // than a function pointer or functor, or else Wait and Passed could
+ // be combined.
+ virtual bool Passed(bool exit_status_ok) = 0;
+
+ // Signals that the death test did not die as expected.
+ virtual void Abort(AbortReason reason) = 0;
+
+ // Returns a human-readable outcome message regarding the outcome of
+ // the last death test.
+ static const char* LastMessage();
+
+ static void set_last_death_test_message(const std::string& message);
+
+ private:
+ // A string containing a description of the outcome of the last death test.
+ static std::string last_death_test_message_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory
+{
+ public:
+ virtual ~DeathTestFactory() { }
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory
+{
+ public:
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+
+// Traps C++ exceptions escaping statement and reports them as test
+// failures. Note that trapping SEH exceptions is not implemented here.
+# if GTEST_HAS_EXCEPTIONS
+# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (const ::std::exception& gtest_exception) { \
+ fprintf(\
+ stderr, \
+ "\n%s: Caught std::exception-derived exception escaping the " \
+ "death test statement. Exception message: %s\n", \
+ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
+ gtest_exception.what()); \
+ fflush(stderr); \
+ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+ } catch (...) { \
+ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+ }
+
+# else
+# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+
+# endif
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ const ::testing::internal::RE& gtest_regex = (regex); \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
+ __FILE__, __LINE__, >est_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != NULL) { \
+ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+ gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel \
+ gtest_sentinel(gtest_dt); \
+ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ default: \
+ break; \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+ fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
+// NDEBUG mode. In this case we need the statements to be executed, the regex is
+// ignored, and the macro must accept a streamed message even though the message
+// is never printed.
+# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } else \
+ ::testing::Message()
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag
+{
+ public:
+ InternalRunDeathTestFlag(const std::string& a_file,
+ int a_line,
+ int an_index,
+ int a_write_fd)
+ : file_(a_file), line_(a_line), index_(an_index),
+ write_fd_(a_write_fd) {}
+
+ ~InternalRunDeathTestFlag() {
+ if (write_fd_ >= 0)
+ posix::Close(write_fd_);
+ }
+
+ const std::string& file() const { return file_; }
+ int line() const { return line_; }
+ int index() const { return index_; }
+ int write_fd() const { return write_fd_; }
+
+ private:
+ std::string file_;
+ int line_;
+ int index_;
+ int write_fd_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#else // GTEST_HAS_DEATH_TEST
+
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
+// systems that support death tests. This allows one to write such a macro
+// on a system that does not support death tests and be sure that it will
+// compile on a death-test supporting system.
+//
+// Parameters:
+// statement - A statement that a macro such as EXPECT_DEATH would test
+// for program termination. This macro has to make sure this
+// statement is compiled but not executed, to ensure that
+// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+// parameter iff EXPECT_DEATH compiles with it.
+// regex - A regex that a macro such as EXPECT_DEATH would use to test
+// the output of statement. This parameter has to be
+// compiled but not evaluated by this macro, to ensure that
+// this macro only accepts expressions that a macro such as
+// EXPECT_DEATH would accept.
+// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+// compile inside functions where ASSERT_DEATH doesn't
+// compile.
+//
+// The branch that has an always false condition is used to ensure that
+// statement and regex are compiled (and thus syntactically correct) but
+// never executed. The unreachable code macro protects the terminator
+// statement from generating an 'unreachable code' warning in case
+// statement unconditionally returns or throws. The Message constructor at
+// the end allows the syntax of streaming additional messages into the
+// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_LOG_(WARNING) \
+ << "Death tests are not supported on this platform.\n" \
+ << "Statement '" #statement "' cannot be verified."; \
+ } else if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::RE::PartialMatch(".*", (regex)); \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ terminator; \
+ } else \
+ ::testing::Message()
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-filepath.h b/external/gtest-1.6.0/include/gtest/internal/gtest-filepath.h
new file mode 100644
index 0000000..5e76eb0
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-filepath.h
@@ -0,0 +1,209 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray at gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included in <gtest/internal/gtest-internal.h>.
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#include "gtest/internal/gtest-string.h"
+
+namespace testing
+{
+namespace internal
+{
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class GTEST_API_ FilePath
+{
+ public:
+ FilePath() : pathname_("") { }
+ FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+ explicit FilePath(const std::string& pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ FilePath& operator=(const FilePath& rhs) {
+ Set(rhs);
+ return *this;
+ }
+
+ void Set(const FilePath& rhs) {
+ pathname_ = rhs.pathname_;
+ }
+
+ const std::string& string() const { return pathname_; }
+ const char* c_str() const { return pathname_.c_str(); }
+
+ // Returns the current working directory, or "" if unsuccessful.
+ static FilePath GetCurrentDir();
+
+ // Given directory = "dir", base_name = "test", number = 0,
+ // extension = "xml", returns "dir/test.xml". If number is greater
+ // than zero (e.g., 12), returns "dir/test_12.xml".
+ // On Windows platform, uses \ as the separator rather than /.
+ static FilePath MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension);
+
+ // Given directory = "dir", relative_path = "test.xml",
+ // returns "dir/test.xml".
+ // On Windows, uses \ as the separator rather than /.
+ static FilePath ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path);
+
+ // Returns a pathname for a file that does not currently exist. The pathname
+ // will be directory/base_name.extension or
+ // directory/base_name_<number>.extension if directory/base_name.extension
+ // already exists. The number will be incremented until a pathname is found
+ // that does not already exist.
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+ // There could be a race condition if two or more processes are calling this
+ // function at the same time -- they could both pick the same filename.
+ static FilePath GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension);
+
+ // Returns true iff the path is "".
+ bool IsEmpty() const { return pathname_.empty(); }
+
+ // If input name has a trailing separator character, removes it and returns
+ // the name, otherwise return the name string unmodified.
+ // On Windows platform, uses \ as the separator, other platforms use /.
+ FilePath RemoveTrailingPathSeparator() const;
+
+ // Returns a copy of the FilePath with the directory part removed.
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+ // returns an empty FilePath ("").
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveDirectoryName() const;
+
+ // RemoveFileName returns the directory path with the filename removed.
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveFileName() const;
+
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+ // FilePath("dir/file"). If a case-insensitive extension is not
+ // found, returns a copy of the original FilePath.
+ FilePath RemoveExtension(const char* extension) const;
+
+ // Creates directories so that path exists. Returns true if successful or if
+ // the directories already exist; returns false if unable to create
+ // directories for any reason. Will also return false if the FilePath does
+ // not represent a directory (that is, it doesn't end with a path separator).
+ bool CreateDirectoriesRecursively() const;
+
+ // Create the directory so that path exists. Returns true if successful or
+ // if the directory already exists; returns false if unable to create the
+ // directory for any reason, including if the parent directory does not
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
+ bool CreateFolder() const;
+
+ // Returns true if FilePath describes something in the file-system,
+ // either a file, directory, or whatever, and that something exists.
+ bool FileOrDirectoryExists() const;
+
+ // Returns true if pathname describes a directory in the file-system
+ // that exists.
+ bool DirectoryExists() const;
+
+ // Returns true if FilePath ends with a path separator, which indicates that
+ // it is intended to represent a directory. Returns false otherwise.
+ // This does NOT check that a directory (or file) actually exists.
+ bool IsDirectory() const;
+
+ // Returns true if pathname describes a root directory. (Windows has one
+ // root directory per disk drive.)
+ bool IsRootDirectory() const;
+
+ // Returns true if pathname describes an absolute path.
+ bool IsAbsolutePath() const;
+
+ private:
+ // Replaces multiple consecutive separators with a single separator.
+ // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+ // redundancies that might be in a pathname involving "." or "..".
+ //
+ // A pathname with multiple consecutive separators may occur either through
+ // user error or as a result of some scripts or APIs that generate a pathname
+ // with a trailing separator. On other platforms the same API or script
+ // may NOT generate a pathname with a trailing "/". Then elsewhere that
+ // pathname may have another "/" and pathname components added to it,
+ // without checking for the separator already being there.
+ // The script language and operating system may allow paths like "foo//bar"
+ // but some of the functions in FilePath will not handle that correctly. In
+ // particular, RemoveTrailingPathSeparator() only removes one separator, and
+ // it is called in CreateDirectoriesRecursively() assuming that it will change
+ // a pathname from directory syntax (trailing separator) to filename syntax.
+ //
+ // On Windows this method also replaces the alternate path separator '/' with
+ // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
+ // "bar\\foo".
+
+ void Normalize();
+
+ // Returns a pointer to the last occurence of a valid path separator in
+ // the FilePath. On Windows, for example, both '/' and '\' are valid path
+ // separators. Returns NULL if no path separator was found.
+ const char* FindLastPathSeparator() const;
+
+ std::string pathname_;
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-internal.h b/external/gtest-1.6.0/include/gtest/internal/gtest-internal.h
new file mode 100644
index 0000000..e12c307
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-internal.h
@@ -0,0 +1,1172 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan at google.com (Zhanyong Wan), eefacm at gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_OS_LINUX
+# include <stdlib.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-string.h"
+#include "gtest/internal/gtest-filepath.h"
+#include "gtest/internal/gtest-type-util.h"
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__. Writing
+//
+// foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number. For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+class ProtocolMessage;
+namespace proto2 { class Message; }
+
+namespace testing
+{
+
+// Forward declarations.
+
+class AssertionResult; // Result of an assertion.
+class Message; // Represents a failure message.
+class Test; // Represents a test.
+class TestInfo; // Information about a test.
+class TestPartResult; // Result of a test part.
+class UnitTest; // A collection of test cases.
+
+template <typename T>
+::std::string PrintToString(const T& value);
+
+namespace internal
+{
+
+struct TraceInfo; // Information about a trace point.
+class ScopedTrace; // Implements scoped trace.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+// How many times InitGoogleTest() has been called.
+GTEST_API_ extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant). Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler. These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise. Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal. Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char(&IsNullLiteralHelper(...))[2]; // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_POD_
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_IS_NULL_LITERAL_(x) false
+#else
+# define GTEST_IS_NULL_LITERAL_(x) \
+ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif // GTEST_ELLIPSIS_NEEDS_POD_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ std::string AppendUserMessage(
+ const std::string& gtest_msg, const Message& user_msg);
+
+#if GTEST_HAS_EXCEPTIONS
+
+// This exception is thrown by (and only by) a failed Google Test
+// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
+// are enabled). We derive it from std::runtime_error, which is for
+// errors presumably detectable only at run time. Since
+// std::runtime_error inherits from std::exception, many testing
+// frameworks know how to extract and print the message inside it.
+class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error
+{
+ public:
+ explicit GoogleTestFailureException(const TestPartResult& failure);
+};
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// A helper class for creating scoped traces in user programs.
+class GTEST_API_ ScopedTrace
+{
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+ ScopedTrace(const char* file, int line, const Message& message);
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
+// c'tor and d'tor. Therefore it doesn't
+// need to be used otherwise.
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const std::string& expected_value,
+ const std::string& actual_value,
+ bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ std::string GetBoolAssertionFailureMessage(
+ const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value);
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison. (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly. Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+// The most-significant bit being the leftmost, an IEEE
+// floating-point looks like
+//
+// sign_bit exponent_bits fraction_bits
+//
+// Here, sign_bit is a single bit that designates the sign of the
+// number.
+//
+// For float, there are 8 exponent bits and 23 fraction bits.
+//
+// For double, there are 11 exponent bits and 52 fraction bits.
+//
+// More details can be found at
+// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint
+{
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+ // Constants.
+
+ // # of bits in a number.
+ static const size_t kBitCount = 8*sizeof(RawType);
+
+ // # of fraction bits in a number.
+ static const size_t kFractionBitCount =
+ std::numeric_limits<RawType>::digits - 1;
+
+ // # of exponent bits in a number.
+ static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+ // The mask for the sign bit.
+ static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask =
+ ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+ // The mask for the exponent bits.
+ static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+ // How many ULP's (Units in the Last Place) we want to tolerate when
+ // comparing two numbers. The larger the value, the more error we
+ // allow. A 0 value means that two numbers must be exactly the same
+ // to be considered equal.
+ //
+ // The maximum error of a single floating-point operation is 0.5
+ // units in the last place. On Intel CPU's, all floating-point
+ // calculations are done with 80-bit precision, while double has 64
+ // bits. Therefore, 4 should be enough for ordinary use.
+ //
+ // See the following article for more details on ULP:
+ // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ static const size_t kMaxUlps = 4;
+
+ // Constructs a FloatingPoint from a raw floating-point number.
+ //
+ // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+ // around may change its bits, although the new value is guaranteed
+ // to be also a NAN. Therefore, don't expect this constructor to
+ // preserve the bits in x when x is a NAN.
+ explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+ // Static methods
+
+ // Reinterprets a bit pattern as a floating-point number.
+ //
+ // This function is needed to test the AlmostEquals() method.
+ static RawType ReinterpretBits(const Bits bits) {
+ FloatingPoint fp(0);
+ fp.u_.bits_ = bits;
+ return fp.u_.value_;
+ }
+
+ // Returns the floating-point number that represent positive infinity.
+ static RawType Infinity() {
+ return ReinterpretBits(kExponentBitMask);
+ }
+
+ // Non-static methods
+
+ // Returns the bits that represents this number.
+ const Bits& bits() const { return u_.bits_; }
+
+ // Returns the exponent bits of this number.
+ Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+ // Returns the fraction bits of this number.
+ Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+ // Returns the sign bit of this number.
+ Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+ // Returns true iff this is NAN (not a number).
+ bool is_nan() const {
+ // It's a NAN if the exponent bits are all ones and the fraction
+ // bits are not entirely zeros.
+ return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+ }
+
+ // Returns true iff this number is at most kMaxUlps ULP's away from
+ // rhs. In particular, this function:
+ //
+ // - returns false if either number is (or both are) NAN.
+ // - treats really large numbers as almost equal to infinity.
+ // - thinks +0.0 and -0.0 are 0 DLP's apart.
+ bool AlmostEquals(const FloatingPoint& rhs) const {
+ // The IEEE standard says that any comparison operation involving
+ // a NAN must return false.
+ if (is_nan() || rhs.is_nan()) return false;
+
+ return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+ <= kMaxUlps;
+ }
+
+ private:
+ // The data type used to store the actual floating-point number.
+ union FloatingPointUnion {
+ RawType value_; // The raw floating-point number.
+ Bits bits_; // The bits that represent the number.
+ };
+
+ // Converts an integer from the sign-and-magnitude representation to
+ // the biased representation. More precisely, let N be 2 to the
+ // power of (kBitCount - 1), an integer x is represented by the
+ // unsigned number x + N.
+ //
+ // For instance,
+ //
+ // -N + 1 (the most negative number representable using
+ // sign-and-magnitude) is represented by 1;
+ // 0 is represented by N; and
+ // N - 1 (the biggest number representable using
+ // sign-and-magnitude) is represented by 2N - 1.
+ //
+ // Read http://en.wikipedia.org/wiki/Signed_number_representations
+ // for more details on signed number representations.
+ static Bits SignAndMagnitudeToBiased(const Bits& sam) {
+ if (kSignBitMask & sam) {
+ // sam represents a negative number.
+ return ~sam + 1;
+ } else {
+ // sam represents a positive number.
+ return kSignBitMask | sam;
+ }
+ }
+
+ // Given two numbers in the sign-and-magnitude representation,
+ // returns the distance between them as an unsigned number.
+ static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits& sam1,
+ const Bits& sam2) {
+ const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+ const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+ return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+ }
+
+ FloatingPointUnion u_;
+};
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them. The TypeId type is
+// used to hold such IDs. The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper
+{
+ public:
+ // dummy_ must not have a const type. Otherwise an overly eager
+ // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+ // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+ static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T. Different values will be
+// returned for different types. Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId()
+{
+ // The compiler is required to allocate a different
+ // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+ // the template. Therefore, the address of dummy_ is guaranteed to
+ // be unique.
+ return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test. Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+GTEST_API_ TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase
+{
+ public:
+ virtual ~TestFactoryBase() {}
+
+ // Creates a test instance to run. The instance is both created and destroyed
+ // within TestInfoImpl::Run()
+ virtual Test* CreateTest() = 0;
+
+ protected:
+ TestFactoryBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase
+{
+ public:
+ virtual Test* CreateTest() { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
+ long hr); // NOLINT
+GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
+ long hr); // NOLINT
+
+#endif // GTEST_OS_WINDOWS
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// type_param the name of the test's type parameter, or NULL if
+// this is not a typed or a type-parameterized test.
+// value_param text representation of the test's value parameter,
+// or NULL if this is not a type-parameterized test.
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name,
+ const char* name,
+ const char* type_param,
+ const char* value_param,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory);
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// State of the definition of a type-parameterized test case.
+class GTEST_API_ TypedTestCasePState
+{
+ public:
+ TypedTestCasePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test case hasn't been registered; otherwise aborts the
+ // program.
+ bool AddTestName(const char* file, int line, const char* case_name,
+ const char* test_name) {
+ if (registered_) {
+ fprintf(stderr, "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ fflush(stderr);
+ posix::Abort();
+ }
+ defined_test_names_.insert(test_name);
+ return true;
+ }
+
+ // Verifies that registered_tests match the test names in
+ // defined_test_names_; returns registered_tests if successful, or
+ // aborts the program otherwise.
+ const char* VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests);
+
+ private:
+ bool registered_;
+ ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str)
+{
+ const char* comma = strchr(str, ',');
+ if (comma == NULL) {
+ return NULL;
+ }
+ while (IsSpace(*(++comma))) {}
+ return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline std::string GetPrefixUntilComma(const char* str)
+{
+ const char* comma = strchr(str, ',');
+ return comma == NULL ? str : std::string(str, comma);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test. The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter. It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest
+{
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+ // Types). Valid values for 'index' are [0, N - 1] where N is the
+ // length of Types.
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names, int index) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
+ + StreamableToString(index)).c_str(),
+ GetPrefixUntilComma(test_names).c_str(),
+ GetTypeName<Type>().c_str(),
+ NULL, // No value parameter.
+ GetTypeId<FixtureClass>(),
+ TestClass::SetUpTestCase,
+ TestClass::TearDownTestCase,
+ new TestFactoryImpl<TestClass>);
+
+ // Next, recurses (at compile time) with the tail of the type list.
+ return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+ ::Register(prefix, case_name, test_names, index + 1);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0>
+{
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/, int /*index*/) {
+ return true;
+ }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test. The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase
+{
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, case_name, test_names, 0);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+ ::Register(prefix, case_name, SkipComma(test_names));
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types>
+{
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/) {
+ return true;
+ }
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
+ UnitTest* unit_test, int skip_count);
+
+// Helpers for suppressing warnings on unreachable code or constant
+// condition.
+
+// Always returns true.
+GTEST_API_ bool AlwaysTrue();
+
+// Always returns false.
+inline bool AlwaysFalse() { return !AlwaysTrue(); }
+
+// Helper for suppressing false warning from Clang on a const char*
+// variable declared in a conditional expression always being NULL in
+// the else branch.
+struct GTEST_API_ ConstCharPtr {
+ ConstCharPtr(const char* str) : value(str) {}
+ operator bool() const { return true; }
+ const char* value;
+};
+
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution. Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code). Unlike rand_r(), it's portable. An LCG isn't very random,
+// but it's good enough for our purposes.
+class GTEST_API_ Random
+{
+ public:
+ static const UInt32 kMaxRange = 1u << 31;
+
+ explicit Random(UInt32 seed) : state_(seed) {}
+
+ void Reseed(UInt32 seed) { state_ = seed; }
+
+ // Generates a random number from [0, range). Crashes if 'range' is
+ // 0 or greater than kMaxRange.
+ UInt32 Generate(UInt32 range);
+
+ private:
+ UInt32 state_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
+// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
+// compiler error iff T1 and T2 are different types.
+template <typename T1, typename T2>
+struct CompileAssertTypesEqual;
+
+template <typename T>
+struct CompileAssertTypesEqual<T, T> {
+};
+
+// Removes the reference from a type if it is a reference type,
+// otherwise leaves it unchanged. This is the same as
+// tr1::remove_reference, which is not widely available yet.
+template <typename T>
+struct RemoveReference { typedef T type; }; // NOLINT
+template <typename T>
+struct RemoveReference<T&> { typedef T type; }; // NOLINT
+
+// A handy wrapper around RemoveReference that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_REFERENCE_(T) \
+ typename ::testing::internal::RemoveReference<T>::type
+
+// Removes const from a type if it is a const type, otherwise leaves
+// it unchanged. This is the same as tr1::remove_const, which is not
+// widely available yet.
+template <typename T>
+struct RemoveConst { typedef T type; }; // NOLINT
+template <typename T>
+struct RemoveConst<const T> { typedef T type; }; // NOLINT
+
+// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
+// definition to fail to remove the const in 'const int[3]' and 'const
+// char[3][4]'. The following specialization works around the bug.
+template <typename T, size_t N>
+struct RemoveConst<const T[N]> {
+ typedef typename RemoveConst<T>::type type[N];
+};
+
+#if defined(_MSC_VER) && _MSC_VER < 1400
+// This is the only specialization that allows VC++ 7.1 to remove const in
+// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC
+// and thus needs to be conditionally compiled.
+template <typename T, size_t N>
+struct RemoveConst<T[N]> {
+ typedef typename RemoveConst<T>::type type[N];
+};
+#endif
+
+// A handy wrapper around RemoveConst that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_CONST_(T) \
+ typename ::testing::internal::RemoveConst<T>::type
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
+
+// Adds reference to a type if it is not a reference type,
+// otherwise leaves it unchanged. This is the same as
+// tr1::add_reference, which is not widely available yet.
+template <typename T>
+struct AddReference { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddReference<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper around AddReference that works when the argument T
+// depends on template parameters.
+#define GTEST_ADD_REFERENCE_(T) \
+ typename ::testing::internal::AddReference<T>::type
+
+// Adds a reference to const on top of T as necessary. For example,
+// it transforms
+//
+// char ==> const char&
+// const char ==> const char&
+// char& ==> const char&
+// const char& ==> const char&
+//
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))
+
+// ImplicitlyConvertible<From, To>::value is a compile-time bool
+// constant that's true iff type From can be implicitly converted to
+// type To.
+template <typename From, typename To>
+class ImplicitlyConvertible
+{
+ private:
+ // We need the following helper functions only for their types.
+ // They have no implementations.
+
+ // MakeFrom() is an expression whose type is From. We cannot simply
+ // use From(), as the type From may not have a public default
+ // constructor.
+ static From MakeFrom();
+
+ // These two functions are overloaded. Given an expression
+ // Helper(x), the compiler will pick the first version if x can be
+ // implicitly converted to type To; otherwise it will pick the
+ // second version.
+ //
+ // The first version returns a value of size 1, and the second
+ // version returns a value of size 2. Therefore, by checking the
+ // size of Helper(x), which can be done at compile time, we can tell
+ // which version of Helper() is used, and hence whether x can be
+ // implicitly converted to type To.
+ static char Helper(To);
+ static char(&Helper(...))[2]; // NOLINT
+
+ // We have to put the 'public' section after the 'private' section,
+ // or MSVC refuses to compile the code.
+ public:
+ // MSVC warns about implicitly converting from double to int for
+ // possible loss of data, so we need to temporarily disable the
+ // warning.
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4244) // Temporarily disables warning 4244.
+
+ static const bool value =
+ sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+# pragma warning(pop) // Restores the warning state.
+#elif defined(__BORLANDC__)
+ // C++Builder cannot use member overload resolution during template
+ // instantiation. The simplest workaround is to use its C++0x type traits
+ // functions (C++Builder 2009 and above only).
+ static const bool value = __is_convertible(From, To);
+#else
+ static const bool value =
+ sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+#endif // _MSV_VER
+};
+template <typename From, typename To>
+const bool ImplicitlyConvertible<From, To>::value;
+
+// IsAProtocolMessage<T>::value is a compile-time bool constant that's
+// true iff T is type ProtocolMessage, proto2::Message, or a subclass
+// of those.
+template <typename T>
+struct IsAProtocolMessage
+ : public bool_constant<
+ ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
+ ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
+};
+
+// When the compiler sees expression IsContainerTest<C>(0), if C is an
+// STL-style container class, the first overload of IsContainerTest
+// will be viable (since both C::iterator* and C::const_iterator* are
+// valid types and NULL can be implicitly converted to them). It will
+// be picked over the second overload as 'int' is a perfect match for
+// the type of argument 0. If C::iterator or C::const_iterator is not
+// a valid type, the first overload is not viable, and the second
+// overload will be picked. Therefore, we can determine whether C is
+// a container class by checking the type of IsContainerTest<C>(0).
+// The value of the expression is insignificant.
+//
+// Note that we look for both C::iterator and C::const_iterator. The
+// reason is that C++ injects the name of a class as a member of the
+// class itself (e.g. you can refer to class iterator as either
+// 'iterator' or 'iterator::iterator'). If we look for C::iterator
+// only, for example, we would mistakenly think that a class named
+// iterator is an STL container.
+//
+// Also note that the simpler approach of overloading
+// IsContainerTest(typename C::const_iterator*) and
+// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
+typedef int IsContainer;
+template <class C>
+IsContainer IsContainerTest(int /* dummy */,
+ typename C::iterator* /* it */ = NULL,
+ typename C::const_iterator* /* const_it */ = NULL)
+{
+ return 0;
+}
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
+
+// EnableIf<condition>::type is void when 'Cond' is true, and
+// undefined when 'Cond' is false. To use SFINAE to make a function
+// overload only apply when a particular expression is true, add
+// "typename EnableIf<expression>::type* = 0" as the last parameter.
+template<bool> struct EnableIf;
+template<> struct EnableIf<true> { typedef void type; }; // NOLINT
+
+// Utilities for native arrays.
+
+// ArrayEq() compares two k-dimensional native arrays using the
+// elements' operator==, where k can be any integer >= 0. When k is
+// 0, ArrayEq() degenerates into comparing a single pair of values.
+
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N])
+{
+ return internal::ArrayEq(lhs, N, rhs);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous ArrayEq() function, arrays with different sizes would
+// lead to different copies of the template code.
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs)
+{
+ for (size_t i = 0; i != size; i++) {
+ if (!internal::ArrayEq(lhs[i], rhs[i]))
+ return false;
+ }
+ return true;
+}
+
+// Finds the first element in the iterator range [begin, end) that
+// equals elem. Element may be a native array type itself.
+template <typename Iter, typename Element>
+Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem)
+{
+ for (Iter it = begin; it != end; ++it) {
+ if (internal::ArrayEq(*it, elem))
+ return it;
+ }
+ return end;
+}
+
+// CopyArray() copies a k-dimensional native array using the elements'
+// operator=, where k can be any integer >= 0. When k is 0,
+// CopyArray() degenerates into copying a single value.
+
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) { *to = from; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline void CopyArray(const T(&from)[N], U(*to)[N])
+{
+ internal::CopyArray(from, N, *to);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous CopyArray() function, arrays with different sizes
+// would lead to different copies of the template code.
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to)
+{
+ for (size_t i = 0; i != size; i++) {
+ internal::CopyArray(from[i], to + i);
+ }
+}
+
+// The relation between an NativeArray object (see below) and the
+// native array it represents.
+enum RelationToSource {
+ kReference, // The NativeArray references the native array.
+ kCopy // The NativeArray makes a copy of the native array and
+ // owns the copy.
+};
+
+// Adapts a native array to a read-only STL-style container. Instead
+// of the complete STL container concept, this adaptor only implements
+// members useful for Google Mock's container matchers. New members
+// should be added as needed. To simplify the implementation, we only
+// support Element being a raw type (i.e. having no top-level const or
+// reference modifier). It's the client's responsibility to satisfy
+// this requirement. Element can be an array type itself (hence
+// multi-dimensional arrays are supported).
+template <typename Element>
+class NativeArray
+{
+ public:
+ // STL-style container typedefs.
+ typedef Element value_type;
+ typedef Element* iterator;
+ typedef const Element* const_iterator;
+
+ // Constructs from a native array.
+ NativeArray(const Element* array, size_t count, RelationToSource relation) {
+ Init(array, count, relation);
+ }
+
+ // Copy constructor.
+ NativeArray(const NativeArray& rhs) {
+ Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+ }
+
+ ~NativeArray() {
+ // Ensures that the user doesn't instantiate NativeArray with a
+ // const or reference type.
+ static_cast<void>(StaticAssertTypeEqHelper<Element,
+ GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
+ if (relation_to_source_ == kCopy)
+ delete[] array_;
+ }
+
+ // STL-style container methods.
+ size_t size() const { return size_; }
+ const_iterator begin() const { return array_; }
+ const_iterator end() const { return array_ + size_; }
+ bool operator==(const NativeArray& rhs) const {
+ return size() == rhs.size() &&
+ ArrayEq(begin(), size(), rhs.begin());
+ }
+
+ private:
+ // Initializes this object; makes a copy of the input array if
+ // 'relation' is kCopy.
+ void Init(const Element* array, size_t a_size, RelationToSource relation) {
+ if (relation == kReference) {
+ array_ = array;
+ } else {
+ Element* const copy = new Element[a_size];
+ CopyArray(array, a_size, copy);
+ array_ = copy;
+ }
+ size_ = a_size;
+ relation_to_source_ = relation;
+ }
+
+ const Element* array_;
+ size_t size_;
+ RelationToSource relation_to_source_;
+
+ GTEST_DISALLOW_ASSIGN_(NativeArray);
+};
+
+} // namespace internal
+} // namespace testing
+
+#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
+ ::testing::internal::AssertHelper(result_type, file, line, message) \
+ = ::testing::Message()
+
+#define GTEST_MESSAGE_(message, result_type) \
+ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)
+
+#define GTEST_FATAL_FAILURE_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
+
+#define GTEST_SUCCESS_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
+
+// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+ if (::testing::internal::AlwaysTrue()) { statement; }
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::ConstCharPtr gtest_msg = "") { \
+ bool gtest_caught_expected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (expected_exception const&) { \
+ gtest_caught_expected = true; \
+ } \
+ catch (...) { \
+ gtest_msg.value = \
+ "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws a different type."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ if (!gtest_caught_expected) { \
+ gtest_msg.value = \
+ "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws nothing."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+ fail(gtest_msg.value)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+ fail("Expected: " #statement " doesn't throw an exception.\n" \
+ " Actual: it throws.")
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ bool gtest_caught_any = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ gtest_caught_any = true; \
+ } \
+ if (!gtest_caught_any) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+ fail("Expected: " #statement " throws an exception.\n" \
+ " Actual: it doesn't.")
+
+
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
+// either a boolean expression or an AssertionResult. text is a textual
+// represenation of expression as it was passed into the EXPECT_TRUE.
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar_ = \
+ ::testing::AssertionResult(expression)) \
+ ; \
+ else \
+ fail(::testing::internal::GetBoolAssertionFailureMessage(\
+ gtest_ar_, text, #actual, #expected).c_str())
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+ fail("Expected: " #statement " doesn't generate new fatal " \
+ "failures in the current thread.\n" \
+ " Actual: it does.")
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+ virtual void TestBody();\
+ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+ ::test_info_ =\
+ ::testing::internal::MakeAndRegisterTestInfo(\
+ #test_case_name, #test_name, NULL, NULL, \
+ (parent_id), \
+ parent_class::SetUpTestCase, \
+ parent_class::TearDownTestCase, \
+ new ::testing::internal::TestFactoryImpl<\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-linked_ptr.h b/external/gtest-1.6.0/include/gtest/internal/gtest-linked_ptr.h
new file mode 100644
index 0000000..b903697
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-linked_ptr.h
@@ -0,0 +1,240 @@
+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor at google.com)
+//
+// A "smart" pointer type with reference tracking. Every pointer to a
+// particular object is kept on a circular linked list. When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+// object is traversed. This class is therefore NOT SUITABLE when there
+// will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+// will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+// Unlike other linked_ptr implementations, in this implementation
+// a linked_ptr object is thread-safe in the sense that:
+// - it's safe to copy linked_ptr objects concurrently,
+// - it's safe to copy *from* a linked_ptr and read its underlying
+// raw pointer (e.g. via get()) concurrently, and
+// - it's safe to write to two linked_ptrs that point to the same
+// shared object concurrently.
+// TODO(wan at google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "gtest/internal/gtest-port.h"
+
+namespace testing
+{
+namespace internal
+{
+
+// Protects copying of all linked_ptr objects.
+GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// This is used internally by all instances of linked_ptr<>. It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
+class linked_ptr_internal
+{
+ public:
+ // Create a new circle that includes only this instance.
+ void join_new() {
+ next_ = this;
+ }
+
+ // Many linked_ptr operations may change p.link_ for some linked_ptr
+ // variable p in the same circle as this object. Therefore we need
+ // to prevent two such operations from occurring concurrently.
+ //
+ // Note that different types of linked_ptr objects can coexist in a
+ // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+ // linked_ptr<Derived2>). Therefore we must use a single mutex to
+ // protect all linked_ptr objects. This can create serious
+ // contention in production code, but is acceptable in a testing
+ // framework.
+
+ // Join an existing circle.
+ void join(linked_ptr_internal const* ptr)
+ GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ linked_ptr_internal const* p = ptr;
+ while (p->next_ != ptr) p = p->next_;
+ p->next_ = this;
+ next_ = ptr;
+ }
+
+ // Leave whatever circle we're part of. Returns true if we were the
+ // last member of the circle. Once this is done, you can join() another.
+ bool depart()
+ GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ if (next_ == this) return true;
+ linked_ptr_internal const* p = next_;
+ while (p->next_ != this) p = p->next_;
+ p->next_ = next_;
+ return false;
+ }
+
+ private:
+ mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr
+{
+ public:
+ typedef T element_type;
+
+ // Take over ownership of a raw pointer. This should happen as soon as
+ // possible after the object is created.
+ explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+ ~linked_ptr() { depart(); }
+
+ // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+ template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+ linked_ptr(linked_ptr const& ptr) { // NOLINT
+ assert(&ptr != this);
+ copy(&ptr);
+ }
+
+ // Assignment releases the old value and acquires the new.
+ template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+ depart();
+ copy(&ptr);
+ return *this;
+ }
+
+ linked_ptr& operator=(linked_ptr const& ptr) {
+ if (&ptr != this) {
+ depart();
+ copy(&ptr);
+ }
+ return *this;
+ }
+
+ // Smart pointer members.
+ void reset(T* ptr = NULL) {
+ depart();
+ capture(ptr);
+ }
+ T* get() const { return value_; }
+ T* operator->() const { return value_; }
+ T& operator*() const { return *value_; }
+
+ bool operator==(T* p) const { return value_ == p; }
+ bool operator!=(T* p) const { return value_ != p; }
+ template <typename U>
+ bool operator==(linked_ptr<U> const& ptr) const {
+ return value_ == ptr.get();
+ }
+ template <typename U>
+ bool operator!=(linked_ptr<U> const& ptr) const {
+ return value_ != ptr.get();
+ }
+
+ private:
+ template <typename U>
+ friend class linked_ptr;
+
+ T* value_;
+ linked_ptr_internal link_;
+
+ void depart() {
+ if (link_.depart()) delete value_;
+ }
+
+ void capture(T* ptr) {
+ value_ = ptr;
+ link_.join_new();
+ }
+
+ template <typename U> void copy(linked_ptr<U> const* ptr) {
+ value_ = ptr->get();
+ if (value_)
+ link_.join(&ptr->link_);
+ else
+ link_.join_new();
+ }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x)
+{
+ return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x)
+{
+ return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr)
+{
+ return linked_ptr<T>(ptr);
+}
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-param-util-generated.h b/external/gtest-1.6.0/include/gtest/internal/gtest-param-util-generated.h
new file mode 100644
index 0000000..9eea3f2
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-param-util-generated.h
@@ -0,0 +1,5270 @@
+// This file was GENERATED by command:
+// pump.py gtest-param-util-generated.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework at googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing
+{
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T(&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal
+{
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1
+{
+ public:
+ explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray1& other);
+
+ const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2
+{
+ public:
+ ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray2& other);
+
+ const T1 v1_;
+ const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3
+{
+ public:
+ ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray3& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4
+{
+ public:
+ ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray4& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5
+{
+ public:
+ ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray5& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class ValueArray6
+{
+ public:
+ ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray6& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class ValueArray7
+{
+ public:
+ ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray7& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class ValueArray8
+{
+ public:
+ ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray8& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class ValueArray9
+{
+ public:
+ ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray9& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10
+{
+ public:
+ ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray10& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+class ValueArray11
+{
+ public:
+ ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray11& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+class ValueArray12
+{
+ public:
+ ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray12& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+class ValueArray13
+{
+ public:
+ ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray13& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+class ValueArray14
+{
+ public:
+ ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray14& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15
+{
+ public:
+ ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray15& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+class ValueArray16
+{
+ public:
+ ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray16& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+class ValueArray17
+{
+ public:
+ ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray17& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+class ValueArray18
+{
+ public:
+ ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray18& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+class ValueArray19
+{
+ public:
+ ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray19& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20
+{
+ public:
+ ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray20& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+class ValueArray21
+{
+ public:
+ ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray21& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+class ValueArray22
+{
+ public:
+ ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray22& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+class ValueArray23
+{
+ public:
+ ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray23& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+class ValueArray24
+{
+ public:
+ ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray24& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25
+{
+ public:
+ ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray25& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+class ValueArray26
+{
+ public:
+ ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray26& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+class ValueArray27
+{
+ public:
+ ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray27& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+class ValueArray28
+{
+ public:
+ ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray28& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+class ValueArray29
+{
+ public:
+ ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray29& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30
+{
+ public:
+ ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray30& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+class ValueArray31
+{
+ public:
+ ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray31& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+class ValueArray32
+{
+ public:
+ ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray32& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+class ValueArray33
+{
+ public:
+ ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray33& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+class ValueArray34
+{
+ public:
+ ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray34& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35
+{
+ public:
+ ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray35& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+class ValueArray36
+{
+ public:
+ ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray36& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+class ValueArray37
+{
+ public:
+ ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray37& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+class ValueArray38
+{
+ public:
+ ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray38& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+class ValueArray39
+{
+ public:
+ ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray39& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40
+{
+ public:
+ ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray40& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+class ValueArray41
+{
+ public:
+ ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray41& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+class ValueArray42
+{
+ public:
+ ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray42& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+class ValueArray43
+{
+ public:
+ ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+ v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray43& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+class ValueArray44
+{
+ public:
+ ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+ v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+ v43_(v43), v44_(v44) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray44& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45
+{
+ public:
+ ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+ v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+ static_cast<T>(v45_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray45& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+class ValueArray46
+{
+ public:
+ ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+ static_cast<T>(v45_), static_cast<T>(v46_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray46& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+class ValueArray47
+{
+ public:
+ ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+ v47_(v47) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+ static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray47& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+class ValueArray48
+{
+ public:
+ ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+ v46_(v46), v47_(v47), v48_(v48) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+ static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+ static_cast<T>(v48_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray48& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+class ValueArray49
+{
+ public:
+ ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+ T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+ static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+ static_cast<T>(v48_), static_cast<T>(v49_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray49& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50
+{
+ public:
+ ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+ T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+ static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+ static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+ static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+ static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+ static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+ static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+ static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+ static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+ static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+ static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+ static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+ static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+ static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+ static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+ static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+ static_cast<T>(v48_), static_cast<T>(v49_), static_cast<T>(v50_)
+ };
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray50& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+ const T50 v50_;
+};
+
+# if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+ CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2)
+ : g1_(g1), g2_(g2) {}
+ virtual ~CartesianProductGenerator2() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current2_;
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator2::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator2& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+}; // class CartesianProductGenerator2
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+ CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ virtual ~CartesianProductGenerator3() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current3_;
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator3::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator3& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+}; // class CartesianProductGenerator3
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+ CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ virtual ~CartesianProductGenerator4() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current4_;
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator4::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator4& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+}; // class CartesianProductGenerator4
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+ CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ virtual ~CartesianProductGenerator5() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current5_;
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator5::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator5& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+}; // class CartesianProductGenerator5
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class CartesianProductGenerator6
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+ T6> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+ CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ virtual ~CartesianProductGenerator6() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current6_;
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator6::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator6& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+}; // class CartesianProductGenerator6
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class CartesianProductGenerator7
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+ CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ virtual ~CartesianProductGenerator7() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current7_;
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator7::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator7& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+}; // class CartesianProductGenerator7
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+ CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ virtual ~CartesianProductGenerator8() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current8_;
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator8::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator8& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+}; // class CartesianProductGenerator8
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+ CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ virtual ~CartesianProductGenerator9() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current9_;
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator9::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator9& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+}; // class CartesianProductGenerator9
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9, T10> >
+{
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+ CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+ const ParamGenerator<T10>& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ virtual ~CartesianProductGenerator10() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9,
+ const ParamGenerator<T10>& g10,
+ const typename ParamGenerator<T10>::iterator& current10)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+ begin10_(g10.begin()), end10_(g10.end()), current10_(current10) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current10_;
+ if (current10_ == end10_) {
+ current10_ = begin10_;
+ ++current9_;
+ }
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_ &&
+ current10_ == typed_other->current10_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_),
+ begin10_(other.begin10_),
+ end10_(other.end10_),
+ current10_(other.current10_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_, *current10_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_ ||
+ current10_ == end10_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ const typename ParamGenerator<T10>::iterator begin10_;
+ const typename ParamGenerator<T10>::iterator end10_;
+ typename ParamGenerator<T10>::iterator current10_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator10::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator10& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+ const ParamGenerator<T10> g10_;
+}; // class CartesianProductGenerator10
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2
+{
+ public:
+ CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+ : g1_(g1), g2_(g2) {}
+ template <typename T1, typename T2>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+ new CartesianProductGenerator2<T1, T2>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder2& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+}; // class CartesianProductHolder2
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3
+{
+ public:
+ CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ template <typename T1, typename T2, typename T3>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+ new CartesianProductGenerator3<T1, T2, T3>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder3& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+}; // class CartesianProductHolder3
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4>
+class CartesianProductHolder4
+{
+ public:
+ CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ template <typename T1, typename T2, typename T3, typename T4>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+ new CartesianProductGenerator4<T1, T2, T3, T4>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder4& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+}; // class CartesianProductHolder4
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5>
+class CartesianProductHolder5
+{
+ public:
+ CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+ new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder5& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+}; // class CartesianProductHolder5
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6
+{
+ public:
+ CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+ new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder6& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+}; // class CartesianProductHolder6
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7
+{
+ public:
+ CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+ new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder7& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+}; // class CartesianProductHolder7
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8>
+class CartesianProductHolder8
+{
+ public:
+ CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+ T8> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+ new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder8& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+}; // class CartesianProductHolder8
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9>
+class CartesianProductHolder9
+{
+ public:
+ CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >(
+ new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder9& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+}; // class CartesianProductHolder9
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10
+{
+ public:
+ CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9, const Generator10& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >(
+ new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+ T10>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_),
+ static_cast<ParamGenerator<T10> >(g10_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder10& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+ const Generator10 g10_;
+}; // class CartesianProductHolder10
+
+# endif // GTEST_HAS_COMBINE
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-param-util-generated.h.pump b/external/gtest-1.6.0/include/gtest/internal/gtest-param-util-generated.h.pump
new file mode 100644
index 0000000..009206f
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-param-util-generated.h.pump
@@ -0,0 +1,301 @@
+$$ -*- mode: c++; -*-
+$var n = 50 $$ Maximum length of Values arguments we want to support.
+$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most $n arguments in Values,
+// and at most $maxtuple arguments in Combine. Please contact
+// googletestframework at googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at $maxtuple.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+ explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray1& other);
+
+ const T1 v1_;
+};
+
+$range i 2..n
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename T$j]]>
+class ValueArray$i {
+ public:
+ ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {$for j, [[static_cast<T>(v$(j)_)]]};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray$i& other);
+
+$for j [[
+
+ const T$j v$(j)_;
+]]
+
+};
+
+]]
+
+# if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+$range k 2..i
+
+template <$for j, [[typename T$j]]>
+class CartesianProductGenerator$i
+ : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > {
+ public:
+ typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType;
+
+ CartesianProductGenerator$i($for j, [[const ParamGenerator<T$j>& g$j]])
+ : $for j, [[g$(j)_(g$j)]] {}
+ virtual ~CartesianProductGenerator$i() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]);
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base, $for j, [[
+
+ const ParamGenerator<T$j>& g$j,
+ const typename ParamGenerator<T$j>::iterator& current$(j)]])
+ : base_(base),
+$for j, [[
+
+ begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j)
+]] {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current$(i)_;
+
+$for k [[
+ if (current$(i+2-k)_ == end$(i+2-k)_) {
+ current$(i+2-k)_ = begin$(i+2-k)_;
+ ++current$(i+2-k-1)_;
+ }
+
+]]
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return ¤t_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ ($for j && [[
+
+ current$(j)_ == typed_other->current$(j)_
+]]);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_), $for j, [[
+
+ begin$(j)_(other.begin$(j)_),
+ end$(j)_(other.end$(j)_),
+ current$(j)_(other.current$(j)_)
+]] {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType($for j, [[*current$(j)_]]);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+$for j || [[
+
+ current$(j)_ == end$(j)_
+]];
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+$for j [[
+
+ const typename ParamGenerator<T$j>::iterator begin$(j)_;
+ const typename ParamGenerator<T$j>::iterator end$(j)_;
+ typename ParamGenerator<T$j>::iterator current$(j)_;
+]]
+
+ ParamType current_value_;
+ }; // class CartesianProductGenerator$i::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator$i& other);
+
+
+$for j [[
+ const ParamGenerator<T$j> g$(j)_;
+
+]]
+}; // class CartesianProductGenerator$i
+
+
+]]
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+
+template <$for j, [[class Generator$j]]>
+class CartesianProductHolder$i {
+ public:
+CartesianProductHolder$i($for j, [[const Generator$j& g$j]])
+ : $for j, [[g$(j)_(g$j)]] {}
+ template <$for j, [[typename T$j]]>
+ operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const {
+ return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >(
+ new CartesianProductGenerator$i<$for j, [[T$j]]>(
+$for j,[[
+
+ static_cast<ParamGenerator<T$j> >(g$(j)_)
+]]));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder$i& other);
+
+
+$for j [[
+ const Generator$j g$(j)_;
+
+]]
+}; // class CartesianProductHolder$i
+
+]]
+
+# endif // GTEST_HAS_COMBINE
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-param-util.h b/external/gtest-1.6.0/include/gtest/internal/gtest-param-util.h
new file mode 100644
index 0000000..b7e7acd
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-param-util.h
@@ -0,0 +1,635 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-linked_ptr.h"
+#include "gtest/internal/gtest-port.h"
+#include "gtest/gtest-printers.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing
+{
+namespace internal
+{
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line);
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface
+{
+ public:
+ virtual ~ParamIteratorInterface() {}
+ // A pointer to the base generator instance.
+ // Used only for the purposes of iterator comparison
+ // to make sure that two iterators belong to the same generator.
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+ // Advances iterator to point to the next element
+ // provided by the generator. The caller is responsible
+ // for not calling Advance() on an iterator equal to
+ // BaseGenerator()->End().
+ virtual void Advance() = 0;
+ // Clones the iterator object. Used for implementing copy semantics
+ // of ParamIterator<T>.
+ virtual ParamIteratorInterface* Clone() const = 0;
+ // Dereferences the current iterator and provides (read-only) access
+ // to the pointed value. It is the caller's responsibility not to call
+ // Current() on an iterator equal to BaseGenerator()->End().
+ // Used for implementing ParamGenerator<T>::operator*().
+ virtual const T* Current() const = 0;
+ // Determines whether the given iterator and other point to the same
+ // element in the sequence generated by the generator.
+ // Used for implementing ParamGenerator<T>::operator==().
+ virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator
+{
+ public:
+ typedef T value_type;
+ typedef const T& reference;
+ typedef ptrdiff_t difference_type;
+
+ // ParamIterator assumes ownership of the impl_ pointer.
+ ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+ ParamIterator& operator=(const ParamIterator& other) {
+ if (this != &other)
+ impl_.reset(other.impl_->Clone());
+ return *this;
+ }
+
+ const T& operator*() const { return *impl_->Current(); }
+ const T* operator->() const { return impl_->Current(); }
+ // Prefix version of operator++.
+ ParamIterator& operator++() {
+ impl_->Advance();
+ return *this;
+ }
+ // Postfix version of operator++.
+ ParamIterator operator++(int /*unused*/) {
+ ParamIteratorInterface<T>* clone = impl_->Clone();
+ impl_->Advance();
+ return ParamIterator(clone);
+ }
+ bool operator==(const ParamIterator& other) const {
+ return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+ }
+ bool operator!=(const ParamIterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend class ParamGenerator<T>;
+ explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+ scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface
+{
+ public:
+ typedef T ParamType;
+
+ virtual ~ParamGeneratorInterface() {}
+
+ // Generator interface definition
+ virtual ParamIteratorInterface<T>* Begin() const = 0;
+ virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator
+{
+ public:
+ typedef ParamIterator<T> iterator;
+
+ explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+ ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+ ParamGenerator& operator=(const ParamGenerator& other) {
+ impl_ = other.impl_;
+ return *this;
+ }
+
+ iterator begin() const { return iterator(impl_->Begin()); }
+ iterator end() const { return iterator(impl_->End()); }
+
+ private:
+ linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T>
+{
+ public:
+ RangeGenerator(T begin, T end, IncrementT step)
+ : begin_(begin), end_(end),
+ step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+ virtual ~RangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, begin_, 0, step_);
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, end_, end_index_, step_);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<T>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+ IncrementT step)
+ : base_(base), value_(value), index_(index), step_(step) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ value_ = value_ + step_;
+ index_++;
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const T* Current() const { return &value_; }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const int other_index =
+ CheckedDowncastToActualType<const Iterator>(&other)->index_;
+ return index_ == other_index;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : ParamIteratorInterface<T>(),
+ base_(other.base_), value_(other.value_), index_(other.index_),
+ step_(other.step_) {}
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<T>* const base_;
+ T value_;
+ int index_;
+ const IncrementT step_;
+ }; // class RangeGenerator::Iterator
+
+ static int CalculateEndIndex(const T& begin,
+ const T& end,
+ const IncrementT& step) {
+ int end_index = 0;
+ for (T i = begin; i < end; i = i + step)
+ end_index++;
+ return end_index;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const RangeGenerator& other);
+
+ const T begin_;
+ const T end_;
+ const IncrementT step_;
+ // The index for the end() iterator. All the elements in the generated
+ // sequence are indexed (0-based) to aid iterator comparison.
+ const int end_index_;
+}; // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T>
+{
+ public:
+ template <typename ForwardIterator>
+ ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+ : container_(begin, end) {}
+ virtual ~ValuesInIteratorRangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, container_.begin());
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, container_.end());
+ }
+
+ private:
+ typedef typename ::std::vector<T> ContainerType;
+
+ class Iterator : public ParamIteratorInterface<T>
+ {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base,
+ typename ContainerType::const_iterator iterator)
+ : base_(base), iterator_(iterator) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ ++iterator_;
+ value_.reset();
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ // We need to use cached value referenced by iterator_ because *iterator_
+ // can return a temporary object (and of type other then T), so just
+ // having "return &*iterator_;" doesn't work.
+ // value_ is updated here and not in Advance() because Advance()
+ // can advance iterator_ beyond the end of the range, and we cannot
+ // detect that fact. The client code, on the other hand, is
+ // responsible for not calling Current() on an out-of-range iterator.
+ virtual const T* Current() const {
+ if (value_.get() == NULL)
+ value_.reset(new T(*iterator_));
+ return value_.get();
+ }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ return iterator_ ==
+ CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ // The explicit constructor call suppresses a false warning
+ // emitted by gcc when supplied with the -Wextra option.
+ : ParamIteratorInterface<T>(),
+ base_(other.base_),
+ iterator_(other.iterator_) {}
+
+ const ParamGeneratorInterface<T>* const base_;
+ typename ContainerType::const_iterator iterator_;
+ // A cached value of *iterator_. We keep it here to allow access by
+ // pointer in the wrapping iterator's operator->().
+ // value_ needs to be mutable to be accessed in Current().
+ // Use of scoped_ptr helps manage cached value's lifetime,
+ // which is bound by the lifespan of the iterator itself.
+ mutable scoped_ptr<const T> value_;
+ }; // class ValuesInIteratorRangeGenerator::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const ValuesInIteratorRangeGenerator& other);
+
+ const ContainerType container_;
+}; // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase
+{
+ public:
+ typedef typename TestClass::ParamType ParamType;
+ explicit ParameterizedTestFactory(ParamType parameter) :
+ parameter_(parameter) {}
+ virtual Test* CreateTest() {
+ TestClass::SetParam(¶meter_);
+ return new TestClass();
+ }
+
+ private:
+ const ParamType parameter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase
+{
+ public:
+ virtual ~TestMetaFactoryBase() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+ : public TestMetaFactoryBase<typename TestCase::ParamType>
+{
+ public:
+ typedef typename TestCase::ParamType ParamType;
+
+ TestMetaFactory() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+ return new ParameterizedTestFactory<TestCase>(parameter);
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase
+{
+ public:
+ virtual ~ParameterizedTestCaseInfoBase() {}
+
+ // Base part of test case name for display purposes.
+ virtual const string& GetTestCaseName() const = 0;
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const = 0;
+ // UnitTest class invokes this method to register tests in this
+ // test case right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ virtual void RegisterTests() = 0;
+
+ protected:
+ ParameterizedTestCaseInfoBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase
+{
+ public:
+ // ParamType and GeneratorCreationFunc are private types but are required
+ // for declarations of public methods AddTestPattern() and
+ // AddTestCaseInstantiation().
+ typedef typename TestCase::ParamType ParamType;
+ // A function that returns an instance of appropriate generator type.
+ typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+ explicit ParameterizedTestCaseInfo(const char* name)
+ : test_case_name_(name) {}
+
+ // Test case base name for display purposes.
+ virtual const string& GetTestCaseName() const { return test_case_name_; }
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+ // TEST_P macro uses AddTestPattern() to record information
+ // about a single test in a LocalTestInfo structure.
+ // test_case_name is the base name of the test case (without invocation
+ // prefix). test_base_name is the name of an individual test without
+ // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+ // test case base name and DoBar is test base name.
+ void AddTestPattern(const char* test_case_name,
+ const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* meta_factory) {
+ tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+ test_base_name,
+ meta_factory)));
+ }
+ // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+ // about a generator.
+ int AddTestCaseInstantiation(const string& instantiation_name,
+ GeneratorCreationFunc* func,
+ const char* /* file */,
+ int /* line */) {
+ instantiations_.push_back(::std::make_pair(instantiation_name, func));
+ return 0; // Return value used only to run this method in namespace scope.
+ }
+ // UnitTest class invokes this method to register tests in this test case
+ // test cases right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more then once.
+ virtual void RegisterTests() {
+ for (typename TestInfoContainer::iterator test_it = tests_.begin();
+ test_it != tests_.end(); ++test_it) {
+ linked_ptr<TestInfo> test_info = *test_it;
+ for (typename InstantiationContainer::iterator gen_it =
+ instantiations_.begin(); gen_it != instantiations_.end();
+ ++gen_it) {
+ const string& instantiation_name = gen_it->first;
+ ParamGenerator<ParamType> generator((*gen_it->second)());
+
+ string test_case_name;
+ if (!instantiation_name.empty())
+ test_case_name = instantiation_name + "/";
+ test_case_name += test_info->test_case_base_name;
+
+ int i = 0;
+ for (typename ParamGenerator<ParamType>::iterator param_it =
+ generator.begin();
+ param_it != generator.end(); ++param_it, ++i) {
+ Message test_name_stream;
+ test_name_stream << test_info->test_base_name << "/" << i;
+ MakeAndRegisterTestInfo(
+ test_case_name.c_str(),
+ test_name_stream.GetString().c_str(),
+ NULL, // No type parameter.
+ PrintToString(*param_it).c_str(),
+ GetTestCaseTypeId(),
+ TestCase::SetUpTestCase,
+ TestCase::TearDownTestCase,
+ test_info->test_meta_factory->CreateTestFactory(*param_it));
+ } // for param_it
+ } // for gen_it
+ } // for test_it
+ } // RegisterTests
+
+ private:
+ // LocalTestInfo structure keeps information about a single test registered
+ // with TEST_P macro.
+ struct TestInfo {
+ TestInfo(const char* a_test_case_base_name,
+ const char* a_test_base_name,
+ TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
+ test_case_base_name(a_test_case_base_name),
+ test_base_name(a_test_base_name),
+ test_meta_factory(a_test_meta_factory) {}
+
+ const string test_case_base_name;
+ const string test_base_name;
+ const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+ };
+ typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+ // Keeps pairs of <Instantiation name, Sequence generator creation function>
+ // received from INSTANTIATE_TEST_CASE_P macros.
+ typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
+ InstantiationContainer;
+
+ const string test_case_name_;
+ TestInfoContainer tests_;
+ InstantiationContainer instantiations_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+}; // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry
+{
+ public:
+ ParameterizedTestCaseRegistry() {}
+ ~ParameterizedTestCaseRegistry() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ // Looks up or creates and returns a structure containing information about
+ // tests and instantiations of a particular test case.
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name,
+ const char* file,
+ int line) {
+ ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ if ((*it)->GetTestCaseName() == test_case_name) {
+ if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+ // Complain about incorrect usage of Google Test facilities
+ // and terminate the program since we cannot guaranty correct
+ // test case setup and tear-down in this case.
+ ReportInvalidTestCaseType(test_case_name, file, line);
+ posix::Abort();
+ } else {
+ // At this point we are sure that the object we found is of the same
+ // type we are looking for, so we downcast it to that type
+ // without further checks.
+ typed_test_info = CheckedDowncastToActualType<
+ ParameterizedTestCaseInfo<TestCase> >(*it);
+ }
+ break;
+ }
+ }
+ if (typed_test_info == NULL) {
+ typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+ test_case_infos_.push_back(typed_test_info);
+ }
+ return typed_test_info;
+ }
+ void RegisterTests() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ (*it)->RegisterTests();
+ }
+ }
+
+ private:
+ typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+ TestCaseInfoContainer test_case_infos_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-port.h b/external/gtest-1.6.0/include/gtest/internal/gtest-port.h
new file mode 100644
index 0000000..51d94e4
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-port.h
@@ -0,0 +1,1995 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan at google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms. They are subject to change without notice. DO NOT USE
+// THEM IN USER CODE.
+//
+// This file is fundamental to Google Test. All other Google Test source
+// files are expected to #include this. Therefore, it cannot #include
+// any other Google Test header.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior. If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
+// is/isn't available.
+// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions
+// are enabled.
+// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::string, which is different to std::string).
+// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::wstring, which is different to std::wstring).
+// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular
+// expressions are/aren't available.
+// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
+// is/isn't available.
+// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
+// enabled.
+// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
+// std::wstring does/doesn't work (Google Test can
+// be used where std::wstring is unavailable).
+// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple
+// is/isn't available.
+// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
+// compiler supports Microsoft's "Structured
+// Exception Handling".
+// GTEST_HAS_STREAM_REDIRECTION
+// - Define it to 1/0 to indicate whether the
+// platform supports I/O stream redirection using
+// dup() and dup2().
+// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google
+// Test's own tr1 tuple implementation should be
+// used. Unused when the user sets
+// GTEST_HAS_TR1_TUPLE to 0.
+// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test
+// is building in C++11/C++98 mode.
+// GTEST_LINKED_AS_SHARED_LIBRARY
+// - Define to 1 when compiling tests that use
+// Google Test as a shared library (known as
+// DLL on Windows).
+// GTEST_CREATE_SHARED_LIBRARY
+// - Define to 1 when compiling Google Test itself
+// as a shared library.
+
+// This header defines the following utilities:
+//
+// Macros indicating the current platform (defined to 1 if compiled on
+// the given platform; otherwise undefined):
+// GTEST_OS_AIX - IBM AIX
+// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_HPUX - HP-UX
+// GTEST_OS_LINUX - Linux
+// GTEST_OS_LINUX_ANDROID - Google Android
+// GTEST_OS_MAC - Mac OS X
+// GTEST_OS_IOS - iOS
+// GTEST_OS_IOS_SIMULATOR - iOS simulator
+// GTEST_OS_NACL - Google Native Client (NaCl)
+// GTEST_OS_OPENBSD - OpenBSD
+// GTEST_OS_QNX - QNX
+// GTEST_OS_SOLARIS - Sun Solaris
+// GTEST_OS_SYMBIAN - Symbian
+// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
+// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
+// GTEST_OS_WINDOWS_MINGW - MinGW
+// GTEST_OS_WINDOWS_MOBILE - Windows Mobile
+// GTEST_OS_ZOS - z/OS
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support. Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable. If you notice any problems on your platform, please notify
+// googletestframework at googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_* macros are defined.
+//
+// Macros indicating available Google Test features (defined to 1 if
+// the corresponding feature is supported; otherwise undefined):
+// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized
+// tests)
+// GTEST_HAS_DEATH_TEST - death tests
+// GTEST_HAS_PARAM_TEST - value-parameterized tests
+// GTEST_HAS_TYPED_TEST - typed tests
+// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with
+// GTEST_HAS_POSIX_RE (see above) which users can
+// define themselves.
+// GTEST_USES_SIMPLE_RE - our own simple regex is used;
+// the above two are mutually exclusive.
+// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+//
+// Macros for basic C++ coding:
+// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a
+// variable don't have to be used.
+// GTEST_DISALLOW_ASSIGN_ - disables operator=.
+// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+// synchronization primitives have real implementations
+// and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
+// IteratorTraits - partial implementation of std::iterator_traits, which
+// is not available in libCstd when compiled with Sun C++.
+//
+// Smart pointers:
+// scoped_ptr - as in TR2.
+//
+// Regular expressions:
+// RE - a simple regular expression class using the POSIX
+// Extended Regular Expression syntax on UNIX-like
+// platforms, or a reduced regular exception syntax on
+// other platforms, including Windows.
+//
+// Logging:
+// GTEST_LOG_() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+//
+// Stdout and stderr capturing:
+// CaptureStdout() - starts capturing stdout.
+// GetCapturedStdout() - stops capturing stdout and returns the captured
+// string.
+// CaptureStderr() - starts capturing stderr.
+// GetCapturedStderr() - stops capturing stderr and returns the captured
+// string.
+//
+// Integer types:
+// TypeWithSize - maps an integer to a int type.
+// Int32, UInt32, Int64, UInt64, TimeInMillis
+// - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GTEST_FLAG() - references a flag.
+// GTEST_DECLARE_*() - declares a flag.
+// GTEST_DEFINE_*() - defines a flag.
+// GetInjectableArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+// GetEnv() - gets the value of an environment variable.
+// BoolFromGTestEnv() - parses a bool environment variable.
+// Int32FromGTestEnv() - parses an Int32 environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+
+#include <ctype.h> // for isspace, etc
+#include <stddef.h> // for ptrdiff_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif // !_WIN32_WCE
+
+#if defined __APPLE__
+# include <AvailabilityMacros.h>
+# include <TargetConditionals.h>
+#endif
+
+#include <iostream> // NOLINT
+#include <sstream> // NOLINT
+#include <string> // NOLINT
+
+#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+#define GTEST_FLAG_PREFIX_ "gtest_"
+#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+#define GTEST_NAME_ "Google Test"
+#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+# define GTEST_GCC_VER_ \
+ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+# define GTEST_OS_CYGWIN 1
+#elif defined __SYMBIAN32__
+# define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+# define GTEST_OS_WINDOWS 1
+# ifdef _WIN32_WCE
+# define GTEST_OS_WINDOWS_MOBILE 1
+# elif defined(__MINGW__) || defined(__MINGW32__)
+# define GTEST_OS_WINDOWS_MINGW 1
+# else
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# endif // _WIN32_WCE
+#elif defined __APPLE__
+# define GTEST_OS_MAC 1
+# if TARGET_OS_IPHONE
+# define GTEST_OS_IOS 1
+# if TARGET_IPHONE_SIMULATOR
+# define GTEST_OS_IOS_SIMULATOR 1
+# endif
+# endif
+#elif defined __linux__
+# define GTEST_OS_LINUX 1
+# if defined __ANDROID__
+# define GTEST_OS_LINUX_ANDROID 1
+# endif
+#elif defined __MVS__
+# define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+# define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+# define GTEST_OS_AIX 1
+#elif defined(__hpux)
+# define GTEST_OS_HPUX 1
+#elif defined __native_client__
+# define GTEST_OS_NACL 1
+#elif defined __OpenBSD__
+# define GTEST_OS_OPENBSD 1
+#elif defined __QNX__
+# define GTEST_OS_QNX 1
+#endif // __CYGWIN__
+
+#ifndef GTEST_LANG_CXX11
+// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
+// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a
+// value for __cplusplus, and recent versions of clang, gcc, and
+// probably other compilers set that too in C++11 mode.
+# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
+// Compiling in at least C++11 mode.
+# define GTEST_LANG_CXX11 1
+# else
+# define GTEST_LANG_CXX11 0
+# endif
+#endif
+
+// Brings in definitions for functions used in the testing::internal::posix
+// namespace (read, write, close, chdir, isatty, stat). We do not currently
+// use them on Windows Mobile.
+#if !GTEST_OS_WINDOWS
+// This assumes that non-Windows OSes provide unistd.h. For OSes where this
+// is not the case, we need to include headers that provide the functions
+// mentioned above.
+# include <unistd.h>
+# include <strings.h>
+#elif !GTEST_OS_WINDOWS_MOBILE
+# include <direct.h>
+# include <io.h>
+#endif
+
+#if GTEST_OS_LINUX_ANDROID
+// Used to define __ANDROID_API__ matching the target NDK API level.
+# include <android/api-level.h> // NOLINT
+#endif
+
+// Defines this to true iff Google Test can use POSIX regular expressions.
+#ifndef GTEST_HAS_POSIX_RE
+# if GTEST_OS_LINUX_ANDROID
+// On Android, <regex.h> is only available starting with Gingerbread.
+# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
+# else
+# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
+# endif
+#endif
+
+#if GTEST_HAS_POSIX_RE
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise. We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+# include <regex.h> // NOLINT
+
+# define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+// <regex.h> is not available on Windows. Use our own simple regex
+// implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform. Use our own
+// simple regex implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#endif // GTEST_HAS_POSIX_RE
+
+#ifndef GTEST_HAS_EXCEPTIONS
+// The user didn't tell us whether exceptions are enabled, so we need
+// to figure it out.
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+# ifndef _HAS_EXCEPTIONS
+# define _HAS_EXCEPTIONS 1
+# endif // _HAS_EXCEPTIONS
+# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__SUNPRO_CC)
+// Sun Pro CC supports exceptions. However, there is no compile-time way of
+// detecting whether they are enabled or not. Therefore, we assume that
+// they are enabled unless the user tells us otherwise.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__IBMCPP__) && __EXCEPTIONS
+// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__HP_aCC)
+// Exception handling is in effect by default in HP aCC compiler. It has to
+// be turned of by +noeh compiler option if desired.
+# define GTEST_HAS_EXCEPTIONS 1
+# else
+// For other compilers, we assume exceptions are disabled to be
+// conservative.
+# define GTEST_HAS_EXCEPTIONS 0
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+#endif // GTEST_HAS_EXCEPTIONS
+
+#if !defined(GTEST_HAS_STD_STRING)
+// Even though we don't use this macro any longer, we keep it in case
+// some clients still depend on it.
+# define GTEST_HAS_STD_STRING 1
+#elif !GTEST_HAS_STD_STRING
+// The user told us that ::std::string isn't available.
+# error "Google Test cannot be used where ::std::string isn't available."
+#endif // !defined(GTEST_HAS_STD_STRING)
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+# define GTEST_HAS_GLOBAL_STRING 0
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan at google.com): uses autoconf to detect whether ::std::wstring
+// is available.
+
+// Cygwin 1.7 and below doesn't support ::std::wstring.
+// Solaris' libc++ doesn't support it either. Android has
+// no support for it at least as recent as Froyo (2.2).
+# define GTEST_HAS_STD_WSTRING \
+ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+
+#endif // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+# define GTEST_HAS_GLOBAL_WSTRING \
+ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+# ifdef _MSC_VER
+
+# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
+
+# ifdef __GXX_RTTI
+// When building against STLport with the Android NDK and with
+// -frtti -fno-exceptions, the build fails at link time with undefined
+// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
+// so disable RTTI when detected.
+# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
+ !defined(__EXCEPTIONS)
+# define GTEST_HAS_RTTI 0
+# else
+# define GTEST_HAS_RTTI 1
+# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
+# else
+# define GTEST_HAS_RTTI 0
+# endif // __GXX_RTTI
+
+// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
+// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
+// first version with C++ support.
+# elif defined(__clang__)
+
+# define GTEST_HAS_RTTI __has_feature(cxx_rtti)
+
+// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
+// both the typeid and dynamic_cast features are present.
+# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
+
+# ifdef __RTTI_ALL__
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif
+
+# else
+
+// For all other compilers, we assume RTTI is enabled.
+# define GTEST_HAS_RTTI 1
+
+# endif // _MSC_VER
+
+#endif // GTEST_HAS_RTTI
+
+// It's this header's responsibility to #include <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+# include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we assume pthreads support is
+// available on Linux and Mac.
+//
+// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
+// to your compiler flags.
+# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
+ || GTEST_OS_QNX)
+#endif // GTEST_HAS_PTHREAD
+
+#if GTEST_HAS_PTHREAD
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+# include <pthread.h> // NOLINT
+
+// For timespec and nanosleep, used below.
+# include <time.h> // NOLINT
+#endif
+
+// Determines whether Google Test can use tr1/tuple. You can define
+// this macro to 0 to prevent Google Test from using tuple (any
+// feature depending on tuple with be disabled in this mode).
+#ifndef GTEST_HAS_TR1_TUPLE
+# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR)
+// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>.
+# define GTEST_HAS_TR1_TUPLE 0
+# else
+// The user didn't tell us not to do it, so we assume it's OK.
+# define GTEST_HAS_TR1_TUPLE 1
+# endif
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether Google Test's own tr1 tuple implementation
+// should be used.
+#ifndef GTEST_USE_OWN_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// We use our own TR1 tuple if we aren't sure the user has an
+// implementation of it already. At this time, libstdc++ 4.0.0+ and
+// MSVC 2010 are the only mainstream standard libraries that come
+// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler
+// pretends to be GCC by defining __GNUC__ and friends, but cannot
+// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1
+// tuple in a 323 MB Feature Pack download, which we cannot assume the
+// user has. QNX's QCC compiler is a modified GCC but it doesn't
+// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode,
+// and it can be used with some compilers that define __GNUC__.
+# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \
+ && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600
+# define GTEST_ENV_HAS_TR1_TUPLE_ 1
+# endif
+
+// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used
+// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6
+// can build with clang but need to use gcc4.2's libstdc++).
+# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
+# define GTEST_ENV_HAS_STD_TUPLE_ 1
+# endif
+
+# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
+# define GTEST_USE_OWN_TR1_TUPLE 0
+# else
+# define GTEST_USE_OWN_TR1_TUPLE 1
+# endif
+
+#endif // GTEST_USE_OWN_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+
+# if GTEST_USE_OWN_TR1_TUPLE
+# include "gtest/internal/gtest-tuple.h"
+# elif GTEST_ENV_HAS_STD_TUPLE_
+# include <tuple>
+// C++11 puts its tuple into the ::std namespace rather than
+// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there.
+// This causes undefined behavior, but supported compilers react in
+// the way we intend.
+namespace std
+{
+namespace tr1
+{
+using ::std::get;
+using ::std::make_tuple;
+using ::std::tuple;
+using ::std::tuple_element;
+using ::std::tuple_size;
+}
+}
+
+# elif GTEST_OS_SYMBIAN
+
+// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
+// use STLport's tuple implementation, which unfortunately doesn't
+// work as the copy of STLport distributed with Symbian is incomplete.
+// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
+// use its own tuple implementation.
+# ifdef BOOST_HAS_TR1_TUPLE
+# undef BOOST_HAS_TR1_TUPLE
+# endif // BOOST_HAS_TR1_TUPLE
+
+// This prevents <boost/tr1/detail/config.hpp>, which defines
+// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
+# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
+# include <tuple>
+
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does
+// not conform to the TR1 spec, which requires the header to be <tuple>.
+
+# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
+// which is #included by <tr1/tuple>, to not compile when RTTI is
+// disabled. _TR1_FUNCTIONAL is the header guard for
+// <tr1/functional>. Hence the following #define is a hack to prevent
+// <tr1/functional> from being included.
+# define _TR1_FUNCTIONAL 1
+# include <tr1/tuple>
+# undef _TR1_FUNCTIONAL // Allows the user to #include
+// <tr1/functional> if he chooses to.
+# else
+# include <tr1/tuple> // NOLINT
+# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+
+# else
+// If the compiler is not GCC 4.0+, we assume the user is using a
+// spec-conforming TR1 implementation.
+# include <tuple> // NOLINT
+# endif // GTEST_USE_OWN_TR1_TUPLE
+
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+# if GTEST_OS_LINUX && !defined(__ia64__)
+# if GTEST_OS_LINUX_ANDROID
+// On Android, clone() is only available on ARM starting with Gingerbread.
+# if defined(__arm__) && __ANDROID_API__ >= 9
+# define GTEST_HAS_CLONE 1
+# else
+# define GTEST_HAS_CLONE 0
+# endif
+# else
+# define GTEST_HAS_CLONE 1
+# endif
+# else
+# define GTEST_HAS_CLONE 0
+# endif // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif // GTEST_HAS_CLONE
+
+// Determines whether to support stream redirection. This is used to test
+// output correctness and to implement death tests.
+#ifndef GTEST_HAS_STREAM_REDIRECTION
+// By default, we assume that stream redirection is supported on all
+// platforms except known mobile ones.
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
+# define GTEST_HAS_STREAM_REDIRECTION 0
+# else
+# define GTEST_HAS_STREAM_REDIRECTION 1
+# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+// Determines whether to support death tests.
+// Google Test does not support death tests for VC 7.1 and earlier as
+// abort() in a VC 7.1 application compiled as GUI in debug config
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
+ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
+ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
+ GTEST_OS_OPENBSD || GTEST_OS_QNX)
+# define GTEST_HAS_DEATH_TEST 1
+# include <vector> // NOLINT
+#endif
+
+// We don't support MSVC 7.1 with exceptions disabled now. Therefore
+// all the compilers we care about are adequate for supporting
+// value-parameterized tests.
+#define GTEST_HAS_PARAM_TEST 1
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, IBM Visual Age, and HP aCC support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
+ defined(__IBMCPP__) || defined(__HP_aCC)
+# define GTEST_HAS_TYPED_TEST 1
+# define GTEST_HAS_TYPED_TEST_P 1
+#endif
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled. The implementation doesn't
+// work on Sun Studio since it doesn't understand templated conversion
+// operators.
+#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
+# define GTEST_HAS_COMBINE 1
+#endif
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
+
+// Determines whether test results can be streamed to a socket.
+#if GTEST_OS_LINUX
+# define GTEST_CAN_STREAM_RESULTS_ 1
+#endif
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding. This leads to problems with code like:
+//
+// if (gate)
+// ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used. This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor. Example:
+//
+// struct Foo {
+// Foo() { ... }
+// } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+# define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_ASSIGN_(type)\
+ void operator=(type const &)
+
+// A macro to disallow copy constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+ type(type const &);\
+ GTEST_DISALLOW_ASSIGN_(type)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro. The macro should be used on function declarations
+// following the argument list:
+//
+// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+# define GTEST_MUST_USE_RESULT_
+#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling. This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+# define GTEST_HAS_SEH 1
+# else
+// Assume no SEH.
+# define GTEST_HAS_SEH 0
+# endif
+
+#endif // GTEST_HAS_SEH
+
+#ifdef _MSC_VER
+
+# if GTEST_LINKED_AS_SHARED_LIBRARY
+# define GTEST_API_ __declspec(dllimport)
+# elif GTEST_CREATE_SHARED_LIBRARY
+# define GTEST_API_ __declspec(dllexport)
+# endif
+
+#endif // _MSC_VER
+
+#ifndef GTEST_API_
+# define GTEST_API_
+#endif
+
+#ifdef __GNUC__
+// Ask the compiler to never inline a given function.
+# define GTEST_NO_INLINE_ __attribute__((noinline))
+#else
+# define GTEST_NO_INLINE_
+#endif
+
+// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
+#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
+# define GTEST_HAS_CXXABI_H_ 1
+#else
+# define GTEST_HAS_CXXABI_H_ 0
+#endif
+
+namespace testing
+{
+
+class Message;
+
+namespace internal
+{
+
+// A secret type that Google Test users don't know about. It has no
+// definition on purpose. Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define GTEST_COMPILE_ASSERT_(expr, msg) \
+ typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
+ msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
+
+// Implementation details of GTEST_COMPILE_ASSERT_:
+//
+// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// GTEST_COMPILE_ASSERT_(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
+//
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+#if GTEST_HAS_GLOBAL_STRING
+typedef ::string string;
+#else
+typedef ::std::string string;
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+typedef ::wstring wstring;
+#elif GTEST_HAS_STD_WSTRING
+typedef ::std::wstring wstring;
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// A helper for suppressing warnings on constant condition. It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr
+{
+ public:
+ typedef T element_type;
+
+ explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+ ~scoped_ptr() { reset(); }
+
+ T& operator*() const { return *ptr_; }
+ T* operator->() const { return ptr_; }
+ T* get() const { return ptr_; }
+
+ T* release() {
+ T* const ptr = ptr_;
+ ptr_ = NULL;
+ return ptr;
+ }
+
+ void reset(T* p = NULL) {
+ if (p != ptr_) {
+ if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type.
+ delete ptr_;
+ }
+ ptr_ = p;
+ }
+ }
+
+ private:
+ T* ptr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>. It uses the POSIX Extended
+// Regular Expression syntax.
+class GTEST_API_ RE
+{
+ public:
+ // A copy constructor is required by the Standard to initialize object
+ // references from r-values.
+ RE(const RE& other) { Init(other.pattern()); }
+
+ // Constructs an RE from a string.
+ RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
+
+#if GTEST_HAS_GLOBAL_STRING
+
+ RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ RE(const char* regex) { Init(regex); } // NOLINT
+ ~RE();
+
+ // Returns the string representation of the regex.
+ const char* pattern() const { return pattern_; }
+
+ // FullMatch(str, re) returns true iff regular expression re matches
+ // the entire str.
+ // PartialMatch(str, re) returns true iff regular expression re
+ // matches a substring of str (including str itself).
+ //
+ // TODO(wan at google.com): make FullMatch() and PartialMatch() work
+ // when str contains NUL characters.
+ static bool FullMatch(const ::std::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::std::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+
+#if GTEST_HAS_GLOBAL_STRING
+
+ static bool FullMatch(const ::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ static bool FullMatch(const char* str, const RE& re);
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+
+ // We use a const char* instead of an std::string, as Google Test used to be
+ // used where std::string is not available. TODO(wan at google.com): change to
+ // std::string.
+ const char* pattern_;
+ bool is_valid_;
+
+#if GTEST_USES_POSIX_RE
+
+ regex_t full_regex_; // For FullMatch().
+ regex_t partial_regex_; // For PartialMatch().
+
+#else // GTEST_USES_SIMPLE_RE
+
+ const char* full_pattern_; // For FullMatch();
+
+#endif
+
+ GTEST_DISALLOW_ASSIGN_(RE);
+};
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line);
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file,
+ int line);
+
+// Defines logging utilities:
+// GTEST_LOG_(severity) - logs messages at the specified severity level. The
+// message itself is streamed into the macro.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+ GTEST_INFO,
+ GTEST_WARNING,
+ GTEST_ERROR,
+ GTEST_FATAL
+};
+
+// Formats log entry severity, provides a stream object for streaming the
+// log message, and terminates the message with a newline when going out of
+// scope.
+class GTEST_API_ GTestLog
+{
+ public:
+ GTestLog(GTestLogSeverity severity, const char* file, int line);
+
+ // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+ ~GTestLog();
+
+ ::std::ostream& GetStream() { return ::std::cerr; }
+
+ private:
+ const GTestLogSeverity severity_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
+};
+
+#define GTEST_LOG_(severity) \
+ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+ __FILE__, __LINE__).GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+// Synopsys:
+// GTEST_CHECK_(boolean_condition);
+// or
+// GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+// This checks the condition and if the condition is not satisfied
+// it prints message about the condition violation, including the
+// condition itself, plus additional message streamed into it, if any,
+// and then it aborts the program. It aborts the program irrespective of
+// whether it is built in the debug mode or not.
+#define GTEST_CHECK_(condition) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::IsTrue(condition)) \
+ ; \
+ else \
+ GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+
+// An all-mode assert to verify that the given POSIX-style function
+// call returns 0 (indicating success). Known limitation: this
+// doesn't expand to a balanced 'if' statement, so enclose the macro
+// in {} if you need to use it as the only statement in an 'if'
+// branch.
+#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
+ if (const int gtest_error = (posix_call)) \
+ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
+ << gtest_error
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Use ImplicitCast_ as a safe version of static_cast for upcasting in
+// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
+// const Foo*). When you use ImplicitCast_, the compiler checks that
+// the cast is safe. Such explicit ImplicitCast_s are necessary in
+// surprisingly many situations where C++ demands an exact type match
+// instead of an argument type convertable to a target type.
+//
+// The syntax for using ImplicitCast_ is the same as for static_cast:
+//
+// ImplicitCast_<ToType>(expr)
+//
+// ImplicitCast_ would have been part of the C++ standard library,
+// but the proposal was submitted too late. It will probably make
+// its way into the language in the future.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., implicit_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To>
+inline To ImplicitCast_(To x) { return x; }
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
+// always succeed. When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo? It
+// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
+// when you downcast, you should use this macro. In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not). In normal mode, we do the efficient static_cast<>
+// instead. Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+// This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., down_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To, typename From> // use like this: DownCast_<T*>(foo);
+inline To DownCast_(From* f) // so we only accept pointers
+{
+ // Ensures that To is a sub-type of From *. This test is here only
+ // for compile-time type checking, and has no overhead in an
+ // optimized build at run-time, as it will be optimized away
+ // completely.
+ if (false) {
+ const To to = NULL;
+ ::testing::internal::ImplicitCast_<From*>(to);
+ }
+
+#if GTEST_HAS_RTTI
+ // RTTI: debug mode only!
+ GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+ return static_cast<To>(f);
+}
+
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base)
+{
+#if GTEST_HAS_RTTI
+ GTEST_CHECK_(typeid(*base) == typeid(Derived));
+ return dynamic_cast<Derived*>(base); // NOLINT
+#else
+ return static_cast<Derived*>(base); // Poor man's downcast.
+#endif
+}
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Defines the stderr capturer:
+// CaptureStdout - starts capturing stdout.
+// GetCapturedStdout - stops capturing stdout and returns the captured string.
+// CaptureStderr - starts capturing stderr.
+// GetCapturedStderr - stops capturing stderr and returns the captured string.
+//
+GTEST_API_ void CaptureStdout();
+GTEST_API_ std::string GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ std::string GetCapturedStderr();
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+
+#if GTEST_HAS_DEATH_TEST
+
+const ::std::vector<testing::internal::string>& GetInjectableArgvs();
+void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
+ new_argvs);
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+extern ::std::vector<testing::internal::string> g_argvs;
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+#if GTEST_HAS_PTHREAD
+
+// Sleeps for (roughly) n milli-seconds. This function is only for
+// testing Google Test's own constructs. Don't use it in user tests,
+// either directly or indirectly.
+inline void SleepMilliseconds(int n)
+{
+ const timespec time = {
+ 0, // 0 seconds.
+ n * 1000L * 1000L, // And n ms.
+ };
+ nanosleep(&time, NULL);
+}
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified. Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class Notification
+{
+ public:
+ Notification() : notified_(false) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+ }
+ ~Notification() {
+ pthread_mutex_destroy(&mutex_);
+ }
+
+ // Notifies all threads created with this notification to start. Must
+ // be called from the controller thread.
+ void Notify() {
+ pthread_mutex_lock(&mutex_);
+ notified_ = true;
+ pthread_mutex_unlock(&mutex_);
+ }
+
+ // Blocks until the controller thread notifies. Must be called from a test
+ // thread.
+ void WaitForNotification() {
+ for (;;) {
+ pthread_mutex_lock(&mutex_);
+ const bool notified = notified_;
+ pthread_mutex_unlock(&mutex_);
+ if (notified)
+ break;
+ SleepMilliseconds(10);
+ }
+ }
+
+ private:
+ pthread_mutex_t mutex_;
+ bool notified_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+
+// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
+// Consequently, it cannot select a correct instantiation of ThreadWithParam
+// in order to call its Run(). Introducing ThreadWithParamBase as a
+// non-templated base class for ThreadWithParam allows us to bypass this
+// problem.
+class ThreadWithParamBase
+{
+ public:
+ virtual ~ThreadWithParamBase() {}
+ virtual void Run() = 0;
+};
+
+// pthread_create() accepts a pointer to a function type with the C linkage.
+// According to the Standard (7.5/1), function types with different linkages
+// are different even if they are otherwise identical. Some compilers (for
+// example, SunStudio) treat them as different types. Since class methods
+// cannot be defined with C-linkage we need to define a free C-function to
+// pass into pthread_create().
+extern "C" inline void* ThreadFuncWithCLinkage(void* thread)
+{
+ static_cast<ThreadWithParamBase*>(thread)->Run();
+ return NULL;
+}
+
+// Helper class for testing Google Test's multi-threading constructs.
+// To use it, write:
+//
+// void ThreadFunc(int param) { /* Do things with param */ }
+// Notification thread_can_start;
+// ...
+// // The thread_can_start parameter is optional; you can supply NULL.
+// ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
+// thread_can_start.Notify();
+//
+// These classes are only for testing Google Test's own constructs. Do
+// not use them in user tests, either directly or indirectly.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase
+{
+ public:
+ typedef void (*UserThreadFunc)(T);
+
+ ThreadWithParam(
+ UserThreadFunc func, T param, Notification* thread_can_start)
+ : func_(func),
+ param_(param),
+ thread_can_start_(thread_can_start),
+ finished_(false) {
+ ThreadWithParamBase* const base = this;
+ // The thread can be created only after all fields except thread_
+ // have been initialized.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+ }
+ ~ThreadWithParam() { Join(); }
+
+ void Join() {
+ if (!finished_) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+ finished_ = true;
+ }
+ }
+
+ virtual void Run() {
+ if (thread_can_start_ != NULL)
+ thread_can_start_->WaitForNotification();
+ func_(param_);
+ }
+
+ private:
+ const UserThreadFunc func_; // User-supplied thread function.
+ const T param_; // User-supplied parameter to the thread function.
+ // When non-NULL, used to block execution until the controller thread
+ // notifies.
+ Notification* const thread_can_start_;
+ bool finished_; // true iff we know that the thread function has finished.
+ pthread_t thread_; // The native thread object.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms. They
+// are used in conjunction with class MutexLock:
+//
+// Mutex mutex;
+// ...
+// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end
+// // of the current scope.
+//
+// MutexBase implements behavior for both statically and dynamically
+// allocated mutexes. Do not use MutexBase directly. Instead, write
+// the following to define a static mutex:
+//
+// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+//
+// You can forward declare a static mutex like this:
+//
+// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// To create a dynamic mutex, just define an object of type Mutex.
+class MutexBase
+{
+ public:
+ // Acquires this mutex.
+ void Lock() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+ owner_ = pthread_self();
+ has_owner_ = true;
+ }
+
+ // Releases this mutex.
+ void Unlock() {
+ // Since the lock is being released the owner_ field should no longer be
+ // considered valid. We don't protect writing to has_owner_ here, as it's
+ // the caller's responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ has_owner_ = false;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
+ }
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld() const {
+ GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
+ << "The current thread is not holding the mutex @" << this;
+ }
+
+ // A static mutex may be used before main() is entered. It may even
+ // be used before the dynamic initialization stage. Therefore we
+ // must be able to initialize a static mutex object at link time.
+ // This means MutexBase has to be a POD and its member variables
+ // have to be public.
+ public:
+ pthread_mutex_t mutex_; // The underlying pthread mutex.
+ // has_owner_ indicates whether the owner_ field below contains a valid thread
+ // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
+ // accesses to the owner_ field should be protected by a check of this field.
+ // An alternative might be to memset() owner_ to all zeros, but there's no
+ // guarantee that a zero'd pthread_t is necessarily invalid or even different
+ // from pthread_self().
+ bool has_owner_;
+ pthread_t owner_; // The thread holding the mutex.
+};
+
+// Forward-declares a static mutex.
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::MutexBase mutex
+
+// Defines and statically (i.e. at link time) initializes a static mutex.
+// The initialization list here does not explicitly initialize each field,
+// instead relying on default initialization for the unspecified fields. In
+// particular, the owner_ field (a pthread_t) is not explicitly initialized.
+// This allows initialization to work whether pthread_t is a scalar or struct.
+// The flag -Wmissing-field-initializers must not be specified for this to work.
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
+
+// The Mutex class can only be used for mutexes created at runtime. It
+// shares its API with MutexBase otherwise.
+class Mutex : public MutexBase
+{
+ public:
+ Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+ has_owner_ = false;
+ }
+ ~Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+// We cannot name this class MutexLock as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. Hence the typedef trick below.
+class GTestMutexLock
+{
+ public:
+ explicit GTestMutexLock(MutexBase* mutex)
+ : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ MutexBase* const mutex_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage. Therefore it cannot be templatized to access
+// ThreadLocal<T>. Hence the need for class
+// ThreadLocalValueHolderBase.
+class ThreadLocalValueHolderBase
+{
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Called by pthread to delete thread-local data stored by
+// pthread_setspecific().
+extern "C" inline void DeleteThreadLocalValue(void* value_holder)
+{
+ delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+//
+// // Thread 1
+// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
+//
+// // Thread 2
+// tl.set(150); // Changes the value for thread 2 only.
+// EXPECT_EQ(150, tl.get());
+//
+// // Thread 1
+// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
+// tl.set(200);
+// EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// An object managed for a thread by a ThreadLocal instance is deleted
+// when the thread exits. Or, if the ThreadLocal instance dies in
+// that thread, when the ThreadLocal dies. It's the user's
+// responsibility to ensure that all other threads using a ThreadLocal
+// have exited when it dies, or the per-thread objects for those
+// threads will not be deleted.
+//
+// Google Test only uses global ThreadLocal objects. That means they
+// will die after main() has returned. Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal
+{
+ public:
+ ThreadLocal() : key_(CreateKey()),
+ default_() {}
+ explicit ThreadLocal(const T& value) : key_(CreateKey()),
+ default_(value) {}
+
+ ~ThreadLocal() {
+ // Destroys the managed object for the current thread, if any.
+ DeleteThreadLocalValue(pthread_getspecific(key_));
+
+ // Releases resources associated with the key. This will *not*
+ // delete managed objects for other threads.
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
+ }
+
+ T* pointer() { return GetOrCreateValue(); }
+ const T* pointer() const { return GetOrCreateValue(); }
+ const T& get() const { return *pointer(); }
+ void set(const T& value) { *pointer() = value; }
+
+ private:
+ // Holds a value of type T.
+ class ValueHolder : public ThreadLocalValueHolderBase
+ {
+ public:
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+ };
+
+ static pthread_key_t CreateKey() {
+ pthread_key_t key;
+ // When a thread exits, DeleteThreadLocalValue() will be called on
+ // the object managed for that thread.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_key_create(&key, &DeleteThreadLocalValue));
+ return key;
+ }
+
+ T* GetOrCreateValue() const {
+ ThreadLocalValueHolderBase* const holder =
+ static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+ if (holder != NULL) {
+ return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+ }
+
+ ValueHolder* const new_holder = new ValueHolder(default_);
+ ThreadLocalValueHolderBase* const holder_base = new_holder;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+ return new_holder->pointer();
+ }
+
+ // A key pthreads uses for looking up per-thread values.
+ const pthread_key_t key_;
+ const T default_; // The default value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# define GTEST_IS_THREADSAFE 1
+
+#else // GTEST_HAS_PTHREAD
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable). Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex
+{
+ public:
+ Mutex() {}
+ void Lock() {}
+ void Unlock() {}
+ void AssertHeld() const {}
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+class GTestMutexLock
+{
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal
+{
+ public:
+ ThreadLocal() : value_() {}
+ explicit ThreadLocal(const T& value) : value_(value) {}
+ T* pointer() { return &value_; }
+ const T* pointer() const { return &value_; }
+ const T& get() const { return value_; }
+ void set(const T& value) { value_ = value; }
+ private:
+ T value_;
+};
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+# define GTEST_IS_THREADSAFE 0
+
+#endif // GTEST_HAS_PTHREAD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler and generates a warning in Sun Studio. The Nokia Symbian
+// and the IBM XL C/C++ compiler try to instantiate a copy constructor
+// for objects passed through ellipsis (...), failing for uncopyable
+// objects. We define this to ensure that only POD is passed through
+// ellipsis on these systems.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_ELLIPSIS_NEEDS_POD_ 1
+#else
+# define GTEST_CAN_COMPARE_NULL 1
+#endif
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template. These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+# define GTEST_NEEDS_IS_POINTER_ 1
+#endif
+
+template <bool bool_value>
+struct bool_constant {
+ typedef bool_constant<bool_value> type;
+ static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+template <typename Iterator>
+struct IteratorTraits {
+ typedef typename Iterator::value_type value_type;
+};
+
+template <typename T>
+struct IteratorTraits<T*> {
+ typedef T value_type;
+};
+
+template <typename T>
+struct IteratorTraits<const T*> {
+ typedef T value_type;
+};
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_SEP_ "\\"
+# define GTEST_HAS_ALT_PATH_SEP_ 1
+// The biggest signed integer type the compiler supports.
+typedef __int64 BiggestInt;
+#else
+# define GTEST_PATH_SEP_ "/"
+# define GTEST_HAS_ALT_PATH_SEP_ 0
+typedef long long BiggestInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+// Utilities for char.
+
+// isspace(int ch) and friends accept an unsigned char or EOF. char
+// may be signed, depending on the compiler (or compiler flags).
+// Therefore we need to cast a char to unsigned char before calling
+// isspace(), etc.
+
+inline bool IsAlpha(char ch)
+{
+ return isalpha(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsAlNum(char ch)
+{
+ return isalnum(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsDigit(char ch)
+{
+ return isdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsLower(char ch)
+{
+ return islower(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsSpace(char ch)
+{
+ return isspace(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsUpper(char ch)
+{
+ return isupper(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(char ch)
+{
+ return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(wchar_t ch)
+{
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+
+inline char ToLower(char ch)
+{
+ return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
+}
+inline char ToUpper(char ch)
+{
+ return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
+}
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions. These wrappers hide the differences between
+// Windows/MSVC and POSIX systems. Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix
+{
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+# ifdef __BORLANDC__
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2)
+{
+ return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+# else // !__BORLANDC__
+# if GTEST_OS_WINDOWS_MOBILE
+inline int IsATTY(int /* fd */) { return 0; }
+# else
+inline int IsATTY(int fd) { return _isatty(fd); }
+# endif // GTEST_OS_WINDOWS_MOBILE
+inline int StrCaseCmp(const char* s1, const char* s2)
+{
+ return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+# endif // __BORLANDC__
+
+# if GTEST_OS_WINDOWS_MOBILE
+inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
+// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
+// time and thus not defined there.
+# else
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st)
+{
+ return (_S_IFDIR & st.st_mode) != 0;
+}
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2)
+{
+ return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif // GTEST_OS_WINDOWS
+
+// Functions deprecated by MSVC 8.0.
+
+#ifdef _MSC_VER
+// Temporarily disable warning 4996 (deprecated function).
+# pragma warning(push)
+# pragma warning(disable:4996)
+#endif
+
+inline const char* StrNCpy(char* dest, const char* src, size_t n)
+{
+ return strncpy(dest, src, n);
+}
+
+// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
+// StrError() aren't needed on Windows CE at this time and thus not
+// defined there.
+
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode)
+{
+ return fopen(path, mode);
+}
+#if !GTEST_OS_WINDOWS_MOBILE
+inline FILE* FReopen(const char* path, const char* mode, FILE* stream)
+{
+ return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+#endif
+inline int FClose(FILE* fp) { return fclose(fp); }
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int Read(int fd, void* buf, unsigned int count)
+{
+ return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count)
+{
+ return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+#endif
+inline const char* GetEnv(const char* name)
+{
+#if GTEST_OS_WINDOWS_MOBILE
+ // We are on Windows CE, which has no environment variables.
+ return NULL;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+ // Environment variables which we programmatically clear will be set to the
+ // empty string rather than unset (NULL). Handle that case.
+ const char* const env = getenv(name);
+ return (env != NULL && env[0] != '\0') ? env : NULL;
+#else
+ return getenv(name);
+#endif
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop) // Restores the warning state.
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void Abort();
+#else
+inline void Abort() { abort(); }
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+} // namespace posix
+
+// MSVC "deprecates" snprintf and issues warnings wherever it is used. In
+// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
+// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate
+// function in order to achieve that. We use macro definition here because
+// snprintf is a variadic function.
+#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+// MSVC 2005 and above support variadic macros.
+# define GTEST_SNPRINTF_(buffer, size, format, ...) \
+ _snprintf_s(buffer, size, size, format, __VA_ARGS__)
+#elif defined(_MSC_VER)
+// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't
+// complain about _snprintf.
+# define GTEST_SNPRINTF_ _snprintf
+#else
+# define GTEST_SNPRINTF_ snprintf
+#endif
+
+// The maximum number a BiggestInt can represent. This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+ ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type. It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+// TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs. Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize
+{
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4>
+{
+ public:
+ // unsigned int has size 4 in both gcc and MSVC.
+ //
+ // As base/basictypes.h doesn't compile on Windows, we cannot use
+ // uint32, uint64, and etc here.
+ typedef int Int;
+ typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8>
+{
+ public:
+#if GTEST_OS_WINDOWS
+ typedef __int64 Int;
+ typedef unsigned __int64 UInt;
+#else
+ typedef long long Int; // NOLINT
+ typedef unsigned long long UInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+ GTEST_API_ extern ::std::string GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+ GTEST_API_ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
+
+// Thread annotations
+#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+#define GTEST_LOCK_EXCLUDED_(locks)
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-string.h b/external/gtest-1.6.0/include/gtest/internal/gtest-string.h
new file mode 100644
index 0000000..2a23553
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-string.h
@@ -0,0 +1,170 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan at google.com (Zhanyong Wan), eefacm at gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test. They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by <gtest/internal/gtest-internal.h>.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+# include <mem.h>
+#endif
+
+#include <string.h>
+#include <string>
+
+#include "gtest/internal/gtest-port.h"
+
+namespace testing
+{
+namespace internal
+{
+
+// String - an abstract class holding static string utilities.
+class GTEST_API_ String
+{
+ public:
+ // Static utility methods
+
+ // Clones a 0-terminated C string, allocating memory using new. The
+ // caller is responsible for deleting the return value using
+ // delete[]. Returns the cloned string, or NULL if the input is
+ // NULL.
+ //
+ // This is different from strdup() in string.h, which allocates
+ // memory using malloc().
+ static const char* CloneCString(const char* c_str);
+
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+ // able to pass strings to Win32 APIs on CE we need to convert them
+ // to 'Unicode', UTF-16.
+
+ // Creates a UTF-16 wide string from the given ANSI string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the wide string, or NULL if the
+ // input is NULL.
+ //
+ // The wide string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static LPCWSTR AnsiToUtf16(const char* c_str);
+
+ // Creates an ANSI string from the given wide string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the ANSI string, or NULL if the
+ // input is NULL.
+ //
+ // The returned string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+ // Compares two C strings. Returns true iff they have the same content.
+ //
+ // Unlike strcmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CStringEquals(const char* lhs, const char* rhs);
+
+ // Converts a wide C string to a String using the UTF-8 encoding.
+ // NULL will be converted to "(null)". If an error occurred during
+ // the conversion, "(failed to convert from wide string)" is
+ // returned.
+ static std::string ShowWideCString(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true iff they have the same
+ // content.
+ //
+ // Unlike wcscmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+ // Compares two C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike strcasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CaseInsensitiveCStringEquals(const char* lhs,
+ const char* rhs);
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+ static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs);
+
+ // Returns true iff the given string ends with the given suffix, ignoring
+ // case. Any string is considered to end with an empty suffix.
+ static bool EndsWithCaseInsensitive(
+ const std::string& str, const std::string& suffix);
+
+ // Formats an int value as "%02d".
+ static std::string FormatIntWidth2(int value); // "%02d" for width == 2
+
+ // Formats an int value as "%X".
+ static std::string FormatHexInt(int value);
+
+ // Formats a byte as "%02X".
+ static std::string FormatByte(unsigned char value);
+
+ private:
+ String(); // Not meant to be instantiated.
+}; // class String
+
+// Gets the content of the stringstream's buffer as an std::string. Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-tuple.h b/external/gtest-1.6.0/include/gtest/internal/gtest-tuple.h
new file mode 100644
index 0000000..3e0b288
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-tuple.h
@@ -0,0 +1,1051 @@
+// This file was GENERATED by command:
+// pump.py gtest-tuple.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility> // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined). This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+ template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
+ private:
+#endif
+
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
+ void, void, void>
+#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
+ void, void, void>
+#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
+ void, void, void>
+#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
+ void, void, void>
+#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
+ void, void, void>
+#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
+ void, void, void>
+#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ void, void, void>
+#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, void, void>
+#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, T##8, void>
+#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, T##8, T##9>
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+#define GTEST_0_TYPENAMES_(T)
+#define GTEST_1_TYPENAMES_(T) typename T##0
+#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
+#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
+#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3
+#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4
+#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5
+#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6
+#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
+#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, \
+ typename T##7, typename T##8
+#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, \
+ typename T##7, typename T##8, typename T##9
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior. We can do this as we are playing the role of a standard
+// library vendor.
+namespace std
+{
+namespace tr1
+{
+
+template <typename T0 = void, typename T1 = void, typename T2 = void,
+ typename T3 = void, typename T4 = void, typename T5 = void,
+ typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal
+{
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; }; // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>. kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 0, GTEST_10_TUPLE_(T) > {
+ typedef T0 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 1, GTEST_10_TUPLE_(T) > {
+ typedef T1 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 2, GTEST_10_TUPLE_(T) > {
+ typedef T2 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 3, GTEST_10_TUPLE_(T) > {
+ typedef T3 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 4, GTEST_10_TUPLE_(T) > {
+ typedef T4 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 5, GTEST_10_TUPLE_(T) > {
+ typedef T5 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 6, GTEST_10_TUPLE_(T) > {
+ typedef T6 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 7, GTEST_10_TUPLE_(T) > {
+ typedef T7 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 8, GTEST_10_TUPLE_(T) > {
+ typedef T8 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
+ typedef T9 type;
+};
+
+} // namespace gtest_internal
+
+template <>
+class tuple<>
+{
+ public:
+ tuple() {}
+ tuple(const tuple& /* t */) {}
+ tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+class GTEST_1_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
+
+ tuple(const tuple& t) : f0_(t.f0_) {}
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ return *this;
+ }
+
+ T0 f0_;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+class GTEST_2_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
+ f1_(f1) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
+ template <typename U0, typename U1>
+ tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+ template <typename U0, typename U1>
+ tuple& operator=(const ::std::pair<U0, U1>& p) {
+ f0_ = p.first;
+ f1_ = p.second;
+ return *this;
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+class GTEST_3_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+class GTEST_4_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+class GTEST_5_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
+ GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_) {}
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+class GTEST_6_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_) {}
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+class GTEST_7_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+class GTEST_8_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
+ GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5), f6_(f6), f7_(f7) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+class GTEST_9_TUPLE_(T)
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+ GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ f8_ = t.f8_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+ T8 f8_;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+class tuple
+{
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
+ f9_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+ GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
+ f9_(t.f9_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ f8_ = t.f8_;
+ f9_ = t.f9_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+ T8 f8_;
+ T9 f9_;
+};
+
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+template <GTEST_1_TYPENAMES_(T)>
+inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0)
+{
+ return GTEST_1_TUPLE_(T)(f0);
+}
+
+template <GTEST_2_TYPENAMES_(T)>
+inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1)
+{
+ return GTEST_2_TUPLE_(T)(f0, f1);
+}
+
+template <GTEST_3_TYPENAMES_(T)>
+inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2)
+{
+ return GTEST_3_TUPLE_(T)(f0, f1, f2);
+}
+
+template <GTEST_4_TYPENAMES_(T)>
+inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3)
+{
+ return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
+}
+
+template <GTEST_5_TYPENAMES_(T)>
+inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4)
+{
+ return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
+}
+
+template <GTEST_6_TYPENAMES_(T)>
+inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5)
+{
+ return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
+}
+
+template <GTEST_7_TYPENAMES_(T)>
+inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6)
+{
+ return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
+}
+
+template <GTEST_8_TYPENAMES_(T)>
+inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7)
+{
+ return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
+}
+
+template <GTEST_9_TYPENAMES_(T)>
+inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+ const T8& f8)
+{
+ return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
+}
+
+template <GTEST_10_TYPENAMES_(T)>
+inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+ const T8& f8, const T9& f9)
+{
+ return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
+}
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+template <GTEST_0_TYPENAMES_(T)>
+struct tuple_size<GTEST_0_TUPLE_(T) > {
+ static const int value = 0;
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+struct tuple_size<GTEST_1_TUPLE_(T) > {
+ static const int value = 1;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+struct tuple_size<GTEST_2_TUPLE_(T) > {
+ static const int value = 2;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+struct tuple_size<GTEST_3_TUPLE_(T) > {
+ static const int value = 3;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+struct tuple_size<GTEST_4_TUPLE_(T) > {
+ static const int value = 4;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+struct tuple_size<GTEST_5_TUPLE_(T) > {
+ static const int value = 5;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+struct tuple_size<GTEST_6_TUPLE_(T) > {
+ static const int value = 6;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+struct tuple_size<GTEST_7_TUPLE_(T) > {
+ static const int value = 7;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+struct tuple_size<GTEST_8_TUPLE_(T) > {
+ static const int value = 8;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+struct tuple_size<GTEST_9_TUPLE_(T) > {
+ static const int value = 9;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct tuple_size<GTEST_10_TUPLE_(T) > {
+ static const int value = 10;
+};
+
+template <int k, class Tuple>
+struct tuple_element {
+ typedef typename gtest_internal::TupleElement<
+ k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal
+{
+
+template <>
+class Get<0>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+ Field(Tuple& t) { return t.f0_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+ ConstField(const Tuple& t) { return t.f0_; }
+};
+
+template <>
+class Get<1>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+ Field(Tuple& t) { return t.f1_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+ ConstField(const Tuple& t) { return t.f1_; }
+};
+
+template <>
+class Get<2>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+ Field(Tuple& t) { return t.f2_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+ ConstField(const Tuple& t) { return t.f2_; }
+};
+
+template <>
+class Get<3>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+ Field(Tuple& t) { return t.f3_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+ ConstField(const Tuple& t) { return t.f3_; }
+};
+
+template <>
+class Get<4>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+ Field(Tuple& t) { return t.f4_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+ ConstField(const Tuple& t) { return t.f4_; }
+};
+
+template <>
+class Get<5>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+ Field(Tuple& t) { return t.f5_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+ ConstField(const Tuple& t) { return t.f5_; }
+};
+
+template <>
+class Get<6>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+ Field(Tuple& t) { return t.f6_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+ ConstField(const Tuple& t) { return t.f6_; }
+};
+
+template <>
+class Get<7>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+ Field(Tuple& t) { return t.f7_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+ ConstField(const Tuple& t) { return t.f7_; }
+};
+
+template <>
+class Get<8>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+ Field(Tuple& t) { return t.f8_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+ ConstField(const Tuple& t) { return t.f8_; }
+};
+
+template <>
+class Get<9>
+{
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+ Field(Tuple& t) { return t.f9_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+ ConstField(const Tuple& t) { return t.f9_; }
+};
+
+} // namespace gtest_internal
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(GTEST_10_TUPLE_(T)& t)
+{
+ return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(const GTEST_10_TUPLE_(T)& t)
+{
+ return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal
+{
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+ return true;
+ }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+ return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+ ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+ }
+};
+
+} // namespace gtest_internal
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator==(const GTEST_10_TUPLE_(T)& t,
+ const GTEST_10_TUPLE_(U)& u)
+{
+ return gtest_internal::SameSizeTuplePrefixComparator<
+ tuple_size<GTEST_10_TUPLE_(T) >::value,
+ tuple_size<GTEST_10_TUPLE_(U) >::value>::Eq(t, u);
+}
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
+ const GTEST_10_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+} // namespace tr1
+} // namespace std
+
+#undef GTEST_0_TUPLE_
+#undef GTEST_1_TUPLE_
+#undef GTEST_2_TUPLE_
+#undef GTEST_3_TUPLE_
+#undef GTEST_4_TUPLE_
+#undef GTEST_5_TUPLE_
+#undef GTEST_6_TUPLE_
+#undef GTEST_7_TUPLE_
+#undef GTEST_8_TUPLE_
+#undef GTEST_9_TUPLE_
+#undef GTEST_10_TUPLE_
+
+#undef GTEST_0_TYPENAMES_
+#undef GTEST_1_TYPENAMES_
+#undef GTEST_2_TYPENAMES_
+#undef GTEST_3_TYPENAMES_
+#undef GTEST_4_TYPENAMES_
+#undef GTEST_5_TYPENAMES_
+#undef GTEST_6_TYPENAMES_
+#undef GTEST_7_TYPENAMES_
+#undef GTEST_8_TYPENAMES_
+#undef GTEST_9_TYPENAMES_
+#undef GTEST_10_TYPENAMES_
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-tuple.h.pump b/external/gtest-1.6.0/include/gtest/internal/gtest-tuple.h.pump
new file mode 100644
index 0000000..c7d9e03
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-tuple.h.pump
@@ -0,0 +1,339 @@
+$$ -*- mode: c++; -*-
+$var n = 10 $$ Maximum number of tuple fields we want to support.
+$$ This meta comment fixes auto-indentation in Emacs. }}
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility> // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined). This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+ template <GTEST_$(n)_TYPENAMES_(U)> friend class tuple; \
+ private:
+#endif
+
+
+$range i 0..n-1
+$range j 0..n
+$range k 1..n
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+
+$for k [[
+$range m 0..k-1
+$range m2 k..n-1
+#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]>
+
+]]
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+
+$for j [[
+$range m 0..j-1
+#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]]
+
+
+]]
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior. We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <$for i, [[typename T$i = void]]>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; }; // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>. kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+
+$for i [[
+template <GTEST_$(n)_TYPENAMES_(T)>
+struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T) > {
+ typedef T$i type;
+};
+
+
+]]
+} // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+ tuple() {}
+ tuple(const tuple& /* t */) {}
+ tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+
+$for k [[
+$range m 0..k-1
+template <GTEST_$(k)_TYPENAMES_(T)>
+class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : $for m, [[f$(m)_()]] {}
+
+ explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]]
+$for m, [[f$(m)_(f$m)]] {}
+
+ tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
+
+ template <GTEST_$(k)_TYPENAMES_(U)>
+ tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
+
+$if k == 2 [[
+ template <typename U0, typename U1>
+ tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+]]
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_$(k)_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+$if k == 2 [[
+ template <typename U0, typename U1>
+ tuple& operator=(const ::std::pair<U0, U1>& p) {
+ f0_ = p.first;
+ f1_ = p.second;
+ return *this;
+ }
+
+]]
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_$(k)_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) {
+
+$for m [[
+ f$(m)_ = t.f$(m)_;
+
+]]
+ return *this;
+ }
+
+
+$for m [[
+ T$m f$(m)_;
+
+]]
+};
+
+
+]]
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+$for k [[
+$range m 0..k-1
+
+template <GTEST_$(k)_TYPENAMES_(T)>
+inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) {
+ return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]);
+}
+
+]]
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+
+$for j [[
+template <GTEST_$(j)_TYPENAMES_(T)>
+struct tuple_size<GTEST_$(j)_TUPLE_(T) > {
+ static const int value = $j;
+};
+
+
+]]
+template <int k, class Tuple>
+struct tuple_element {
+ typedef typename gtest_internal::TupleElement<
+ k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+
+$for i [[
+template <>
+class Get<$i> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
+ Field(Tuple& t) { return t.f$(i)_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
+ ConstField(const Tuple& t) { return t.f$(i)_; }
+};
+
+
+]]
+} // namespace gtest_internal
+
+template <int k, GTEST_$(n)_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
+get(GTEST_$(n)_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_$(n)_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
+get(const GTEST_$(n)_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+ return true;
+ }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+ return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+ ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+ }
+};
+
+} // namespace gtest_internal
+
+template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
+inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
+ const GTEST_$(n)_TUPLE_(U)& u) {
+ return gtest_internal::SameSizeTuplePrefixComparator<
+ tuple_size<GTEST_$(n)_TUPLE_(T) >::value,
+ tuple_size<GTEST_$(n)_TUPLE_(U) >::value>::Eq(t, u);
+}
+
+template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t,
+ const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+} // namespace tr1
+} // namespace std
+
+
+$for j [[
+#undef GTEST_$(j)_TUPLE_
+
+]]
+
+
+$for j [[
+#undef GTEST_$(j)_TYPENAMES_
+
+]]
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-type-util.h b/external/gtest-1.6.0/include/gtest/internal/gtest-type-util.h
new file mode 100644
index 0000000..416f0ea
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-type-util.h
@@ -0,0 +1,3335 @@
+// This file was GENERATED by command:
+// pump.py gtest-type-util.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework at googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# if GTEST_HAS_CXXABI_H_
+# include <cxxabi.h>
+# elif defined(__HP_aCC)
+# include <acxx_demangle.h>
+# endif // GTEST_HASH_CXXABI_H_
+
+namespace testing
+{
+namespace internal
+{
+
+// GetTypeName<T>() returns a human-readable name of type T.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName()
+{
+# if GTEST_HAS_RTTI
+
+ const char* const name = typeid(T).name();
+# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+# if GTEST_HAS_CXXABI_H_
+ using abi::__cxa_demangle;
+# endif // GTEST_HAS_CXXABI_H_
+ char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+ const std::string name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return name_str;
+# else
+ return name;
+# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
+
+# else
+
+ return "<type>";
+
+# endif // GTEST_HAS_RTTI
+}
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type. This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+ typedef bool type;
+};
+
+// A unique type used as the default value for the arguments of class
+// template Types. This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists. In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+ typedef T1 Head;
+ typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+ typedef T1 Head;
+ typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+ typedef T1 Head;
+ typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+ typedef T1 Head;
+ typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+ typedef T1 Head;
+ typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types6 {
+ typedef T1 Head;
+ typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types7 {
+ typedef T1 Head;
+ typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types8 {
+ typedef T1 Head;
+ typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+ typedef T1 Head;
+ typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+ typedef T1 Head;
+ typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types11 {
+ typedef T1 Head;
+ typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types12 {
+ typedef T1 Head;
+ typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types13 {
+ typedef T1 Head;
+ typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+ typedef T1 Head;
+ typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+ typedef T1 Head;
+ typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types16 {
+ typedef T1 Head;
+ typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types17 {
+ typedef T1 Head;
+ typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types18 {
+ typedef T1 Head;
+ typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+ typedef T1 Head;
+ typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+ typedef T1 Head;
+ typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types21 {
+ typedef T1 Head;
+ typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types22 {
+ typedef T1 Head;
+ typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types23 {
+ typedef T1 Head;
+ typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+ typedef T1 Head;
+ typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+ typedef T1 Head;
+ typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types26 {
+ typedef T1 Head;
+ typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types27 {
+ typedef T1 Head;
+ typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types28 {
+ typedef T1 Head;
+ typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+ typedef T1 Head;
+ typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+ typedef T1 Head;
+ typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types31 {
+ typedef T1 Head;
+ typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types32 {
+ typedef T1 Head;
+ typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types33 {
+ typedef T1 Head;
+ typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+ typedef T1 Head;
+ typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+ typedef T1 Head;
+ typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types36 {
+ typedef T1 Head;
+ typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types37 {
+ typedef T1 Head;
+ typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types38 {
+ typedef T1 Head;
+ typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+ typedef T1 Head;
+ typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+ typedef T1 Head;
+ typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types41 {
+ typedef T1 Head;
+ typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types42 {
+ typedef T1 Head;
+ typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types43 {
+ typedef T1 Head;
+ typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+ typedef T1 Head;
+ typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+ typedef T1 Head;
+ typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types46 {
+ typedef T1 Head;
+ typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types47 {
+ typedef T1 Head;
+ typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types48 {
+ typedef T1 Head;
+ typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+ typedef T1 Head;
+ typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+ typedef T1 Head;
+ typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+} // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length. Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+ typename T3 = internal::None, typename T4 = internal::None,
+ typename T5 = internal::None, typename T6 = internal::None,
+ typename T7 = internal::None, typename T8 = internal::None,
+ typename T9 = internal::None, typename T10 = internal::None,
+ typename T11 = internal::None, typename T12 = internal::None,
+ typename T13 = internal::None, typename T14 = internal::None,
+ typename T15 = internal::None, typename T16 = internal::None,
+ typename T17 = internal::None, typename T18 = internal::None,
+ typename T19 = internal::None, typename T20 = internal::None,
+ typename T21 = internal::None, typename T22 = internal::None,
+ typename T23 = internal::None, typename T24 = internal::None,
+ typename T25 = internal::None, typename T26 = internal::None,
+ typename T27 = internal::None, typename T28 = internal::None,
+ typename T29 = internal::None, typename T30 = internal::None,
+ typename T31 = internal::None, typename T32 = internal::None,
+ typename T33 = internal::None, typename T34 = internal::None,
+ typename T35 = internal::None, typename T36 = internal::None,
+ typename T37 = internal::None, typename T38 = internal::None,
+ typename T39 = internal::None, typename T40 = internal::None,
+ typename T41 = internal::None, typename T42 = internal::None,
+ typename T43 = internal::None, typename T44 = internal::None,
+ typename T45 = internal::None, typename T46 = internal::None,
+ typename T47 = internal::None, typename T48 = internal::None,
+ typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+ typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, internal::None, internal::None, internal::None> {
+ typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, internal::None, internal::None> {
+ typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, T49, internal::None> {
+ typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal
+{
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates. This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists. In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN). Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates4 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates7 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates10 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates13 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates16 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates19 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates22 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates25 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates28 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates31 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates34 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates37 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates40 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates43 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates46 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates49 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length. Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+ GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+ GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+ GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+ GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+ GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+ GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+ GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+ GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+ GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+ GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+ GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+ GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+ GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+ GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+ GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+ GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+ GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+ GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+ GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+ GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+ GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+ GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+ GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+ GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+ typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, NoneT, NoneT, NoneT> {
+ typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, NoneT, NoneT> {
+ typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, T49, NoneT> {
+ typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList {
+ typedef Types1<T> type;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> > {
+ typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/external/gtest-1.6.0/include/gtest/internal/gtest-type-util.h.pump b/external/gtest-1.6.0/include/gtest/internal/gtest-type-util.h.pump
new file mode 100644
index 0000000..251fdf0
--- /dev/null
+++ b/external/gtest-1.6.0/include/gtest/internal/gtest-type-util.h.pump
@@ -0,0 +1,297 @@
+$$ -*- mode: c++; -*-
+$var n = 50 $$ Maximum length of type lists we want to support.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently we support at most $n types in a list, and at most $n
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework at googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# if GTEST_HAS_CXXABI_H_
+# include <cxxabi.h>
+# elif defined(__HP_aCC)
+# include <acxx_demangle.h>
+# endif // GTEST_HASH_CXXABI_H_
+
+namespace testing {
+namespace internal {
+
+// GetTypeName<T>() returns a human-readable name of type T.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+# if GTEST_HAS_RTTI
+
+ const char* const name = typeid(T).name();
+# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+# if GTEST_HAS_CXXABI_H_
+ using abi::__cxa_demangle;
+# endif // GTEST_HAS_CXXABI_H_
+ char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+ const std::string name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return name_str;
+# else
+ return name;
+# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
+
+# else
+
+ return "<type>";
+
+# endif // GTEST_HAS_RTTI
+}
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type. This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+ typedef bool type;
+};
+
+// A unique type used as the default value for the arguments of class
+// template Types. This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists. In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+ typedef T1 Head;
+ typedef Types0 Tail;
+};
+
+$range i 2..n
+
+$for i [[
+$range j 1..i
+$range k 2..i
+template <$for j, [[typename T$j]]>
+struct Types$i {
+ typedef T1 Head;
+ typedef Types$(i-1)<$for k, [[T$k]]> Tail;
+};
+
+
+]]
+
+} // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length. Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Types template.
+
+$range i 1..n
+template <$for i, [[typename T$i = internal::None]]>
+struct Types {
+ typedef internal::Types$n<$for i, [[T$i]]> type;
+};
+
+template <>
+struct Types<$for i, [[internal::None]]> {
+ typedef internal::Types0 type;
+};
+
+$range i 1..n-1
+$for i [[
+$range j 1..i
+$range k i+1..n
+template <$for j, [[typename T$j]]>
+struct Types<$for j, [[T$j]]$for k[[, internal::None]]> {
+ typedef internal::Types$i<$for j, [[T$j]]> type;
+};
+
+]]
+
+namespace internal {
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates. This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists. In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN). Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates0 Tail;
+};
+
+$range i 2..n
+
+$for i [[
+$range j 1..i
+$range k 2..i
+template <$for j, [[GTEST_TEMPLATE_ T$j]]>
+struct Templates$i {
+ typedef TemplateSel<T1> Head;
+ typedef Templates$(i-1)<$for k, [[T$k]]> Tail;
+};
+
+
+]]
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length. Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Templates template.
+
+$range i 1..n
+template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]>
+struct Templates {
+ typedef Templates$n<$for i, [[T$i]]> type;
+};
+
+template <>
+struct Templates<$for i, [[NoneT]]> {
+ typedef Templates0 type;
+};
+
+$range i 1..n-1
+$for i [[
+$range j 1..i
+$range k i+1..n
+template <$for j, [[GTEST_TEMPLATE_ T$j]]>
+struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
+ typedef Templates$i<$for j, [[T$j]]> type;
+};
+
+]]
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList {
+ typedef Types1<T> type;
+};
+
+
+$range i 1..n
+template <$for i, [[typename T$i]]>
+struct TypeList<Types<$for i, [[T$i]]> > {
+ typedef typename Types<$for i, [[T$i]]>::type type;
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/external/gtest-1.6.0/m4/acx_pthread.m4 b/external/gtest-1.6.0/m4/acx_pthread.m4
new file mode 100644
index 0000000..2cf20de
--- /dev/null
+++ b/external/gtest-1.6.0/m4/acx_pthread.m4
@@ -0,0 +1,363 @@
+# This was retrieved from
+# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi
+# See also (perhaps for new versions?)
+# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi
+#
+# We've rewritten the inconsistency check code (from avahi), to work
+# more broadly. In particular, it no longer assumes ld accepts -zdefs.
+# This caused a restructing of the code, but the functionality has only
+# changed a little.
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl LIBS="$PTHREAD_LIBS $LIBS"
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj at alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+dnl
+dnl Checks for GCC shared/pthread inconsistency based on work by
+dnl Marcin Owsiany <marcin at owsiany.pl>
+
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+ else
+ PTHREAD_CC=$CC
+ fi
+
+ # The next part tries to detect GCC inconsistency with -shared on some
+ # architectures and systems. The problem is that in certain
+ # configurations, when -shared is specified, GCC "forgets" to
+ # internally use various flags which are still necessary.
+
+ #
+ # Prepare the flags
+ #
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ save_CC="$CC"
+
+ # Try with the flags determined by the earlier checks.
+ #
+ # -Wl,-z,defs forces link-time symbol resolution, so that the
+ # linking checks with -shared actually have any value
+ #
+ # FIXME: -fPIC is required for -shared on many architectures,
+ # so we specify it here, but the right way would probably be to
+ # properly detect whether it is actually required.
+ CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CC="$PTHREAD_CC"
+
+ # In order not to create several levels of indentation, we test
+ # the value of "$done" until we find the cure or run out of ideas.
+ done="no"
+
+ # First, make sure the CFLAGS we added are actually accepted by our
+ # compiler. If not (and OS X's ld, for instance, does not accept -z),
+ # then we can't do this test.
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies])
+ AC_TRY_LINK(,, , [done=yes])
+
+ if test "x$done" = xyes ; then
+ AC_MSG_RESULT([no])
+ else
+ AC_MSG_RESULT([yes])
+ fi
+ fi
+
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -pthread is sufficient with -shared])
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ #
+ # Linux gcc on some architectures such as mips/mipsel forgets
+ # about -lpthread
+ #
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -lpthread fixes that])
+ LIBS="-lpthread $PTHREAD_LIBS $save_LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ #
+ # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc
+ #
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -lc_r fixes that])
+ LIBS="-lc_r $PTHREAD_LIBS $save_LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ if test x"$done" = xno; then
+ # OK, we have run out of ideas
+ AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries])
+
+ # so it's not safe to assume that we may use pthreads
+ acx_pthread_ok=no
+ fi
+
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ CC="$save_CC"
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/external/gtest-1.6.0/m4/gtest.m4 b/external/gtest-1.6.0/m4/gtest.m4
new file mode 100644
index 0000000..6598ba7
--- /dev/null
+++ b/external/gtest-1.6.0/m4/gtest.m4
@@ -0,0 +1,74 @@
+dnl GTEST_LIB_CHECK([minimum version [,
+dnl action if found [,action if not found]]])
+dnl
+dnl Check for the presence of the Google Test library, optionally at a minimum
+dnl version, and indicate a viable version with the HAVE_GTEST flag. It defines
+dnl standard variables for substitution including GTEST_CPPFLAGS,
+dnl GTEST_CXXFLAGS, GTEST_LDFLAGS, and GTEST_LIBS. It also defines
+dnl GTEST_VERSION as the version of Google Test found. Finally, it provides
+dnl optional custom action slots in the event GTEST is found or not.
+AC_DEFUN([GTEST_LIB_CHECK],
+[
+dnl Provide a flag to enable or disable Google Test usage.
+AC_ARG_ENABLE([gtest],
+ [AS_HELP_STRING([--enable-gtest],
+ [Enable tests using the Google C++ Testing Framework.
+ (Default is enabled.)])],
+ [],
+ [enable_gtest=])
+AC_ARG_VAR([GTEST_CONFIG],
+ [The exact path of Google Test's 'gtest-config' script.])
+AC_ARG_VAR([GTEST_CPPFLAGS],
+ [C-like preprocessor flags for Google Test.])
+AC_ARG_VAR([GTEST_CXXFLAGS],
+ [C++ compile flags for Google Test.])
+AC_ARG_VAR([GTEST_LDFLAGS],
+ [Linker path and option flags for Google Test.])
+AC_ARG_VAR([GTEST_LIBS],
+ [Library linking flags for Google Test.])
+AC_ARG_VAR([GTEST_VERSION],
+ [The version of Google Test available.])
+HAVE_GTEST="no"
+AS_IF([test "x${enable_gtest}" != "xno"],
+ [AC_MSG_CHECKING([for 'gtest-config'])
+ AS_IF([test "x${enable_gtest}" != "xyes"],
+ [AS_IF([test -x "${enable_gtest}/scripts/gtest-config"],
+ [GTEST_CONFIG="${enable_gtest}/scripts/gtest-config"],
+ [GTEST_CONFIG="${enable_gtest}/bin/gtest-config"])
+ AS_IF([test -x "${GTEST_CONFIG}"], [],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([dnl
+Unable to locate either a built or installed Google Test.
+The specific location '${enable_gtest}' was provided for a built or installed
+Google Test, but no 'gtest-config' script could be found at this location.])
+ ])],
+ [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])])
+ AS_IF([test -x "${GTEST_CONFIG}"],
+ [AC_MSG_RESULT([${GTEST_CONFIG}])
+ m4_ifval([$1],
+ [_gtest_min_version="--min-version=$1"
+ AC_MSG_CHECKING([for Google Test at least version >= $1])],
+ [_gtest_min_version="--min-version=0"
+ AC_MSG_CHECKING([for Google Test])])
+ AS_IF([${GTEST_CONFIG} ${_gtest_min_version}],
+ [AC_MSG_RESULT([yes])
+ HAVE_GTEST='yes'],
+ [AC_MSG_RESULT([no])])],
+ [AC_MSG_RESULT([no])])
+ AS_IF([test "x${HAVE_GTEST}" = "xyes"],
+ [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags`
+ GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags`
+ GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags`
+ GTEST_LIBS=`${GTEST_CONFIG} --libs`
+ GTEST_VERSION=`${GTEST_CONFIG} --version`
+ AC_DEFINE([HAVE_GTEST],[1],[Defined when Google Test is available.])],
+ [AS_IF([test "x${enable_gtest}" = "xyes"],
+ [AC_MSG_ERROR([dnl
+Google Test was enabled, but no viable version could be found.])
+ ])])])
+AC_SUBST([HAVE_GTEST])
+AM_CONDITIONAL([HAVE_GTEST],[test "x$HAVE_GTEST" = "xyes"])
+AS_IF([test "x$HAVE_GTEST" = "xyes"],
+ [m4_ifval([$2], [$2])],
+ [m4_ifval([$3], [$3])])
+])
diff --git a/external/gtest-1.6.0/make/Makefile b/external/gtest-1.6.0/make/Makefile
new file mode 100644
index 0000000..9ac7449
--- /dev/null
+++ b/external/gtest-1.6.0/make/Makefile
@@ -0,0 +1,82 @@
+# A sample Makefile for building Google Test and using it in user
+# tests. Please tweak it to suit your environment and project. You
+# may want to move it to your project's root directory.
+#
+# SYNOPSIS:
+#
+# make [all] - makes everything.
+# make TARGET - makes the given target.
+# make clean - removes all files generated by make.
+
+# Please tweak the following variable definitions as needed by your
+# project, except GTEST_HEADERS, which you can use in your own targets
+# but shouldn't modify.
+
+# Points to the root of Google Test, relative to where this file is.
+# Remember to tweak this if you move this file.
+GTEST_DIR = ..
+
+# Where to find user code.
+USER_DIR = ../samples
+
+# Flags passed to the preprocessor.
+# Set Google Test's header directory as a system directory, such that
+# the compiler doesn't generate warnings in Google Test headers.
+CPPFLAGS += -isystem $(GTEST_DIR)/include
+
+# Flags passed to the C++ compiler.
+CXXFLAGS += -g -Wall -Wextra -pthread
+
+# All tests produced by this Makefile. Remember to add new tests you
+# created to the list.
+TESTS = sample1_unittest
+
+# All Google Test headers. Usually you shouldn't change this
+# definition.
+GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
+ $(GTEST_DIR)/include/gtest/internal/*.h
+
+# House-keeping build targets.
+
+all : $(TESTS)
+
+clean :
+ rm -f $(TESTS) gtest.a gtest_main.a *.o
+
+# Builds gtest.a and gtest_main.a.
+
+# Usually you shouldn't tweak such internal variables, indicated by a
+# trailing _.
+GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
+
+# For simplicity and to avoid depending on Google Test's
+# implementation details, the dependencies specified below are
+# conservative and not optimized. This is fine as Google Test
+# compiles fast and for ordinary users its source rarely changes.
+gtest-all.o : $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest-all.cc
+
+gtest_main.o : $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest_main.cc
+
+gtest.a : gtest-all.o
+ $(AR) $(ARFLAGS) $@ $^
+
+gtest_main.a : gtest-all.o gtest_main.o
+ $(AR) $(ARFLAGS) $@ $^
+
+# Builds a sample test. A test should link with either gtest.a or
+# gtest_main.a, depending on whether it defines its own main()
+# function.
+
+sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc
+
+sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \
+ $(USER_DIR)/sample1.h $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc
+
+sample1_unittest : sample1.o sample1_unittest.o gtest_main.a
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
diff --git a/external/gtest-1.6.0/msvc/gtest-md.sln b/external/gtest-1.6.0/msvc/gtest-md.sln
new file mode 100644
index 0000000..f7908da
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest-md.sln
@@ -0,0 +1,45 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest-md.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "gtest_main-md.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test-md", "gtest_prod_test-md.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest-md", "gtest_unittest-md.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.Build.0 = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.Build.0 = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.ActiveCfg = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.Build.0 = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.ActiveCfg = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.Build.0 = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.ActiveCfg = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.Build.0 = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.ActiveCfg = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.Build.0 = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.ActiveCfg = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.Build.0 = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.ActiveCfg = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/external/gtest-1.6.0/msvc/gtest-md.vcproj b/external/gtest-1.6.0/msvc/gtest-md.vcproj
new file mode 100644
index 0000000..1c35c3a
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest-md.vcproj
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest-md"
+ ProjectGUID="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/gtestd.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath=""..\include";".."">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/gtest.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest-all.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest.sln b/external/gtest-1.6.0/msvc/gtest.sln
new file mode 100644
index 0000000..ef4b057
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest.sln
@@ -0,0 +1,45 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest", "gtest_unittest.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test", "gtest_prod_test.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.Build.0 = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.Build.0 = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.ActiveCfg = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.Build.0 = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.ActiveCfg = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.Build.0 = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.ActiveCfg = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.Build.0 = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.ActiveCfg = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.Build.0 = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.ActiveCfg = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.Build.0 = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.ActiveCfg = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/external/gtest-1.6.0/msvc/gtest.vcproj b/external/gtest-1.6.0/msvc/gtest.vcproj
new file mode 100644
index 0000000..a8373ce
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest.vcproj
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest"
+ ProjectGUID="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/gtestd.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath=""..\include";".."">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/gtest.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest-all.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest_main-md.vcproj b/external/gtest-1.6.0/msvc/gtest_main-md.vcproj
new file mode 100644
index 0000000..b5379fe
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest_main-md.vcproj
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_main-md"
+ ProjectGUID="{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName)d.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath=""..\include";".."">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName).lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+ Name="gtest-md"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest_main.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest_main.vcproj b/external/gtest-1.6.0/msvc/gtest_main.vcproj
new file mode 100644
index 0000000..e8b763c
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest_main.vcproj
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_main"
+ ProjectGUID="{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName)d.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath=""..\include";".."">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName).lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
+ Name="gtest"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest_main.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest_prod_test-md.vcproj b/external/gtest-1.6.0/msvc/gtest_prod_test-md.vcproj
new file mode 100644
index 0000000..05b05d9
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest_prod_test-md.vcproj
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_prod_test-md"
+ ProjectGUID="{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_prod_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ Name="gtest_main-md"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_prod_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\test\production.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\test\production.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest_prod_test.vcproj b/external/gtest-1.6.0/msvc/gtest_prod_test.vcproj
new file mode 100644
index 0000000..6d7a2f0
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest_prod_test.vcproj
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_prod_test"
+ ProjectGUID="{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_prod_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ Name="gtest_main"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_prod_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\test\production.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\test\production.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest_unittest-md.vcproj b/external/gtest-1.6.0/msvc/gtest_unittest-md.vcproj
new file mode 100644
index 0000000..38a5e56
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest_unittest-md.vcproj
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_unittest-md"
+ ProjectGUID="{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_unittest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ Name="gtest_main-md"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_unittest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""..";"..\include""
+ BasicRuntimeChecks="0"
+ UsePrecompiledHeader="0"
+ DebugInformationFormat="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/msvc/gtest_unittest.vcproj b/external/gtest-1.6.0/msvc/gtest_unittest.vcproj
new file mode 100644
index 0000000..cb1f52b
--- /dev/null
+++ b/external/gtest-1.6.0/msvc/gtest_unittest.vcproj
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_unittest"
+ ProjectGUID="{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_unittest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ Name="gtest_main"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_unittest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""..";"..\include""
+ BasicRuntimeChecks="0"
+ UsePrecompiledHeader="0"
+ DebugInformationFormat="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..";"..\include""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/external/gtest-1.6.0/samples/prime_tables.h b/external/gtest-1.6.0/samples/prime_tables.h
new file mode 100644
index 0000000..64f4552
--- /dev/null
+++ b/external/gtest-1.6.0/samples/prime_tables.h
@@ -0,0 +1,126 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+// Author: vladl at google.com (Vlad Losev)
+
+// This provides interface PrimeTable that determines whether a number is a
+// prime and determines a next prime number. This interface is used
+// in Google Test samples demonstrating use of parameterized tests.
+
+#ifndef GTEST_SAMPLES_PRIME_TABLES_H_
+#define GTEST_SAMPLES_PRIME_TABLES_H_
+
+#include <algorithm>
+
+// The prime table interface.
+class PrimeTable
+{
+ public:
+ virtual ~PrimeTable() {}
+
+ // Returns true iff n is a prime number.
+ virtual bool IsPrime(int n) const = 0;
+
+ // Returns the smallest prime number greater than p; or returns -1
+ // if the next prime is beyond the capacity of the table.
+ virtual int GetNextPrime(int p) const = 0;
+};
+
+// Implementation #1 calculates the primes on-the-fly.
+class OnTheFlyPrimeTable : public PrimeTable
+{
+ public:
+ virtual bool IsPrime(int n) const {
+ if (n <= 1) return false;
+
+ for (int i = 2; i*i <= n; i++) {
+ // n is divisible by an integer other than 1 and itself.
+ if ((n % i) == 0) return false;
+ }
+
+ return true;
+ }
+
+ virtual int GetNextPrime(int p) const {
+ for (int n = p + 1; n > 0; n++) {
+ if (IsPrime(n)) return n;
+ }
+
+ return -1;
+ }
+};
+
+// Implementation #2 pre-calculates the primes and stores the result
+// in an array.
+class PreCalculatedPrimeTable : public PrimeTable
+{
+ public:
+ // 'max' specifies the maximum number the prime table holds.
+ explicit PreCalculatedPrimeTable(int max)
+ : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) {
+ CalculatePrimesUpTo(max);
+ }
+ virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; }
+
+ virtual bool IsPrime(int n) const {
+ return 0 <= n && n < is_prime_size_ && is_prime_[n];
+ }
+
+ virtual int GetNextPrime(int p) const {
+ for (int n = p + 1; n < is_prime_size_; n++) {
+ if (is_prime_[n]) return n;
+ }
+
+ return -1;
+ }
+
+ private:
+ void CalculatePrimesUpTo(int max) {
+ ::std::fill(is_prime_, is_prime_ + is_prime_size_, true);
+ is_prime_[0] = is_prime_[1] = false;
+
+ for (int i = 2; i <= max; i++) {
+ if (!is_prime_[i]) continue;
+
+ // Marks all multiples of i (except i itself) as non-prime.
+ for (int j = 2*i; j <= max; j += i) {
+ is_prime_[j] = false;
+ }
+ }
+ }
+
+ const int is_prime_size_;
+ bool* const is_prime_;
+
+ // Disables compiler warning "assignment operator could not be generated."
+ void operator=(const PreCalculatedPrimeTable& rhs);
+};
+
+#endif // GTEST_SAMPLES_PRIME_TABLES_H_
diff --git a/external/gtest-1.6.0/samples/sample1.cc b/external/gtest-1.6.0/samples/sample1.cc
new file mode 100644
index 0000000..7a7f821
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample1.cc
@@ -0,0 +1,70 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "sample1.h"
+
+// Returns n! (the factorial of n). For negative n, n! is defined to be 1.
+int Factorial(int n)
+{
+ int result = 1;
+ for (int i = 1; i <= n; i++) {
+ result *= i;
+ }
+
+ return result;
+}
+
+// Returns true iff n is a prime number.
+bool IsPrime(int n)
+{
+ // Trivial case 1: small numbers
+ if (n <= 1) return false;
+
+ // Trivial case 2: even numbers
+ if (n % 2 == 0) return n == 2;
+
+ // Now, we have that n is odd and n >= 3.
+
+ // Try to divide n by every odd number i, starting from 3
+ for (int i = 3; ; i += 2) {
+ // We only have to try i up to the squre root of n
+ if (i > n/i) break;
+
+ // Now, we have i <= n/i < n.
+ // If n is divisible by i, n is not prime.
+ if (n % i == 0) return false;
+ }
+
+ // n has no integer factor in the range (1, n), and thus is prime.
+ return true;
+}
diff --git a/external/gtest-1.6.0/samples/sample1.h b/external/gtest-1.6.0/samples/sample1.h
new file mode 100644
index 0000000..3dfeb98
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample1.h
@@ -0,0 +1,43 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE1_H_
+#define GTEST_SAMPLES_SAMPLE1_H_
+
+// Returns n! (the factorial of n). For negative n, n! is defined to be 1.
+int Factorial(int n);
+
+// Returns true iff n is a prime number.
+bool IsPrime(int n);
+
+#endif // GTEST_SAMPLES_SAMPLE1_H_
diff --git a/external/gtest-1.6.0/samples/sample10_unittest.cc b/external/gtest-1.6.0/samples/sample10_unittest.cc
new file mode 100644
index 0000000..b2cbdcd
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample10_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// This sample shows how to use Google Test listener API to implement
+// a primitive leak checker.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gtest/gtest.h"
+
+using ::testing::EmptyTestEventListener;
+using ::testing::InitGoogleTest;
+using ::testing::Test;
+using ::testing::TestCase;
+using ::testing::TestEventListeners;
+using ::testing::TestInfo;
+using ::testing::TestPartResult;
+using ::testing::UnitTest;
+
+namespace
+{
+
+// We will track memory used by this class.
+class Water
+{
+ public:
+ // Normal Water declarations go here.
+
+ // operator new and operator delete help us control water allocation.
+ void* operator new(size_t allocation_size) {
+ allocated_++;
+ return malloc(allocation_size);
+ }
+
+ void operator delete(void* block, size_t /* allocation_size */) {
+ allocated_--;
+ free(block);
+ }
+
+ static int allocated() { return allocated_; }
+
+ private:
+ static int allocated_;
+};
+
+int Water::allocated_ = 0;
+
+// This event listener monitors how many Water objects are created and
+// destroyed by each test, and reports a failure if a test leaks some Water
+// objects. It does this by comparing the number of live Water objects at
+// the beginning of a test and at the end of a test.
+class LeakChecker : public EmptyTestEventListener
+{
+ private:
+ // Called before a test starts.
+ virtual void OnTestStart(const TestInfo& /* test_info */) {
+ initially_allocated_ = Water::allocated();
+ }
+
+ // Called after a test ends.
+ virtual void OnTestEnd(const TestInfo& /* test_info */) {
+ int difference = Water::allocated() - initially_allocated_;
+
+ // You can generate a failure in any event handler except
+ // OnTestPartResult. Just use an appropriate Google Test assertion to do
+ // it.
+ EXPECT_LE(difference, 0) << "Leaked " << difference << " unit(s) of Water!";
+ }
+
+ int initially_allocated_;
+};
+
+TEST(ListenersTest, DoesNotLeak)
+{
+ Water* water = new Water;
+ delete water;
+}
+
+// This should fail when the --check_for_leaks command line flag is
+// specified.
+TEST(ListenersTest, LeaksWater)
+{
+ Water* water = new Water;
+ EXPECT_TRUE(water != NULL);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ InitGoogleTest(&argc, argv);
+
+ bool check_for_leaks = false;
+ if (argc > 1 && strcmp(argv[1], "--check_for_leaks") == 0)
+ check_for_leaks = true;
+ else
+ printf("%s\n", "Run this program with --check_for_leaks to enable "
+ "custom leak checking in the tests.");
+
+ // If we are given the --check_for_leaks command line flag, installs the
+ // leak checker.
+ if (check_for_leaks) {
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+
+ // Adds the leak checker to the end of the test event listener list,
+ // after the default text output printer and the default XML report
+ // generator.
+ //
+ // The order is important - it ensures that failures generated in the
+ // leak checker's OnTestEnd() method are processed by the text and XML
+ // printers *before* their OnTestEnd() methods are called, such that
+ // they are attributed to the right test. Remember that a listener
+ // receives an OnXyzStart event *after* listeners preceding it in the
+ // list received that event, and receives an OnXyzEnd event *before*
+ // listeners preceding it.
+ //
+ // We don't need to worry about deleting the new listener later, as
+ // Google Test will do it.
+ listeners.Append(new LeakChecker);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/samples/sample1_unittest.cc b/external/gtest-1.6.0/samples/sample1_unittest.cc
new file mode 100644
index 0000000..35c5287
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample1_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+
+// This sample shows how to write a simple unit test for a function,
+// using Google C++ testing framework.
+//
+// Writing a unit test using Google C++ testing framework is easy as 1-2-3:
+
+
+// Step 1. Include necessary header files such that the stuff your
+// test logic needs is declared.
+//
+// Don't forget gtest.h, which declares the testing framework.
+
+#include <limits.h>
+#include "sample1.h"
+#include "gtest/gtest.h"
+
+
+// Step 2. Use the TEST macro to define your tests.
+//
+// TEST has two parameters: the test case name and the test name.
+// After using the macro, you should define your test logic between a
+// pair of braces. You can use a bunch of macros to indicate the
+// success or failure of a test. EXPECT_TRUE and EXPECT_EQ are
+// examples of such macros. For a complete list, see gtest.h.
+//
+// <TechnicalDetails>
+//
+// In Google Test, tests are grouped into test cases. This is how we
+// keep test code organized. You should put logically related tests
+// into the same test case.
+//
+// The test case name and the test name should both be valid C++
+// identifiers. And you should not use underscore (_) in the names.
+//
+// Google Test guarantees that each test you define is run exactly
+// once, but it makes no guarantee on the order the tests are
+// executed. Therefore, you should write your tests in such a way
+// that their results don't depend on their order.
+//
+// </TechnicalDetails>
+
+
+// Tests Factorial().
+
+// Tests factorial of negative numbers.
+TEST(FactorialTest, Negative)
+{
+ // This test is named "Negative", and belongs to the "FactorialTest"
+ // test case.
+ EXPECT_EQ(1, Factorial(-5));
+ EXPECT_EQ(1, Factorial(-1));
+ EXPECT_GT(Factorial(-10), 0);
+
+ // <TechnicalDetails>
+ //
+ // EXPECT_EQ(expected, actual) is the same as
+ //
+ // EXPECT_TRUE((expected) == (actual))
+ //
+ // except that it will print both the expected value and the actual
+ // value when the assertion fails. This is very helpful for
+ // debugging. Therefore in this case EXPECT_EQ is preferred.
+ //
+ // On the other hand, EXPECT_TRUE accepts any Boolean expression,
+ // and is thus more general.
+ //
+ // </TechnicalDetails>
+}
+
+// Tests factorial of 0.
+TEST(FactorialTest, Zero)
+{
+ EXPECT_EQ(1, Factorial(0));
+}
+
+// Tests factorial of positive numbers.
+TEST(FactorialTest, Positive)
+{
+ EXPECT_EQ(1, Factorial(1));
+ EXPECT_EQ(2, Factorial(2));
+ EXPECT_EQ(6, Factorial(3));
+ EXPECT_EQ(40320, Factorial(8));
+}
+
+
+// Tests IsPrime()
+
+// Tests negative input.
+TEST(IsPrimeTest, Negative)
+{
+ // This test belongs to the IsPrimeTest test case.
+
+ EXPECT_FALSE(IsPrime(-1));
+ EXPECT_FALSE(IsPrime(-2));
+ EXPECT_FALSE(IsPrime(INT_MIN));
+}
+
+// Tests some trivial cases.
+TEST(IsPrimeTest, Trivial)
+{
+ EXPECT_FALSE(IsPrime(0));
+ EXPECT_FALSE(IsPrime(1));
+ EXPECT_TRUE(IsPrime(2));
+ EXPECT_TRUE(IsPrime(3));
+}
+
+// Tests positive input.
+TEST(IsPrimeTest, Positive)
+{
+ EXPECT_FALSE(IsPrime(4));
+ EXPECT_TRUE(IsPrime(5));
+ EXPECT_FALSE(IsPrime(6));
+ EXPECT_TRUE(IsPrime(23));
+}
+
+// Step 3. Call RUN_ALL_TESTS() in main().
+//
+// We do this by linking in src/gtest_main.cc file, which consists of
+// a main() function which calls RUN_ALL_TESTS() for us.
+//
+// This runs all the tests you've defined, prints the result, and
+// returns 0 if successful, or 1 otherwise.
+//
+// Did you notice that we didn't register the tests? The
+// RUN_ALL_TESTS() macro magically knows about all the tests we
+// defined. Isn't this convenient?
diff --git a/external/gtest-1.6.0/samples/sample2.cc b/external/gtest-1.6.0/samples/sample2.cc
new file mode 100644
index 0000000..7fee2c7
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample2.cc
@@ -0,0 +1,58 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "sample2.h"
+
+#include <string.h>
+
+// Clones a 0-terminated C string, allocating memory using new.
+const char* MyString::CloneCString(const char* a_c_string)
+{
+ if (a_c_string == NULL) return NULL;
+
+ const size_t len = strlen(a_c_string);
+ char* const clone = new char[ len + 1 ];
+ memcpy(clone, a_c_string, len + 1);
+
+ return clone;
+}
+
+// Sets the 0-terminated C string this MyString object
+// represents.
+void MyString::Set(const char* a_c_string)
+{
+ // Makes sure this works when c_string == c_string_
+ const char* const temp = MyString::CloneCString(a_c_string);
+ delete[] c_string_;
+ c_string_ = temp;
+}
diff --git a/external/gtest-1.6.0/samples/sample2.h b/external/gtest-1.6.0/samples/sample2.h
new file mode 100644
index 0000000..c7ddc90
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample2.h
@@ -0,0 +1,86 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE2_H_
+#define GTEST_SAMPLES_SAMPLE2_H_
+
+#include <string.h>
+
+
+// A simple string class.
+class MyString
+{
+ private:
+ const char* c_string_;
+ const MyString& operator=(const MyString& rhs);
+
+ public:
+ // Clones a 0-terminated C string, allocating memory using new.
+ static const char* CloneCString(const char* a_c_string);
+
+ ////////////////////////////////////////////////////////////
+ //
+ // C'tors
+
+ // The default c'tor constructs a NULL string.
+ MyString() : c_string_(NULL) {}
+
+ // Constructs a MyString by cloning a 0-terminated C string.
+ explicit MyString(const char* a_c_string) : c_string_(NULL) {
+ Set(a_c_string);
+ }
+
+ // Copy c'tor
+ MyString(const MyString& string) : c_string_(NULL) {
+ Set(string.c_string_);
+ }
+
+ ////////////////////////////////////////////////////////////
+ //
+ // D'tor. MyString is intended to be a final class, so the d'tor
+ // doesn't need to be virtual.
+ ~MyString() { delete[] c_string_; }
+
+ // Gets the 0-terminated C string this MyString object represents.
+ const char* c_string() const { return c_string_; }
+
+ size_t Length() const {
+ return c_string_ == NULL ? 0 : strlen(c_string_);
+ }
+
+ // Sets the 0-terminated C string this MyString object represents.
+ void Set(const char* c_string);
+};
+
+
+#endif // GTEST_SAMPLES_SAMPLE2_H_
diff --git a/external/gtest-1.6.0/samples/sample2_unittest.cc b/external/gtest-1.6.0/samples/sample2_unittest.cc
new file mode 100644
index 0000000..a349a08
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample2_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+
+// This sample shows how to write a more complex unit test for a class
+// that has multiple member functions.
+//
+// Usually, it's a good idea to have one test for each method in your
+// class. You don't have to do that exactly, but it helps to keep
+// your tests organized. You may also throw in additional tests as
+// needed.
+
+#include "sample2.h"
+#include "gtest/gtest.h"
+
+// In this example, we test the MyString class (a simple string).
+
+// Tests the default c'tor.
+TEST(MyString, DefaultConstructor)
+{
+ const MyString s;
+
+ // Asserts that s.c_string() returns NULL.
+ //
+ // <TechnicalDetails>
+ //
+ // If we write NULL instead of
+ //
+ // static_cast<const char *>(NULL)
+ //
+ // in this assertion, it will generate a warning on gcc 3.4. The
+ // reason is that EXPECT_EQ needs to know the types of its
+ // arguments in order to print them when it fails. Since NULL is
+ // #defined as 0, the compiler will use the formatter function for
+ // int to print it. However, gcc thinks that NULL should be used as
+ // a pointer, not an int, and therefore complains.
+ //
+ // The root of the problem is C++'s lack of distinction between the
+ // integer number 0 and the null pointer constant. Unfortunately,
+ // we have to live with this fact.
+ //
+ // </TechnicalDetails>
+ EXPECT_STREQ(NULL, s.c_string());
+
+ EXPECT_EQ(0u, s.Length());
+}
+
+const char kHelloString[] = "Hello, world!";
+
+// Tests the c'tor that accepts a C string.
+TEST(MyString, ConstructorFromCString)
+{
+ const MyString s(kHelloString);
+ EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));
+ EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1,
+ s.Length());
+}
+
+// Tests the copy c'tor.
+TEST(MyString, CopyConstructor)
+{
+ const MyString s1(kHelloString);
+ const MyString s2 = s1;
+ EXPECT_EQ(0, strcmp(s2.c_string(), kHelloString));
+}
+
+// Tests the Set method.
+TEST(MyString, Set)
+{
+ MyString s;
+
+ s.Set(kHelloString);
+ EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));
+
+ // Set should work when the input pointer is the same as the one
+ // already in the MyString object.
+ s.Set(s.c_string());
+ EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));
+
+ // Can we set the MyString to NULL?
+ s.Set(NULL);
+ EXPECT_STREQ(NULL, s.c_string());
+}
diff --git a/external/gtest-1.6.0/samples/sample3-inl.h b/external/gtest-1.6.0/samples/sample3-inl.h
new file mode 100644
index 0000000..83a961c
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample3-inl.h
@@ -0,0 +1,174 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE3_INL_H_
+#define GTEST_SAMPLES_SAMPLE3_INL_H_
+
+#include <stddef.h>
+
+
+// Queue is a simple queue implemented as a singled-linked list.
+//
+// The element type must support copy constructor.
+template <typename E> // E is the element type
+class Queue;
+
+// QueueNode is a node in a Queue, which consists of an element of
+// type E and a pointer to the next node.
+template <typename E> // E is the element type
+class QueueNode
+{
+ friend class Queue<E>;
+
+ public:
+ // Gets the element in this node.
+ const E& element() const { return element_; }
+
+ // Gets the next node in the queue.
+ QueueNode* next() { return next_; }
+ const QueueNode* next() const { return next_; }
+
+ private:
+ // Creates a node with a given element value. The next pointer is
+ // set to NULL.
+ explicit QueueNode(const E& an_element) : element_(an_element), next_(NULL) {}
+
+ // We disable the default assignment operator and copy c'tor.
+ const QueueNode& operator = (const QueueNode&);
+ QueueNode(const QueueNode&);
+
+ E element_;
+ QueueNode* next_;
+};
+
+template <typename E> // E is the element type.
+class Queue
+{
+ public:
+ // Creates an empty queue.
+ Queue() : head_(NULL), last_(NULL), size_(0) {}
+
+ // D'tor. Clears the queue.
+ ~Queue() { Clear(); }
+
+ // Clears the queue.
+ void Clear() {
+ if (size_ > 0) {
+ // 1. Deletes every node.
+ QueueNode<E>* node = head_;
+ QueueNode<E>* next = node->next();
+ for (; ;) {
+ delete node;
+ node = next;
+ if (node == NULL) break;
+ next = node->next();
+ }
+
+ // 2. Resets the member variables.
+ head_ = last_ = NULL;
+ size_ = 0;
+ }
+ }
+
+ // Gets the number of elements.
+ size_t Size() const { return size_; }
+
+ // Gets the first element of the queue, or NULL if the queue is empty.
+ QueueNode<E>* Head() { return head_; }
+ const QueueNode<E>* Head() const { return head_; }
+
+ // Gets the last element of the queue, or NULL if the queue is empty.
+ QueueNode<E>* Last() { return last_; }
+ const QueueNode<E>* Last() const { return last_; }
+
+ // Adds an element to the end of the queue. A copy of the element is
+ // created using the copy constructor, and then stored in the queue.
+ // Changes made to the element in the queue doesn't affect the source
+ // object, and vice versa.
+ void Enqueue(const E& element) {
+ QueueNode<E>* new_node = new QueueNode<E>(element);
+
+ if (size_ == 0) {
+ head_ = last_ = new_node;
+ size_ = 1;
+ } else {
+ last_->next_ = new_node;
+ last_ = new_node;
+ size_++;
+ }
+ }
+
+ // Removes the head of the queue and returns it. Returns NULL if
+ // the queue is empty.
+ E* Dequeue() {
+ if (size_ == 0) {
+ return NULL;
+ }
+
+ const QueueNode<E>* const old_head = head_;
+ head_ = head_->next_;
+ size_--;
+ if (size_ == 0) {
+ last_ = NULL;
+ }
+
+ E* element = new E(old_head->element());
+ delete old_head;
+
+ return element;
+ }
+
+ // Applies a function/functor on each element of the queue, and
+ // returns the result in a new queue. The original queue is not
+ // affected.
+ template <typename F>
+ Queue* Map(F function) const {
+ Queue* new_queue = new Queue();
+ for (const QueueNode<E>* node = head_; node != NULL; node = node->next_) {
+ new_queue->Enqueue(function(node->element()));
+ }
+
+ return new_queue;
+ }
+
+ private:
+ QueueNode<E>* head_; // The first node of the queue.
+ QueueNode<E>* last_; // The last node of the queue.
+ size_t size_; // The number of elements in the queue.
+
+ // We disallow copying a queue.
+ Queue(const Queue&);
+ const Queue& operator = (const Queue&);
+};
+
+#endif // GTEST_SAMPLES_SAMPLE3_INL_H_
diff --git a/external/gtest-1.6.0/samples/sample3_unittest.cc b/external/gtest-1.6.0/samples/sample3_unittest.cc
new file mode 100644
index 0000000..40b2f32
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample3_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+
+// In this example, we use a more advanced feature of Google Test called
+// test fixture.
+//
+// A test fixture is a place to hold objects and functions shared by
+// all tests in a test case. Using a test fixture avoids duplicating
+// the test code necessary to initialize and cleanup those common
+// objects for each test. It is also useful for defining sub-routines
+// that your tests need to invoke a lot.
+//
+// <TechnicalDetails>
+//
+// The tests share the test fixture in the sense of code sharing, not
+// data sharing. Each test is given its own fresh copy of the
+// fixture. You cannot expect the data modified by one test to be
+// passed on to another test, which is a bad idea.
+//
+// The reason for this design is that tests should be independent and
+// repeatable. In particular, a test should not fail as the result of
+// another test's failure. If one test depends on info produced by
+// another test, then the two tests should really be one big test.
+//
+// The macros for indicating the success/failure of a test
+// (EXPECT_TRUE, FAIL, etc) need to know what the current test is
+// (when Google Test prints the test result, it tells you which test
+// each failure belongs to). Technically, these macros invoke a
+// member function of the Test class. Therefore, you cannot use them
+// in a global function. That's why you should put test sub-routines
+// in a test fixture.
+//
+// </TechnicalDetails>
+
+#include "sample3-inl.h"
+#include "gtest/gtest.h"
+
+// To use a test fixture, derive a class from testing::Test.
+class QueueTest : public testing::Test
+{
+ protected: // You should make the members protected s.t. they can be
+ // accessed from sub-classes.
+
+ // virtual void SetUp() will be called before each test is run. You
+ // should define it if you need to initialize the varaibles.
+ // Otherwise, this can be skipped.
+ virtual void SetUp() {
+ q1_.Enqueue(1);
+ q2_.Enqueue(2);
+ q2_.Enqueue(3);
+ }
+
+ // virtual void TearDown() will be called after each test is run.
+ // You should define it if there is cleanup work to do. Otherwise,
+ // you don't have to provide it.
+ //
+ // virtual void TearDown() {
+ // }
+
+ // A helper function that some test uses.
+ static int Double(int n) {
+ return 2*n;
+ }
+
+ // A helper function for testing Queue::Map().
+ void MapTester(const Queue<int>* q) {
+ // Creates a new queue, where each element is twice as big as the
+ // corresponding one in q.
+ const Queue<int>* const new_q = q->Map(Double);
+
+ // Verifies that the new queue has the same size as q.
+ ASSERT_EQ(q->Size(), new_q->Size());
+
+ // Verifies the relationship between the elements of the two queues.
+ for (const QueueNode<int>* n1 = q->Head(), * n2 = new_q->Head();
+ n1 != NULL; n1 = n1->next(), n2 = n2->next()) {
+ EXPECT_EQ(2 * n1->element(), n2->element());
+ }
+
+ delete new_q;
+ }
+
+ // Declares the variables your tests want to use.
+ Queue<int> q0_;
+ Queue<int> q1_;
+ Queue<int> q2_;
+};
+
+// When you have a test fixture, you define a test using TEST_F
+// instead of TEST.
+
+// Tests the default c'tor.
+TEST_F(QueueTest, DefaultConstructor)
+{
+ // You can access data in the test fixture here.
+ EXPECT_EQ(0u, q0_.Size());
+}
+
+// Tests Dequeue().
+TEST_F(QueueTest, Dequeue)
+{
+ int* n = q0_.Dequeue();
+ EXPECT_TRUE(n == NULL);
+
+ n = q1_.Dequeue();
+ ASSERT_TRUE(n != NULL);
+ EXPECT_EQ(1, *n);
+ EXPECT_EQ(0u, q1_.Size());
+ delete n;
+
+ n = q2_.Dequeue();
+ ASSERT_TRUE(n != NULL);
+ EXPECT_EQ(2, *n);
+ EXPECT_EQ(1u, q2_.Size());
+ delete n;
+}
+
+// Tests the Queue::Map() function.
+TEST_F(QueueTest, Map)
+{
+ MapTester(&q0_);
+ MapTester(&q1_);
+ MapTester(&q2_);
+}
diff --git a/external/gtest-1.6.0/samples/sample4.cc b/external/gtest-1.6.0/samples/sample4.cc
new file mode 100644
index 0000000..5951d58
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample4.cc
@@ -0,0 +1,48 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include <stdio.h>
+
+#include "sample4.h"
+
+// Returns the current counter value, and increments it.
+int Counter::Increment()
+{
+ return counter_++;
+}
+
+// Prints the current counter value to STDOUT.
+void Counter::Print() const
+{
+ printf("%d", counter_);
+}
diff --git a/external/gtest-1.6.0/samples/sample4.h b/external/gtest-1.6.0/samples/sample4.h
new file mode 100644
index 0000000..156dcc7
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample4.h
@@ -0,0 +1,54 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE4_H_
+#define GTEST_SAMPLES_SAMPLE4_H_
+
+// A simple monotonic counter.
+class Counter
+{
+ private:
+ int counter_;
+
+ public:
+ // Creates a counter that starts at 0.
+ Counter() : counter_(0) {}
+
+ // Returns the current counter value, and increments it.
+ int Increment();
+
+ // Prints the current counter value to STDOUT.
+ void Print() const;
+};
+
+#endif // GTEST_SAMPLES_SAMPLE4_H_
diff --git a/external/gtest-1.6.0/samples/sample4_unittest.cc b/external/gtest-1.6.0/samples/sample4_unittest.cc
new file mode 100644
index 0000000..d827a7d
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample4_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest.h"
+#include "sample4.h"
+
+// Tests the Increment() method.
+TEST(Counter, Increment)
+{
+ Counter c;
+
+ // EXPECT_EQ() evaluates its arguments exactly once, so they
+ // can have side effects.
+
+ EXPECT_EQ(0, c.Increment());
+ EXPECT_EQ(1, c.Increment());
+ EXPECT_EQ(2, c.Increment());
+}
diff --git a/external/gtest-1.6.0/samples/sample5_unittest.cc b/external/gtest-1.6.0/samples/sample5_unittest.cc
new file mode 100644
index 0000000..faa986e
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample5_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// This sample teaches how to reuse a test fixture in multiple test
+// cases by deriving sub-fixtures from it.
+//
+// When you define a test fixture, you specify the name of the test
+// case that will use this fixture. Therefore, a test fixture can
+// be used by only one test case.
+//
+// Sometimes, more than one test cases may want to use the same or
+// slightly different test fixtures. For example, you may want to
+// make sure that all tests for a GUI library don't leak important
+// system resources like fonts and brushes. In Google Test, you do
+// this by putting the shared logic in a super (as in "super class")
+// test fixture, and then have each test case use a fixture derived
+// from this super fixture.
+
+#include <limits.h>
+#include <time.h>
+#include "sample3-inl.h"
+#include "gtest/gtest.h"
+#include "sample1.h"
+
+// In this sample, we want to ensure that every test finishes within
+// ~5 seconds. If a test takes longer to run, we consider it a
+// failure.
+//
+// We put the code for timing a test in a test fixture called
+// "QuickTest". QuickTest is intended to be the super fixture that
+// other fixtures derive from, therefore there is no test case with
+// the name "QuickTest". This is OK.
+//
+// Later, we will derive multiple test fixtures from QuickTest.
+class QuickTest : public testing::Test
+{
+ protected:
+ // Remember that SetUp() is run immediately before a test starts.
+ // This is a good place to record the start time.
+ virtual void SetUp() {
+ start_time_ = time(NULL);
+ }
+
+ // TearDown() is invoked immediately after a test finishes. Here we
+ // check if the test was too slow.
+ virtual void TearDown() {
+ // Gets the time when the test finishes
+ const time_t end_time = time(NULL);
+
+ // Asserts that the test took no more than ~5 seconds. Did you
+ // know that you can use assertions in SetUp() and TearDown() as
+ // well?
+ EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long.";
+ }
+
+ // The UTC time (in seconds) when the test starts
+ time_t start_time_;
+};
+
+
+// We derive a fixture named IntegerFunctionTest from the QuickTest
+// fixture. All tests using this fixture will be automatically
+// required to be quick.
+class IntegerFunctionTest : public QuickTest
+{
+ // We don't need any more logic than already in the QuickTest fixture.
+ // Therefore the body is empty.
+};
+
+
+// Now we can write tests in the IntegerFunctionTest test case.
+
+// Tests Factorial()
+TEST_F(IntegerFunctionTest, Factorial)
+{
+ // Tests factorial of negative numbers.
+ EXPECT_EQ(1, Factorial(-5));
+ EXPECT_EQ(1, Factorial(-1));
+ EXPECT_GT(Factorial(-10), 0);
+
+ // Tests factorial of 0.
+ EXPECT_EQ(1, Factorial(0));
+
+ // Tests factorial of positive numbers.
+ EXPECT_EQ(1, Factorial(1));
+ EXPECT_EQ(2, Factorial(2));
+ EXPECT_EQ(6, Factorial(3));
+ EXPECT_EQ(40320, Factorial(8));
+}
+
+
+// Tests IsPrime()
+TEST_F(IntegerFunctionTest, IsPrime)
+{
+ // Tests negative input.
+ EXPECT_FALSE(IsPrime(-1));
+ EXPECT_FALSE(IsPrime(-2));
+ EXPECT_FALSE(IsPrime(INT_MIN));
+
+ // Tests some trivial cases.
+ EXPECT_FALSE(IsPrime(0));
+ EXPECT_FALSE(IsPrime(1));
+ EXPECT_TRUE(IsPrime(2));
+ EXPECT_TRUE(IsPrime(3));
+
+ // Tests positive input.
+ EXPECT_FALSE(IsPrime(4));
+ EXPECT_TRUE(IsPrime(5));
+ EXPECT_FALSE(IsPrime(6));
+ EXPECT_TRUE(IsPrime(23));
+}
+
+
+// The next test case (named "QueueTest") also needs to be quick, so
+// we derive another fixture from QuickTest.
+//
+// The QueueTest test fixture has some logic and shared objects in
+// addition to what's in QuickTest already. We define the additional
+// stuff inside the body of the test fixture, as usual.
+class QueueTest : public QuickTest
+{
+ protected:
+ virtual void SetUp() {
+ // First, we need to set up the super fixture (QuickTest).
+ QuickTest::SetUp();
+
+ // Second, some additional setup for this fixture.
+ q1_.Enqueue(1);
+ q2_.Enqueue(2);
+ q2_.Enqueue(3);
+ }
+
+ // By default, TearDown() inherits the behavior of
+ // QuickTest::TearDown(). As we have no additional cleaning work
+ // for QueueTest, we omit it here.
+ //
+ // virtual void TearDown() {
+ // QuickTest::TearDown();
+ // }
+
+ Queue<int> q0_;
+ Queue<int> q1_;
+ Queue<int> q2_;
+};
+
+
+// Now, let's write tests using the QueueTest fixture.
+
+// Tests the default constructor.
+TEST_F(QueueTest, DefaultConstructor)
+{
+ EXPECT_EQ(0u, q0_.Size());
+}
+
+// Tests Dequeue().
+TEST_F(QueueTest, Dequeue)
+{
+ int* n = q0_.Dequeue();
+ EXPECT_TRUE(n == NULL);
+
+ n = q1_.Dequeue();
+ EXPECT_TRUE(n != NULL);
+ EXPECT_EQ(1, *n);
+ EXPECT_EQ(0u, q1_.Size());
+ delete n;
+
+ n = q2_.Dequeue();
+ EXPECT_TRUE(n != NULL);
+ EXPECT_EQ(2, *n);
+ EXPECT_EQ(1u, q2_.Size());
+ delete n;
+}
+
+// If necessary, you can derive further test fixtures from a derived
+// fixture itself. For example, you can derive another fixture from
+// QueueTest. Google Test imposes no limit on how deep the hierarchy
+// can be. In practice, however, you probably don't want it to be too
+// deep as to be confusing.
diff --git a/external/gtest-1.6.0/samples/sample6_unittest.cc b/external/gtest-1.6.0/samples/sample6_unittest.cc
new file mode 100644
index 0000000..5d0a569
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample6_unittest.cc
@@ -0,0 +1,234 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// This sample shows how to test common properties of multiple
+// implementations of the same interface (aka interface tests).
+
+// The interface and its implementations are in this header.
+#include "prime_tables.h"
+
+#include "gtest/gtest.h"
+
+// First, we define some factory functions for creating instances of
+// the implementations. You may be able to skip this step if all your
+// implementations can be constructed the same way.
+
+template <class T>
+PrimeTable* CreatePrimeTable();
+
+template <>
+PrimeTable* CreatePrimeTable<OnTheFlyPrimeTable>()
+{
+ return new OnTheFlyPrimeTable;
+}
+
+template <>
+PrimeTable* CreatePrimeTable<PreCalculatedPrimeTable>()
+{
+ return new PreCalculatedPrimeTable(10000);
+}
+
+// Then we define a test fixture class template.
+template <class T>
+class PrimeTableTest : public testing::Test
+{
+ protected:
+ // The ctor calls the factory function to create a prime table
+ // implemented by T.
+ PrimeTableTest() : table_(CreatePrimeTable<T>()) {}
+
+ virtual ~PrimeTableTest() { delete table_; }
+
+ // Note that we test an implementation via the base interface
+ // instead of the actual implementation class. This is important
+ // for keeping the tests close to the real world scenario, where the
+ // implementation is invoked via the base interface. It avoids
+ // got-yas where the implementation class has a method that shadows
+ // a method with the same name (but slightly different argument
+ // types) in the base interface, for example.
+ PrimeTable* const table_;
+};
+
+#if GTEST_HAS_TYPED_TEST
+
+using testing::Types;
+
+// Google Test offers two ways for reusing tests for different types.
+// The first is called "typed tests". You should use it if you
+// already know *all* the types you are gonna exercise when you write
+// the tests.
+
+// To write a typed test case, first use
+//
+// TYPED_TEST_CASE(TestCaseName, TypeList);
+//
+// to declare it and specify the type parameters. As with TEST_F,
+// TestCaseName must match the test fixture name.
+
+// The list of types we want to test.
+typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;
+
+TYPED_TEST_CASE(PrimeTableTest, Implementations);
+
+// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test,
+// similar to TEST_F.
+TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes)
+{
+ // Inside the test body, you can refer to the type parameter by
+ // TypeParam, and refer to the fixture class by TestFixture. We
+ // don't need them in this example.
+
+ // Since we are in the template world, C++ requires explicitly
+ // writing 'this->' when referring to members of the fixture class.
+ // This is something you have to learn to live with.
+ EXPECT_FALSE(this->table_->IsPrime(-5));
+ EXPECT_FALSE(this->table_->IsPrime(0));
+ EXPECT_FALSE(this->table_->IsPrime(1));
+ EXPECT_FALSE(this->table_->IsPrime(4));
+ EXPECT_FALSE(this->table_->IsPrime(6));
+ EXPECT_FALSE(this->table_->IsPrime(100));
+}
+
+TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes)
+{
+ EXPECT_TRUE(this->table_->IsPrime(2));
+ EXPECT_TRUE(this->table_->IsPrime(3));
+ EXPECT_TRUE(this->table_->IsPrime(5));
+ EXPECT_TRUE(this->table_->IsPrime(7));
+ EXPECT_TRUE(this->table_->IsPrime(11));
+ EXPECT_TRUE(this->table_->IsPrime(131));
+}
+
+TYPED_TEST(PrimeTableTest, CanGetNextPrime)
+{
+ EXPECT_EQ(2, this->table_->GetNextPrime(0));
+ EXPECT_EQ(3, this->table_->GetNextPrime(2));
+ EXPECT_EQ(5, this->table_->GetNextPrime(3));
+ EXPECT_EQ(7, this->table_->GetNextPrime(5));
+ EXPECT_EQ(11, this->table_->GetNextPrime(7));
+ EXPECT_EQ(131, this->table_->GetNextPrime(128));
+}
+
+// That's it! Google Test will repeat each TYPED_TEST for each type
+// in the type list specified in TYPED_TEST_CASE. Sit back and be
+// happy that you don't have to define them multiple times.
+
+#endif // GTEST_HAS_TYPED_TEST
+
+#if GTEST_HAS_TYPED_TEST_P
+
+using testing::Types;
+
+// Sometimes, however, you don't yet know all the types that you want
+// to test when you write the tests. For example, if you are the
+// author of an interface and expect other people to implement it, you
+// might want to write a set of tests to make sure each implementation
+// conforms to some basic requirements, but you don't know what
+// implementations will be written in the future.
+//
+// How can you write the tests without committing to the type
+// parameters? That's what "type-parameterized tests" can do for you.
+// It is a bit more involved than typed tests, but in return you get a
+// test pattern that can be reused in many contexts, which is a big
+// win. Here's how you do it:
+
+// First, define a test fixture class template. Here we just reuse
+// the PrimeTableTest fixture defined earlier:
+
+template <class T>
+class PrimeTableTest2 : public PrimeTableTest<T>
+{
+};
+
+// Then, declare the test case. The argument is the name of the test
+// fixture, and also the name of the test case (as usual). The _P
+// suffix is for "parameterized" or "pattern".
+TYPED_TEST_CASE_P(PrimeTableTest2);
+
+// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test,
+// similar to what you do with TEST_F.
+TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes)
+{
+ EXPECT_FALSE(this->table_->IsPrime(-5));
+ EXPECT_FALSE(this->table_->IsPrime(0));
+ EXPECT_FALSE(this->table_->IsPrime(1));
+ EXPECT_FALSE(this->table_->IsPrime(4));
+ EXPECT_FALSE(this->table_->IsPrime(6));
+ EXPECT_FALSE(this->table_->IsPrime(100));
+}
+
+TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes)
+{
+ EXPECT_TRUE(this->table_->IsPrime(2));
+ EXPECT_TRUE(this->table_->IsPrime(3));
+ EXPECT_TRUE(this->table_->IsPrime(5));
+ EXPECT_TRUE(this->table_->IsPrime(7));
+ EXPECT_TRUE(this->table_->IsPrime(11));
+ EXPECT_TRUE(this->table_->IsPrime(131));
+}
+
+TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime)
+{
+ EXPECT_EQ(2, this->table_->GetNextPrime(0));
+ EXPECT_EQ(3, this->table_->GetNextPrime(2));
+ EXPECT_EQ(5, this->table_->GetNextPrime(3));
+ EXPECT_EQ(7, this->table_->GetNextPrime(5));
+ EXPECT_EQ(11, this->table_->GetNextPrime(7));
+ EXPECT_EQ(131, this->table_->GetNextPrime(128));
+}
+
+// Type-parameterized tests involve one extra step: you have to
+// enumerate the tests you defined:
+REGISTER_TYPED_TEST_CASE_P(
+ PrimeTableTest2, // The first argument is the test case name.
+ // The rest of the arguments are the test names.
+ ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime);
+
+// At this point the test pattern is done. However, you don't have
+// any real test yet as you haven't said which types you want to run
+// the tests with.
+
+// To turn the abstract test pattern into real tests, you instantiate
+// it with a list of types. Usually the test pattern will be defined
+// in a .h file, and anyone can #include and instantiate it. You can
+// even instantiate it more than once in the same program. To tell
+// different instances apart, you give each of them a name, which will
+// become part of the test case name and can be used in test filters.
+
+// The list of types we want to test. Note that it doesn't have to be
+// defined at the time we write the TYPED_TEST_P()s.
+typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable>
+PrimeTableImplementations;
+INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name
+ PrimeTableTest2, // Test case name
+ PrimeTableImplementations); // Type list
+
+#endif // GTEST_HAS_TYPED_TEST_P
diff --git a/external/gtest-1.6.0/samples/sample7_unittest.cc b/external/gtest-1.6.0/samples/sample7_unittest.cc
new file mode 100644
index 0000000..b14a80d
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample7_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// This sample shows how to test common properties of multiple
+// implementations of an interface (aka interface tests) using
+// value-parameterized tests. Each test in the test case has
+// a parameter that is an interface pointer to an implementation
+// tested.
+
+// The interface and its implementations are in this header.
+#include "prime_tables.h"
+
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+// As a general rule, to prevent a test from affecting the tests that come
+// after it, you should create and destroy the tested objects for each test
+// instead of reusing them. In this sample we will define a simple factory
+// function for PrimeTable objects. We will instantiate objects in test's
+// SetUp() method and delete them in TearDown() method.
+typedef PrimeTable* CreatePrimeTableFunc();
+
+PrimeTable* CreateOnTheFlyPrimeTable()
+{
+ return new OnTheFlyPrimeTable();
+}
+
+template <size_t max_precalculated>
+PrimeTable* CreatePreCalculatedPrimeTable()
+{
+ return new PreCalculatedPrimeTable(max_precalculated);
+}
+
+// Inside the test body, fixture constructor, SetUp(), and TearDown() you
+// can refer to the test parameter by GetParam(). In this case, the test
+// parameter is a factory function which we call in fixture's SetUp() to
+// create and store an instance of PrimeTable.
+class PrimeTableTest : public TestWithParam<CreatePrimeTableFunc*>
+{
+ public:
+ virtual ~PrimeTableTest() { delete table_; }
+ virtual void SetUp() { table_ = (*GetParam())(); }
+ virtual void TearDown() {
+ delete table_;
+ table_ = NULL;
+ }
+
+ protected:
+ PrimeTable* table_;
+};
+
+TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes)
+{
+ EXPECT_FALSE(table_->IsPrime(-5));
+ EXPECT_FALSE(table_->IsPrime(0));
+ EXPECT_FALSE(table_->IsPrime(1));
+ EXPECT_FALSE(table_->IsPrime(4));
+ EXPECT_FALSE(table_->IsPrime(6));
+ EXPECT_FALSE(table_->IsPrime(100));
+}
+
+TEST_P(PrimeTableTest, ReturnsTrueForPrimes)
+{
+ EXPECT_TRUE(table_->IsPrime(2));
+ EXPECT_TRUE(table_->IsPrime(3));
+ EXPECT_TRUE(table_->IsPrime(5));
+ EXPECT_TRUE(table_->IsPrime(7));
+ EXPECT_TRUE(table_->IsPrime(11));
+ EXPECT_TRUE(table_->IsPrime(131));
+}
+
+TEST_P(PrimeTableTest, CanGetNextPrime)
+{
+ EXPECT_EQ(2, table_->GetNextPrime(0));
+ EXPECT_EQ(3, table_->GetNextPrime(2));
+ EXPECT_EQ(5, table_->GetNextPrime(3));
+ EXPECT_EQ(7, table_->GetNextPrime(5));
+ EXPECT_EQ(11, table_->GetNextPrime(7));
+ EXPECT_EQ(131, table_->GetNextPrime(128));
+}
+
+// In order to run value-parameterized tests, you need to instantiate them,
+// or bind them to a list of values which will be used as test parameters.
+// You can instantiate them in a different translation module, or even
+// instantiate them several times.
+//
+// Here, we instantiate our tests with a list of two PrimeTable object
+// factory functions:
+INSTANTIATE_TEST_CASE_P(
+ OnTheFlyAndPreCalculated,
+ PrimeTableTest,
+ Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>));
+
+#else
+
+// Google Test may not support value-parameterized tests with some
+// compilers. If we use conditional compilation to compile out all
+// code referring to the gtest_main library, MSVC linker will not link
+// that library at all and consequently complain about missing entry
+// point defined in that library (fatal error LNK1561: entry point
+// must be defined). This dummy test keeps gtest_main linked in.
+TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif // GTEST_HAS_PARAM_TEST
diff --git a/external/gtest-1.6.0/samples/sample8_unittest.cc b/external/gtest-1.6.0/samples/sample8_unittest.cc
new file mode 100644
index 0000000..8ac1b6f
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample8_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// This sample shows how to test code relying on some global flag variables.
+// Combine() helps with generating all possible combinations of such flags,
+// and each test is given one combination as a parameter.
+
+// Use class definitions to test from this header.
+#include "prime_tables.h"
+
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_COMBINE
+
+// Suppose we want to introduce a new, improved implementation of PrimeTable
+// which combines speed of PrecalcPrimeTable and versatility of
+// OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both
+// PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more
+// appropriate under the circumstances. But in low memory conditions, it can be
+// told to instantiate without PrecalcPrimeTable instance at all and use only
+// OnTheFlyPrimeTable.
+class HybridPrimeTable : public PrimeTable
+{
+ public:
+ HybridPrimeTable(bool force_on_the_fly, int max_precalculated)
+ : on_the_fly_impl_(new OnTheFlyPrimeTable),
+ precalc_impl_(force_on_the_fly ? NULL :
+ new PreCalculatedPrimeTable(max_precalculated)),
+ max_precalculated_(max_precalculated) {}
+ virtual ~HybridPrimeTable() {
+ delete on_the_fly_impl_;
+ delete precalc_impl_;
+ }
+
+ virtual bool IsPrime(int n) const {
+ if (precalc_impl_ != NULL && n < max_precalculated_)
+ return precalc_impl_->IsPrime(n);
+ else
+ return on_the_fly_impl_->IsPrime(n);
+ }
+
+ virtual int GetNextPrime(int p) const {
+ int next_prime = -1;
+ if (precalc_impl_ != NULL && p < max_precalculated_)
+ next_prime = precalc_impl_->GetNextPrime(p);
+
+ return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p);
+ }
+
+ private:
+ OnTheFlyPrimeTable* on_the_fly_impl_;
+ PreCalculatedPrimeTable* precalc_impl_;
+ int max_precalculated_;
+};
+
+using ::testing::TestWithParam;
+using ::testing::Bool;
+using ::testing::Values;
+using ::testing::Combine;
+
+// To test all code paths for HybridPrimeTable we must test it with numbers
+// both within and outside PreCalculatedPrimeTable's capacity and also with
+// PreCalculatedPrimeTable disabled. We do this by defining fixture which will
+// accept different combinations of parameters for instantiating a
+// HybridPrimeTable instance.
+class PrimeTableTest : public TestWithParam< ::std::tr1::tuple<bool, int> >
+{
+ protected:
+ virtual void SetUp() {
+ // This can be written as
+ //
+ // bool force_on_the_fly;
+ // int max_precalculated;
+ // tie(force_on_the_fly, max_precalculated) = GetParam();
+ //
+ // once the Google C++ Style Guide allows use of ::std::tr1::tie.
+ //
+ bool force_on_the_fly = ::std::tr1::get<0>(GetParam());
+ int max_precalculated = ::std::tr1::get<1>(GetParam());
+ table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated);
+ }
+ virtual void TearDown() {
+ delete table_;
+ table_ = NULL;
+ }
+ HybridPrimeTable* table_;
+};
+
+TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes)
+{
+ // Inside the test body, you can refer to the test parameter by GetParam().
+ // In this case, the test parameter is a PrimeTable interface pointer which
+ // we can use directly.
+ // Please note that you can also save it in the fixture's SetUp() method
+ // or constructor and use saved copy in the tests.
+
+ EXPECT_FALSE(table_->IsPrime(-5));
+ EXPECT_FALSE(table_->IsPrime(0));
+ EXPECT_FALSE(table_->IsPrime(1));
+ EXPECT_FALSE(table_->IsPrime(4));
+ EXPECT_FALSE(table_->IsPrime(6));
+ EXPECT_FALSE(table_->IsPrime(100));
+}
+
+TEST_P(PrimeTableTest, ReturnsTrueForPrimes)
+{
+ EXPECT_TRUE(table_->IsPrime(2));
+ EXPECT_TRUE(table_->IsPrime(3));
+ EXPECT_TRUE(table_->IsPrime(5));
+ EXPECT_TRUE(table_->IsPrime(7));
+ EXPECT_TRUE(table_->IsPrime(11));
+ EXPECT_TRUE(table_->IsPrime(131));
+}
+
+TEST_P(PrimeTableTest, CanGetNextPrime)
+{
+ EXPECT_EQ(2, table_->GetNextPrime(0));
+ EXPECT_EQ(3, table_->GetNextPrime(2));
+ EXPECT_EQ(5, table_->GetNextPrime(3));
+ EXPECT_EQ(7, table_->GetNextPrime(5));
+ EXPECT_EQ(11, table_->GetNextPrime(7));
+ EXPECT_EQ(131, table_->GetNextPrime(128));
+}
+
+// In order to run value-parameterized tests, you need to instantiate them,
+// or bind them to a list of values which will be used as test parameters.
+// You can instantiate them in a different translation module, or even
+// instantiate them several times.
+//
+// Here, we instantiate our tests with a list of parameters. We must combine
+// all variations of the boolean flag suppressing PrecalcPrimeTable and some
+// meaningful values for tests. We choose a small value (1), and a value that
+// will put some of the tested numbers beyond the capability of the
+// PrecalcPrimeTable instance and some inside it (10). Combine will produce all
+// possible combinations.
+INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters,
+ PrimeTableTest,
+ Combine(Bool(), Values(1, 10)));
+
+#else
+
+// Google Test may not support Combine() with some compilers. If we
+// use conditional compilation to compile out all code referring to
+// the gtest_main library, MSVC linker will not link that library at
+// all and consequently complain about missing entry point defined in
+// that library (fatal error LNK1561: entry point must be
+// defined). This dummy test keeps gtest_main linked in.
+TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {}
+
+#endif // GTEST_HAS_COMBINE
diff --git a/external/gtest-1.6.0/samples/sample9_unittest.cc b/external/gtest-1.6.0/samples/sample9_unittest.cc
new file mode 100644
index 0000000..0c9a2d9
--- /dev/null
+++ b/external/gtest-1.6.0/samples/sample9_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+
+// This sample shows how to use Google Test listener API to implement
+// an alternative console output and how to use the UnitTest reflection API
+// to enumerate test cases and tests and to inspect their results.
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+
+using ::testing::EmptyTestEventListener;
+using ::testing::InitGoogleTest;
+using ::testing::Test;
+using ::testing::TestCase;
+using ::testing::TestEventListeners;
+using ::testing::TestInfo;
+using ::testing::TestPartResult;
+using ::testing::UnitTest;
+
+namespace
+{
+
+// Provides alternative output mode which produces minimal amount of
+// information about tests.
+class TersePrinter : public EmptyTestEventListener
+{
+ private:
+ // Called before any test activity starts.
+ virtual void OnTestProgramStart(const UnitTest& /* unit_test */) {}
+
+ // Called after all test activities have ended.
+ virtual void OnTestProgramEnd(const UnitTest& unit_test) {
+ fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED");
+ fflush(stdout);
+ }
+
+ // Called before a test starts.
+ virtual void OnTestStart(const TestInfo& test_info) {
+ fprintf(stdout,
+ "*** Test %s.%s starting.\n",
+ test_info.test_case_name(),
+ test_info.name());
+ fflush(stdout);
+ }
+
+ // Called after a failed assertion or a SUCCEED() invocation.
+ virtual void OnTestPartResult(const TestPartResult& test_part_result) {
+ fprintf(stdout,
+ "%s in %s:%d\n%s\n",
+ test_part_result.failed() ? "*** Failure" : "Success",
+ test_part_result.file_name(),
+ test_part_result.line_number(),
+ test_part_result.summary());
+ fflush(stdout);
+ }
+
+ // Called after a test ends.
+ virtual void OnTestEnd(const TestInfo& test_info) {
+ fprintf(stdout,
+ "*** Test %s.%s ending.\n",
+ test_info.test_case_name(),
+ test_info.name());
+ fflush(stdout);
+ }
+}; // class TersePrinter
+
+TEST(CustomOutputTest, PrintsMessage)
+{
+ printf("Printing something from the test body...\n");
+}
+
+TEST(CustomOutputTest, Succeeds)
+{
+ SUCCEED() << "SUCCEED() has been invoked from here";
+}
+
+TEST(CustomOutputTest, Fails)
+{
+ EXPECT_EQ(1, 2)
+ << "This test fails in order to demonstrate alternative failure messages";
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ InitGoogleTest(&argc, argv);
+
+ bool terse_output = false;
+ if (argc > 1 && strcmp(argv[1], "--terse_output") == 0)
+ terse_output = true;
+ else
+ printf("%s\n", "Run this program with --terse_output to change the way "
+ "it prints its output.");
+
+ UnitTest& unit_test = *UnitTest::GetInstance();
+
+ // If we are given the --terse_output command line flag, suppresses the
+ // standard output and attaches own result printer.
+ if (terse_output) {
+ TestEventListeners& listeners = unit_test.listeners();
+
+ // Removes the default console output listener from the list so it will
+ // not receive events from Google Test and won't print any output. Since
+ // this operation transfers ownership of the listener to the caller we
+ // have to delete it as well.
+ delete listeners.Release(listeners.default_result_printer());
+
+ // Adds the custom output listener to the list. It will now receive
+ // events from Google Test and print the alternative output. We don't
+ // have to worry about deleting it since Google Test assumes ownership
+ // over it after adding it to the list.
+ listeners.Append(new TersePrinter);
+ }
+ int ret_val = RUN_ALL_TESTS();
+
+ // This is an example of using the UnitTest reflection API to inspect test
+ // results. Here we discount failures from the tests we expected to fail.
+ int unexpectedly_failed_tests = 0;
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase& test_case = *unit_test.GetTestCase(i);
+ for (int j = 0; j < test_case.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_case.GetTestInfo(j);
+ // Counts failed tests that were not meant to fail (those without
+ // 'Fails' in the name).
+ if (test_info.result()->Failed() &&
+ strcmp(test_info.name(), "Fails") != 0) {
+ unexpectedly_failed_tests++;
+ }
+ }
+ }
+
+ // Test that were meant to fail should not affect the test program outcome.
+ if (unexpectedly_failed_tests == 0)
+ ret_val = 0;
+
+ return ret_val;
+}
diff --git a/external/gtest-1.6.0/scripts/fuse_gtest_files.py b/external/gtest-1.6.0/scripts/fuse_gtest_files.py
new file mode 100755
index 0000000..57ef72f
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/fuse_gtest_files.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""fuse_gtest_files.py v0.2.0
+Fuses Google Test source code into a .h file and a .cc file.
+
+SYNOPSIS
+ fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR
+
+ Scans GTEST_ROOT_DIR for Google Test source code, and generates
+ two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc.
+ Then you can build your tests by adding OUTPUT_DIR to the include
+ search path and linking with OUTPUT_DIR/gtest/gtest-all.cc. These
+ two files contain everything you need to use Google Test. Hence
+ you can "install" Google Test by copying them to wherever you want.
+
+ GTEST_ROOT_DIR can be omitted and defaults to the parent
+ directory of the directory holding this script.
+
+EXAMPLES
+ ./fuse_gtest_files.py fused_gtest
+ ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest
+
+This tool is experimental. In particular, it assumes that there is no
+conditional inclusion of Google Test headers. Please report any
+problems to googletestframework at googlegroups.com. You can read
+http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for
+more information.
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import re
+import sets
+import sys
+
+# We assume that this file is in the scripts/ directory in the Google
+# Test root directory.
+DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..')
+
+# Regex for matching '#include "gtest/..."'.
+INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gtest/.+)"')
+
+# Regex for matching '#include "src/..."'.
+INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"')
+
+# Where to find the source seed files.
+GTEST_H_SEED = 'include/gtest/gtest.h'
+GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h'
+GTEST_ALL_CC_SEED = 'src/gtest-all.cc'
+
+# Where to put the generated files.
+GTEST_H_OUTPUT = 'gtest/gtest.h'
+GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc'
+
+
+def VerifyFileExists(directory, relative_path):
+ """Verifies that the given file exists; aborts on failure.
+
+ relative_path is the file path relative to the given directory.
+ """
+
+ if not os.path.isfile(os.path.join(directory, relative_path)):
+ print 'ERROR: Cannot find %s in directory %s.' % (relative_path,
+ directory)
+ print ('Please either specify a valid project root directory '
+ 'or omit it on the command line.')
+ sys.exit(1)
+
+
+def ValidateGTestRootDir(gtest_root):
+ """Makes sure gtest_root points to a valid gtest root directory.
+
+ The function aborts the program on failure.
+ """
+
+ VerifyFileExists(gtest_root, GTEST_H_SEED)
+ VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED)
+
+
+def VerifyOutputFile(output_dir, relative_path):
+ """Verifies that the given output file path is valid.
+
+ relative_path is relative to the output_dir directory.
+ """
+
+ # Makes sure the output file either doesn't exist or can be overwritten.
+ output_file = os.path.join(output_dir, relative_path)
+ if os.path.exists(output_file):
+ # TODO(wan at google.com): The following user-interaction doesn't
+ # work with automated processes. We should provide a way for the
+ # Makefile to force overwriting the files.
+ print ('%s already exists in directory %s - overwrite it? (y/N) ' %
+ (relative_path, output_dir))
+ answer = sys.stdin.readline().strip()
+ if answer not in ['y', 'Y']:
+ print 'ABORTED.'
+ sys.exit(1)
+
+ # Makes sure the directory holding the output file exists; creates
+ # it and all its ancestors if necessary.
+ parent_directory = os.path.dirname(output_file)
+ if not os.path.isdir(parent_directory):
+ os.makedirs(parent_directory)
+
+
+def ValidateOutputDir(output_dir):
+ """Makes sure output_dir points to a valid output directory.
+
+ The function aborts the program on failure.
+ """
+
+ VerifyOutputFile(output_dir, GTEST_H_OUTPUT)
+ VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT)
+
+
+def FuseGTestH(gtest_root, output_dir):
+ """Scans folder gtest_root to generate gtest/gtest.h in output_dir."""
+
+ output_file = file(os.path.join(output_dir, GTEST_H_OUTPUT), 'w')
+ processed_files = sets.Set() # Holds all gtest headers we've processed.
+
+ def ProcessFile(gtest_header_path):
+ """Processes the given gtest header file."""
+
+ # We don't process the same header twice.
+ if gtest_header_path in processed_files:
+ return
+
+ processed_files.add(gtest_header_path)
+
+ # Reads each line in the given gtest header.
+ for line in file(os.path.join(gtest_root, gtest_header_path), 'r'):
+ m = INCLUDE_GTEST_FILE_REGEX.match(line)
+ if m:
+ # It's '#include "gtest/..."' - let's process it recursively.
+ ProcessFile('include/' + m.group(1))
+ else:
+ # Otherwise we copy the line unchanged to the output file.
+ output_file.write(line)
+
+ ProcessFile(GTEST_H_SEED)
+ output_file.close()
+
+
+def FuseGTestAllCcToFile(gtest_root, output_file):
+ """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file."""
+
+ processed_files = sets.Set()
+
+ def ProcessFile(gtest_source_file):
+ """Processes the given gtest source file."""
+
+ # We don't process the same #included file twice.
+ if gtest_source_file in processed_files:
+ return
+
+ processed_files.add(gtest_source_file)
+
+ # Reads each line in the given gtest source file.
+ for line in file(os.path.join(gtest_root, gtest_source_file), 'r'):
+ m = INCLUDE_GTEST_FILE_REGEX.match(line)
+ if m:
+ if 'include/' + m.group(1) == GTEST_SPI_H_SEED:
+ # It's '#include "gtest/gtest-spi.h"'. This file is not
+ # #included by "gtest/gtest.h", so we need to process it.
+ ProcessFile(GTEST_SPI_H_SEED)
+ else:
+ # It's '#include "gtest/foo.h"' where foo is not gtest-spi.
+ # We treat it as '#include "gtest/gtest.h"', as all other
+ # gtest headers are being fused into gtest.h and cannot be
+ # #included directly.
+
+ # There is no need to #include "gtest/gtest.h" more than once.
+ if not GTEST_H_SEED in processed_files:
+ processed_files.add(GTEST_H_SEED)
+ output_file.write('#include "%s"\n' % (GTEST_H_OUTPUT,))
+ else:
+ m = INCLUDE_SRC_FILE_REGEX.match(line)
+ if m:
+ # It's '#include "src/foo"' - let's process it recursively.
+ ProcessFile(m.group(1))
+ else:
+ output_file.write(line)
+
+ ProcessFile(GTEST_ALL_CC_SEED)
+
+
+def FuseGTestAllCc(gtest_root, output_dir):
+ """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir."""
+
+ output_file = file(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w')
+ FuseGTestAllCcToFile(gtest_root, output_file)
+ output_file.close()
+
+
+def FuseGTest(gtest_root, output_dir):
+ """Fuses gtest.h and gtest-all.cc."""
+
+ ValidateGTestRootDir(gtest_root)
+ ValidateOutputDir(output_dir)
+
+ FuseGTestH(gtest_root, output_dir)
+ FuseGTestAllCc(gtest_root, output_dir)
+
+
+def main():
+ argc = len(sys.argv)
+ if argc == 2:
+ # fuse_gtest_files.py OUTPUT_DIR
+ FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1])
+ elif argc == 3:
+ # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR
+ FuseGTest(sys.argv[1], sys.argv[2])
+ else:
+ print __doc__
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/external/gtest-1.6.0/scripts/gen_gtest_pred_impl.py b/external/gtest-1.6.0/scripts/gen_gtest_pred_impl.py
new file mode 100755
index 0000000..3e7ab04
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/gen_gtest_pred_impl.py
@@ -0,0 +1,730 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""gen_gtest_pred_impl.py v0.1
+
+Generates the implementation of Google Test predicate assertions and
+accompanying tests.
+
+Usage:
+
+ gen_gtest_pred_impl.py MAX_ARITY
+
+where MAX_ARITY is a positive integer.
+
+The command generates the implementation of up-to MAX_ARITY-ary
+predicate assertions, and writes it to file gtest_pred_impl.h in the
+directory where the script is. It also generates the accompanying
+unit test in file gtest_pred_impl_unittest.cc.
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import sys
+import time
+
+# Where this script is.
+SCRIPT_DIR = os.path.dirname(sys.argv[0])
+
+# Where to store the generated header.
+HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h')
+
+# Where to store the generated unit test.
+UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc')
+
+
+def HeaderPreamble(n):
+ """Returns the preamble for the header file.
+
+ Args:
+ n: the maximum arity of the predicate macros to be generated.
+ """
+
+ # A map that defines the values used in the preamble template.
+ DEFS = {
+ 'today' : time.strftime('%m/%d/%Y'),
+ 'year' : time.strftime('%Y'),
+ 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n),
+ 'n' : n
+ }
+
+ return (
+"""// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on %(today)s by command
+// '%(command)s'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most %(n)s.
+// Please email googletestframework at googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \\
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \\
+ ; \\
+ else \\
+ on_failure(gtest_ar.failure_message())
+""" % DEFS)
+
+
+def Arity(n):
+ """Returns the English name of the given arity."""
+
+ if n < 0:
+ return None
+ elif n <= 3:
+ return ['nullary', 'unary', 'binary', 'ternary'][n]
+ else:
+ return '%s-ary' % n
+
+
+def Title(word):
+ """Returns the given word in title case. The difference between
+ this and string's title() method is that Title('4-ary') is '4-ary'
+ while '4-ary'.title() is '4-Ary'."""
+
+ return word[0].upper() + word[1:]
+
+
+def OneTo(n):
+ """Returns the list [1, 2, 3, ..., n]."""
+
+ return range(1, n + 1)
+
+
+def Iter(n, format, sep=''):
+ """Given a positive integer n, a format string that contains 0 or
+ more '%s' format specs, and optionally a separator string, returns
+ the join of n strings, each formatted with the format string on an
+ iterator ranged from 1 to n.
+
+ Example:
+
+ Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'.
+ """
+
+ # How many '%s' specs are in format?
+ spec_count = len(format.split('%s')) - 1
+ return sep.join([format % (spec_count * (i,)) for i in OneTo(n)])
+
+
+def ImplementationForArity(n):
+ """Returns the implementation of n-ary predicate assertions."""
+
+ # A map the defines the values used in the implementation template.
+ DEFS = {
+ 'n' : str(n),
+ 'vs' : Iter(n, 'v%s', sep=', '),
+ 'vts' : Iter(n, '#v%s', sep=', '),
+ 'arity' : Arity(n),
+ 'Arity' : Title(Arity(n))
+ }
+
+ impl = """
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use
+// this in your code.
+template <typename Pred""" % DEFS
+
+ impl += Iter(n, """,
+ typename T%s""")
+
+ impl += """>
+AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS
+
+ impl += Iter(n, """,
+ const char* e%s""")
+
+ impl += """,
+ Pred pred"""
+
+ impl += Iter(n, """,
+ const T%s& v%s""")
+
+ impl += """) {
+ if (pred(%(vs)s)) return AssertionSuccess();
+
+""" % DEFS
+
+ impl += ' return AssertionFailure() << pred_text << "("'
+
+ impl += Iter(n, """
+ << e%s""", sep=' << ", "')
+
+ impl += ' << ") evaluates to false, where"'
+
+ impl += Iter(n, """
+ << "\\n" << e%s << " evaluates to " << v%s""")
+
+ impl += """;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, on_failure)\\
+ GTEST_ASSERT_(pred_format(%(vts)s, %(vs)s), \\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use
+// this in your code.
+#define GTEST_PRED%(n)s_(pred, %(vs)s, on_failure)\\
+ GTEST_ASSERT_(::testing::AssertPred%(n)sHelper(#pred""" % DEFS
+
+ impl += Iter(n, """, \\
+ #v%s""")
+
+ impl += """, \\
+ pred"""
+
+ impl += Iter(n, """, \\
+ v%s""")
+
+ impl += """), on_failure)
+
+// %(Arity)s predicate assertion macros.
+#define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\
+ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED%(n)s(pred, %(vs)s) \\
+ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\
+ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED%(n)s(pred, %(vs)s) \\
+ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_FATAL_FAILURE_)
+
+""" % DEFS
+
+ return impl
+
+
+def HeaderPostamble():
+ """Returns the postamble for the header file."""
+
+ return """
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+"""
+
+
+def GenerateFile(path, content):
+ """Given a file path and a content string, overwrites it with the
+ given content."""
+
+ print 'Updating file %s . . .' % path
+
+ f = file(path, 'w+')
+ print >>f, content,
+ f.close()
+
+ print 'File %s has been updated.' % path
+
+
+def GenerateHeader(n):
+ """Given the maximum arity n, updates the header file that implements
+ the predicate assertions."""
+
+ GenerateFile(HEADER,
+ HeaderPreamble(n)
+ + ''.join([ImplementationForArity(i) for i in OneTo(n)])
+ + HeaderPostamble())
+
+
+def UnitTestPreamble():
+ """Returns the preamble for the unit test file."""
+
+ # A map that defines the values used in the preamble template.
+ DEFS = {
+ 'today' : time.strftime('%m/%d/%Y'),
+ 'year' : time.strftime('%Y'),
+ 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]),
+ }
+
+ return (
+"""// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on %(today)s by command
+// '%(command)s'. DO NOT EDIT BY HAND!
+
+// Regression test for gtest_pred_impl.h
+//
+// This file is generated by a script and quite long. If you intend to
+// learn how Google Test works by reading its unit tests, read
+// gtest_unittest.cc instead.
+//
+// This is intended as a regression test for the Google Test predicate
+// assertions. We compile it as part of the gtest_unittest target
+// only to keep the implementation tidy and compact, as it is quite
+// involved to set up the stage for testing Google Test using Google
+// Test itself.
+//
+// Currently, gtest_unittest takes ~11 seconds to run in the testing
+// daemon. In the future, if it grows too large and needs much more
+// time to finish, we should consider separating this file into a
+// stand-alone regression test.
+
+#include <iostream>
+
+#include "gtest/gtest.h"
+#include "gtest/gtest-spi.h"
+
+// A user-defined data type.
+struct Bool {
+ explicit Bool(int val) : value(val != 0) {}
+
+ bool operator>(int n) const { return value > Bool(n).value; }
+
+ Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); }
+
+ bool operator==(const Bool& rhs) const { return value == rhs.value; }
+
+ bool value;
+};
+
+// Enables Bool to be used in assertions.
+std::ostream& operator<<(std::ostream& os, const Bool& x) {
+ return os << (x.value ? "true" : "false");
+}
+
+""" % DEFS)
+
+
+def TestsForArity(n):
+ """Returns the tests for n-ary predicate assertions."""
+
+ # A map that defines the values used in the template for the tests.
+ DEFS = {
+ 'n' : n,
+ 'es' : Iter(n, 'e%s', sep=', '),
+ 'vs' : Iter(n, 'v%s', sep=', '),
+ 'vts' : Iter(n, '#v%s', sep=', '),
+ 'tvs' : Iter(n, 'T%s v%s', sep=', '),
+ 'int_vs' : Iter(n, 'int v%s', sep=', '),
+ 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '),
+ 'types' : Iter(n, 'typename T%s', sep=', '),
+ 'v_sum' : Iter(n, 'v%s', sep=' + '),
+ 'arity' : Arity(n),
+ 'Arity' : Title(Arity(n)),
+ }
+
+ tests = (
+"""// Sample functions/functors for testing %(arity)s predicate assertions.
+
+// A %(arity)s predicate function.
+template <%(types)s>
+bool PredFunction%(n)s(%(tvs)s) {
+ return %(v_sum)s > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction%(n)sInt(%(int_vs)s) {
+ return %(v_sum)s > 0;
+}
+bool PredFunction%(n)sBool(%(Bool_vs)s) {
+ return %(v_sum)s > 0;
+}
+""" % DEFS)
+
+ tests += """
+// A %(arity)s predicate functor.
+struct PredFunctor%(n)s {
+ template <%(types)s>
+ bool operator()(""" % DEFS
+
+ tests += Iter(n, 'const T%s& v%s', sep=""",
+ """)
+
+ tests += """) {
+ return %(v_sum)s > 0;
+ }
+};
+""" % DEFS
+
+ tests += """
+// A %(arity)s predicate-formatter function.
+template <%(types)s>
+testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS
+
+ tests += Iter(n, 'const char* e%s', sep=""",
+ """)
+
+ tests += Iter(n, """,
+ const T%s& v%s""")
+
+ tests += """) {
+ if (PredFunction%(n)s(%(vs)s))
+ return testing::AssertionSuccess();
+
+ return testing::AssertionFailure()
+ << """ % DEFS
+
+ tests += Iter(n, 'e%s', sep=' << " + " << ')
+
+ tests += """
+ << " is expected to be positive, but evaluates to "
+ << %(v_sum)s << ".";
+}
+""" % DEFS
+
+ tests += """
+// A %(arity)s predicate-formatter functor.
+struct PredFormatFunctor%(n)s {
+ template <%(types)s>
+ testing::AssertionResult operator()(""" % DEFS
+
+ tests += Iter(n, 'const char* e%s', sep=""",
+ """)
+
+ tests += Iter(n, """,
+ const T%s& v%s""")
+
+ tests += """) const {
+ return PredFormatFunction%(n)s(%(es)s, %(vs)s);
+ }
+};
+""" % DEFS
+
+ tests += """
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s.
+
+class Predicate%(n)sTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;""" % DEFS
+
+ tests += """
+ """ + Iter(n, 'n%s_ = ') + """0;
+ }
+"""
+
+ tests += """
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once."""
+
+ tests += ''.join(["""
+ EXPECT_EQ(1, n%s_) <<
+ "The predicate assertion didn't evaluate argument %s "
+ "exactly once.";""" % (i, i + 1) for i in OneTo(n)])
+
+ tests += """
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+""" % DEFS
+
+ tests += Iter(n, """
+ static int n%s_;""")
+
+ tests += """
+};
+
+bool Predicate%(n)sTest::expected_to_finish_;
+bool Predicate%(n)sTest::finished_;
+""" % DEFS
+
+ tests += Iter(n, """int Predicate%%(n)sTest::n%s_;
+""") % DEFS
+
+ tests += """
+typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest;
+typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest;
+typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest;
+typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest;
+""" % DEFS
+
+ def GenTest(use_format, use_assert, expect_failure,
+ use_functor, use_user_type):
+ """Returns the test for a predicate assertion macro.
+
+ Args:
+ use_format: true iff the assertion is a *_PRED_FORMAT*.
+ use_assert: true iff the assertion is a ASSERT_*.
+ expect_failure: true iff the assertion is expected to fail.
+ use_functor: true iff the first argument of the assertion is
+ a functor (as opposed to a function)
+ use_user_type: true iff the predicate functor/function takes
+ argument(s) of a user-defined type.
+
+ Example:
+
+ GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior
+ of a successful EXPECT_PRED_FORMATn() that takes a functor
+ whose arguments have built-in types."""
+
+ if use_assert:
+ assrt = 'ASSERT' # 'assert' is reserved, so we cannot use
+ # that identifier here.
+ else:
+ assrt = 'EXPECT'
+
+ assertion = assrt + '_PRED'
+
+ if use_format:
+ pred_format = 'PredFormat'
+ assertion += '_FORMAT'
+ else:
+ pred_format = 'Pred'
+
+ assertion += '%(n)s' % DEFS
+
+ if use_functor:
+ pred_format_type = 'functor'
+ pred_format += 'Functor%(n)s()'
+ else:
+ pred_format_type = 'function'
+ pred_format += 'Function%(n)s'
+ if not use_format:
+ if use_user_type:
+ pred_format += 'Bool'
+ else:
+ pred_format += 'Int'
+
+ test_name = pred_format_type.title()
+
+ if use_user_type:
+ arg_type = 'user-defined type (Bool)'
+ test_name += 'OnUserType'
+ if expect_failure:
+ arg = 'Bool(n%s_++)'
+ else:
+ arg = 'Bool(++n%s_)'
+ else:
+ arg_type = 'built-in type (int)'
+ test_name += 'OnBuiltInType'
+ if expect_failure:
+ arg = 'n%s_++'
+ else:
+ arg = '++n%s_'
+
+ if expect_failure:
+ successful_or_failed = 'failed'
+ expected_or_not = 'expected.'
+ test_name += 'Failure'
+ else:
+ successful_or_failed = 'successful'
+ expected_or_not = 'UNEXPECTED!'
+ test_name += 'Success'
+
+ # A map that defines the values used in the test template.
+ defs = DEFS.copy()
+ defs.update({
+ 'assert' : assrt,
+ 'assertion' : assertion,
+ 'test_name' : test_name,
+ 'pf_type' : pred_format_type,
+ 'pf' : pred_format,
+ 'arg_type' : arg_type,
+ 'arg' : arg,
+ 'successful' : successful_or_failed,
+ 'expected' : expected_or_not,
+ })
+
+ test = """
+// Tests a %(successful)s %(assertion)s where the
+// predicate-formatter is a %(pf_type)s on a %(arg_type)s.
+TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs
+
+ indent = (len(assertion) + 3)*' '
+ extra_indent = ''
+
+ if expect_failure:
+ extra_indent = ' '
+ if use_assert:
+ test += """
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT"""
+ else:
+ test += """
+ EXPECT_NONFATAL_FAILURE({ // NOLINT"""
+
+ test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs
+
+ test = test % defs
+ test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs)
+ test += ');\n' + extra_indent + ' finished_ = true;\n'
+
+ if expect_failure:
+ test += ' }, "");\n'
+
+ test += '}\n'
+ return test
+
+ # Generates tests for all 2**6 = 64 combinations.
+ tests += ''.join([GenTest(use_format, use_assert, expect_failure,
+ use_functor, use_user_type)
+ for use_format in [0, 1]
+ for use_assert in [0, 1]
+ for expect_failure in [0, 1]
+ for use_functor in [0, 1]
+ for use_user_type in [0, 1]
+ ])
+
+ return tests
+
+
+def UnitTestPostamble():
+ """Returns the postamble for the tests."""
+
+ return ''
+
+
+def GenerateUnitTest(n):
+ """Returns the tests for up-to n-ary predicate assertions."""
+
+ GenerateFile(UNIT_TEST,
+ UnitTestPreamble()
+ + ''.join([TestsForArity(i) for i in OneTo(n)])
+ + UnitTestPostamble())
+
+
+def _Main():
+ """The entry point of the script. Generates the header file and its
+ unit test."""
+
+ if len(sys.argv) != 2:
+ print __doc__
+ print 'Author: ' + __author__
+ sys.exit(1)
+
+ n = int(sys.argv[1])
+ GenerateHeader(n)
+ GenerateUnitTest(n)
+
+
+if __name__ == '__main__':
+ _Main()
diff --git a/external/gtest-1.6.0/scripts/gtest-config.in b/external/gtest-1.6.0/scripts/gtest-config.in
new file mode 100755
index 0000000..780f843
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/gtest-config.in
@@ -0,0 +1,274 @@
+#!/bin/sh
+
+# These variables are automatically filled in by the configure script.
+name="@PACKAGE_TARNAME@"
+version="@PACKAGE_VERSION@"
+
+show_usage()
+{
+ echo "Usage: gtest-config [OPTIONS...]"
+}
+
+show_help()
+{
+ show_usage
+ cat <<\EOF
+
+The `gtest-config' script provides access to the necessary compile and linking
+flags to connect with Google C++ Testing Framework, both in a build prior to
+installation, and on the system proper after installation. The installation
+overrides may be issued in combination with any other queries, but will only
+affect installation queries if called on a built but not installed gtest. The
+installation queries may not be issued with any other types of queries, and
+only one installation query may be made at a time. The version queries and
+compiler flag queries may be combined as desired but not mixed. Different
+version queries are always combined with logical "and" semantics, and only the
+last of any particular query is used while all previous ones ignored. All
+versions must be specified as a sequence of numbers separated by periods.
+Compiler flag queries output the union of the sets of flags when combined.
+
+ Examples:
+ gtest-config --min-version=1.0 || echo "Insufficient Google Test version."
+
+ g++ $(gtest-config --cppflags --cxxflags) -o foo.o -c foo.cpp
+ g++ $(gtest-config --ldflags --libs) -o foo foo.o
+
+ # When using a built but not installed Google Test:
+ g++ $(../../my_gtest_build/scripts/gtest-config ...) ...
+
+ # When using an installed Google Test, but with installation overrides:
+ export GTEST_PREFIX="/opt"
+ g++ $(gtest-config --libdir="/opt/lib64" ...) ...
+
+ Help:
+ --usage brief usage information
+ --help display this help message
+
+ Installation Overrides:
+ --prefix=<dir> overrides the installation prefix
+ --exec-prefix=<dir> overrides the executable installation prefix
+ --libdir=<dir> overrides the library installation prefix
+ --includedir=<dir> overrides the header file installation prefix
+
+ Installation Queries:
+ --prefix installation prefix
+ --exec-prefix executable installation prefix
+ --libdir library installation directory
+ --includedir header file installation directory
+ --version the version of the Google Test installation
+
+ Version Queries:
+ --min-version=VERSION return 0 if the version is at least VERSION
+ --exact-version=VERSION return 0 if the version is exactly VERSION
+ --max-version=VERSION return 0 if the version is at most VERSION
+
+ Compilation Flag Queries:
+ --cppflags compile flags specific to the C-like preprocessors
+ --cxxflags compile flags appropriate for C++ programs
+ --ldflags linker flags
+ --libs libraries for linking
+
+EOF
+}
+
+# This function bounds our version with a min and a max. It uses some clever
+# POSIX-compliant variable expansion to portably do all the work in the shell
+# and avoid any dependency on a particular "sed" or "awk" implementation.
+# Notable is that it will only ever compare the first 3 components of versions.
+# Further components will be cleanly stripped off. All versions must be
+# unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and
+# the max in $2. TODO(chandlerc at google.com): If this ever breaks, we should
+# investigate expanding this via autom4te from AS_VERSION_COMPARE rather than
+# continuing to maintain our own shell version.
+check_versions()
+{
+ major_version=${version%%.*}
+ minor_version="0"
+ point_version="0"
+ if test "${version#*.}" != "${version}"; then
+ minor_version=${version#*.}
+ minor_version=${minor_version%%.*}
+ fi
+ if test "${version#*.*.}" != "${version}"; then
+ point_version=${version#*.*.}
+ point_version=${point_version%%.*}
+ fi
+
+ min_version="$1"
+ min_major_version=${min_version%%.*}
+ min_minor_version="0"
+ min_point_version="0"
+ if test "${min_version#*.}" != "${min_version}"; then
+ min_minor_version=${min_version#*.}
+ min_minor_version=${min_minor_version%%.*}
+ fi
+ if test "${min_version#*.*.}" != "${min_version}"; then
+ min_point_version=${min_version#*.*.}
+ min_point_version=${min_point_version%%.*}
+ fi
+
+ max_version="$2"
+ max_major_version=${max_version%%.*}
+ max_minor_version="0"
+ max_point_version="0"
+ if test "${max_version#*.}" != "${max_version}"; then
+ max_minor_version=${max_version#*.}
+ max_minor_version=${max_minor_version%%.*}
+ fi
+ if test "${max_version#*.*.}" != "${max_version}"; then
+ max_point_version=${max_version#*.*.}
+ max_point_version=${max_point_version%%.*}
+ fi
+
+ test $(($major_version)) -lt $(($min_major_version)) && exit 1
+ if test $(($major_version)) -eq $(($min_major_version)); then
+ test $(($minor_version)) -lt $(($min_minor_version)) && exit 1
+ if test $(($minor_version)) -eq $(($min_minor_version)); then
+ test $(($point_version)) -lt $(($min_point_version)) && exit 1
+ fi
+ fi
+
+ test $(($major_version)) -gt $(($max_major_version)) && exit 1
+ if test $(($major_version)) -eq $(($max_major_version)); then
+ test $(($minor_version)) -gt $(($max_minor_version)) && exit 1
+ if test $(($minor_version)) -eq $(($max_minor_version)); then
+ test $(($point_version)) -gt $(($max_point_version)) && exit 1
+ fi
+ fi
+
+ exit 0
+}
+
+# Show the usage line when no arguments are specified.
+if test $# -eq 0; then
+ show_usage
+ exit 1
+fi
+
+while test $# -gt 0; do
+ case $1 in
+ --usage) show_usage; exit 0;;
+ --help) show_help; exit 0;;
+
+ # Installation overrides
+ --prefix=*) GTEST_PREFIX=${1#--prefix=};;
+ --exec-prefix=*) GTEST_EXEC_PREFIX=${1#--exec-prefix=};;
+ --libdir=*) GTEST_LIBDIR=${1#--libdir=};;
+ --includedir=*) GTEST_INCLUDEDIR=${1#--includedir=};;
+
+ # Installation queries
+ --prefix|--exec-prefix|--libdir|--includedir|--version)
+ if test -n "${do_query}"; then
+ show_usage
+ exit 1
+ fi
+ do_query=${1#--}
+ ;;
+
+ # Version checking
+ --min-version=*)
+ do_check_versions=yes
+ min_version=${1#--min-version=}
+ ;;
+ --max-version=*)
+ do_check_versions=yes
+ max_version=${1#--max-version=}
+ ;;
+ --exact-version=*)
+ do_check_versions=yes
+ exact_version=${1#--exact-version=}
+ ;;
+
+ # Compiler flag output
+ --cppflags) echo_cppflags=yes;;
+ --cxxflags) echo_cxxflags=yes;;
+ --ldflags) echo_ldflags=yes;;
+ --libs) echo_libs=yes;;
+
+ # Everything else is an error
+ *) show_usage; exit 1;;
+ esac
+ shift
+done
+
+# These have defaults filled in by the configure script but can also be
+# overridden by environment variables or command line parameters.
+prefix="${GTEST_PREFIX:- at prefix@}"
+exec_prefix="${GTEST_EXEC_PREFIX:- at exec_prefix@}"
+libdir="${GTEST_LIBDIR:- at libdir@}"
+includedir="${GTEST_INCLUDEDIR:- at includedir@}"
+
+# We try and detect if our binary is not located at its installed location. If
+# it's not, we provide variables pointing to the source and build tree rather
+# than to the install tree. This allows building against a just-built gtest
+# rather than an installed gtest.
+bindir="@bindir@"
+this_relative_bindir=`dirname $0`
+this_bindir=`cd ${this_relative_bindir}; pwd -P`
+if test "${this_bindir}" = "${this_bindir%${bindir}}"; then
+ # The path to the script doesn't end in the bindir sequence from Autoconf,
+ # assume that we are in a build tree.
+ build_dir=`dirname ${this_bindir}`
+ src_dir=`cd ${this_bindir}; cd @top_srcdir@; pwd -P`
+
+ # TODO(chandlerc at google.com): This is a dangerous dependency on libtool, we
+ # should work to remove it, and/or remove libtool altogether, replacing it
+ # with direct references to the library and a link path.
+ gtest_libs="${build_dir}/lib/libgtest.la @PTHREAD_CFLAGS@ @PTHREAD_LIBS@"
+ gtest_ldflags=""
+
+ # We provide hooks to include from either the source or build dir, where the
+ # build dir is always preferred. This will potentially allow us to write
+ # build rules for generated headers and have them automatically be preferred
+ # over provided versions.
+ gtest_cppflags="-I${build_dir}/include -I${src_dir}/include"
+ gtest_cxxflags="@PTHREAD_CFLAGS@"
+else
+ # We're using an installed gtest, although it may be staged under some
+ # prefix. Assume (as our own libraries do) that we can resolve the prefix,
+ # and are present in the dynamic link paths.
+ gtest_ldflags="-L${libdir}"
+ gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@"
+ gtest_cppflags="-I${includedir}"
+ gtest_cxxflags="@PTHREAD_CFLAGS@"
+fi
+
+# Do an installation query if requested.
+if test -n "$do_query"; then
+ case $do_query in
+ prefix) echo $prefix; exit 0;;
+ exec-prefix) echo $exec_prefix; exit 0;;
+ libdir) echo $libdir; exit 0;;
+ includedir) echo $includedir; exit 0;;
+ version) echo $version; exit 0;;
+ *) show_usage; exit 1;;
+ esac
+fi
+
+# Do a version check if requested.
+if test "$do_check_versions" = "yes"; then
+ # Make sure we didn't receive a bad combination of parameters.
+ test "$echo_cppflags" = "yes" && show_usage && exit 1
+ test "$echo_cxxflags" = "yes" && show_usage && exit 1
+ test "$echo_ldflags" = "yes" && show_usage && exit 1
+ test "$echo_libs" = "yes" && show_usage && exit 1
+
+ if test "$exact_version" != ""; then
+ check_versions $exact_version $exact_version
+ # unreachable
+ else
+ check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999}
+ # unreachable
+ fi
+fi
+
+# Do the output in the correct order so that these can be used in-line of
+# a compiler invocation.
+output=""
+test "$echo_cppflags" = "yes" && output="$output $gtest_cppflags"
+test "$echo_cxxflags" = "yes" && output="$output $gtest_cxxflags"
+test "$echo_ldflags" = "yes" && output="$output $gtest_ldflags"
+test "$echo_libs" = "yes" && output="$output $gtest_libs"
+echo $output
+
+exit 0
diff --git a/external/gtest-1.6.0/scripts/pump.py b/external/gtest-1.6.0/scripts/pump.py
new file mode 100755
index 0000000..5efb653
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/pump.py
@@ -0,0 +1,855 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""pump v0.2.0 - Pretty Useful for Meta Programming.
+
+A tool for preprocessor meta programming. Useful for generating
+repetitive boilerplate code. Especially useful for writing C++
+classes, functions, macros, and templates that need to work with
+various number of arguments.
+
+USAGE:
+ pump.py SOURCE_FILE
+
+EXAMPLES:
+ pump.py foo.cc.pump
+ Converts foo.cc.pump to foo.cc.
+
+GRAMMAR:
+ CODE ::= ATOMIC_CODE*
+ ATOMIC_CODE ::= $var ID = EXPRESSION
+ | $var ID = [[ CODE ]]
+ | $range ID EXPRESSION..EXPRESSION
+ | $for ID SEPARATOR [[ CODE ]]
+ | $($)
+ | $ID
+ | $(EXPRESSION)
+ | $if EXPRESSION [[ CODE ]] ELSE_BRANCH
+ | [[ CODE ]]
+ | RAW_CODE
+ SEPARATOR ::= RAW_CODE | EMPTY
+ ELSE_BRANCH ::= $else [[ CODE ]]
+ | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH
+ | EMPTY
+ EXPRESSION has Python syntax.
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import re
+import sys
+
+
+TOKEN_TABLE = [
+ (re.compile(r'\$var\s+'), '$var'),
+ (re.compile(r'\$elif\s+'), '$elif'),
+ (re.compile(r'\$else\s+'), '$else'),
+ (re.compile(r'\$for\s+'), '$for'),
+ (re.compile(r'\$if\s+'), '$if'),
+ (re.compile(r'\$range\s+'), '$range'),
+ (re.compile(r'\$[_A-Za-z]\w*'), '$id'),
+ (re.compile(r'\$\(\$\)'), '$($)'),
+ (re.compile(r'\$'), '$'),
+ (re.compile(r'\[\[\n?'), '[['),
+ (re.compile(r'\]\]\n?'), ']]'),
+ ]
+
+
+class Cursor:
+ """Represents a position (line and column) in a text file."""
+
+ def __init__(self, line=-1, column=-1):
+ self.line = line
+ self.column = column
+
+ def __eq__(self, rhs):
+ return self.line == rhs.line and self.column == rhs.column
+
+ def __ne__(self, rhs):
+ return not self == rhs
+
+ def __lt__(self, rhs):
+ return self.line < rhs.line or (
+ self.line == rhs.line and self.column < rhs.column)
+
+ def __le__(self, rhs):
+ return self < rhs or self == rhs
+
+ def __gt__(self, rhs):
+ return rhs < self
+
+ def __ge__(self, rhs):
+ return rhs <= self
+
+ def __str__(self):
+ if self == Eof():
+ return 'EOF'
+ else:
+ return '%s(%s)' % (self.line + 1, self.column)
+
+ def __add__(self, offset):
+ return Cursor(self.line, self.column + offset)
+
+ def __sub__(self, offset):
+ return Cursor(self.line, self.column - offset)
+
+ def Clone(self):
+ """Returns a copy of self."""
+
+ return Cursor(self.line, self.column)
+
+
+# Special cursor to indicate the end-of-file.
+def Eof():
+ """Returns the special cursor to denote the end-of-file."""
+ return Cursor(-1, -1)
+
+
+class Token:
+ """Represents a token in a Pump source file."""
+
+ def __init__(self, start=None, end=None, value=None, token_type=None):
+ if start is None:
+ self.start = Eof()
+ else:
+ self.start = start
+ if end is None:
+ self.end = Eof()
+ else:
+ self.end = end
+ self.value = value
+ self.token_type = token_type
+
+ def __str__(self):
+ return 'Token @%s: \'%s\' type=%s' % (
+ self.start, self.value, self.token_type)
+
+ def Clone(self):
+ """Returns a copy of self."""
+
+ return Token(self.start.Clone(), self.end.Clone(), self.value,
+ self.token_type)
+
+
+def StartsWith(lines, pos, string):
+ """Returns True iff the given position in lines starts with 'string'."""
+
+ return lines[pos.line][pos.column:].startswith(string)
+
+
+def FindFirstInLine(line, token_table):
+ best_match_start = -1
+ for (regex, token_type) in token_table:
+ m = regex.search(line)
+ if m:
+ # We found regex in lines
+ if best_match_start < 0 or m.start() < best_match_start:
+ best_match_start = m.start()
+ best_match_length = m.end() - m.start()
+ best_match_token_type = token_type
+
+ if best_match_start < 0:
+ return None
+
+ return (best_match_start, best_match_length, best_match_token_type)
+
+
+def FindFirst(lines, token_table, cursor):
+ """Finds the first occurrence of any string in strings in lines."""
+
+ start = cursor.Clone()
+ cur_line_number = cursor.line
+ for line in lines[start.line:]:
+ if cur_line_number == start.line:
+ line = line[start.column:]
+ m = FindFirstInLine(line, token_table)
+ if m:
+ # We found a regex in line.
+ (start_column, length, token_type) = m
+ if cur_line_number == start.line:
+ start_column += start.column
+ found_start = Cursor(cur_line_number, start_column)
+ found_end = found_start + length
+ return MakeToken(lines, found_start, found_end, token_type)
+ cur_line_number += 1
+ # We failed to find str in lines
+ return None
+
+
+def SubString(lines, start, end):
+ """Returns a substring in lines."""
+
+ if end == Eof():
+ end = Cursor(len(lines) - 1, len(lines[-1]))
+
+ if start >= end:
+ return ''
+
+ if start.line == end.line:
+ return lines[start.line][start.column:end.column]
+
+ result_lines = ([lines[start.line][start.column:]] +
+ lines[start.line + 1:end.line] +
+ [lines[end.line][:end.column]])
+ return ''.join(result_lines)
+
+
+def StripMetaComments(str):
+ """Strip meta comments from each line in the given string."""
+
+ # First, completely remove lines containing nothing but a meta
+ # comment, including the trailing \n.
+ str = re.sub(r'^\s*\$\$.*\n', '', str)
+
+ # Then, remove meta comments from contentful lines.
+ return re.sub(r'\s*\$\$.*', '', str)
+
+
+def MakeToken(lines, start, end, token_type):
+ """Creates a new instance of Token."""
+
+ return Token(start, end, SubString(lines, start, end), token_type)
+
+
+def ParseToken(lines, pos, regex, token_type):
+ line = lines[pos.line][pos.column:]
+ m = regex.search(line)
+ if m and not m.start():
+ return MakeToken(lines, pos, pos + m.end(), token_type)
+ else:
+ print 'ERROR: %s expected at %s.' % (token_type, pos)
+ sys.exit(1)
+
+
+ID_REGEX = re.compile(r'[_A-Za-z]\w*')
+EQ_REGEX = re.compile(r'=')
+REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)')
+OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*')
+WHITE_SPACE_REGEX = re.compile(r'\s')
+DOT_DOT_REGEX = re.compile(r'\.\.')
+
+
+def Skip(lines, pos, regex):
+ line = lines[pos.line][pos.column:]
+ m = re.search(regex, line)
+ if m and not m.start():
+ return pos + m.end()
+ else:
+ return pos
+
+
+def SkipUntil(lines, pos, regex, token_type):
+ line = lines[pos.line][pos.column:]
+ m = re.search(regex, line)
+ if m:
+ return pos + m.start()
+ else:
+ print ('ERROR: %s expected on line %s after column %s.' %
+ (token_type, pos.line + 1, pos.column))
+ sys.exit(1)
+
+
+def ParseExpTokenInParens(lines, pos):
+ def ParseInParens(pos):
+ pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX)
+ pos = Skip(lines, pos, r'\(')
+ pos = Parse(pos)
+ pos = Skip(lines, pos, r'\)')
+ return pos
+
+ def Parse(pos):
+ pos = SkipUntil(lines, pos, r'\(|\)', ')')
+ if SubString(lines, pos, pos + 1) == '(':
+ pos = Parse(pos + 1)
+ pos = Skip(lines, pos, r'\)')
+ return Parse(pos)
+ else:
+ return pos
+
+ start = pos.Clone()
+ pos = ParseInParens(pos)
+ return MakeToken(lines, start, pos, 'exp')
+
+
+def RStripNewLineFromToken(token):
+ if token.value.endswith('\n'):
+ return Token(token.start, token.end, token.value[:-1], token.token_type)
+ else:
+ return token
+
+
+def TokenizeLines(lines, pos):
+ while True:
+ found = FindFirst(lines, TOKEN_TABLE, pos)
+ if not found:
+ yield MakeToken(lines, pos, Eof(), 'code')
+ return
+
+ if found.start == pos:
+ prev_token = None
+ prev_token_rstripped = None
+ else:
+ prev_token = MakeToken(lines, pos, found.start, 'code')
+ prev_token_rstripped = RStripNewLineFromToken(prev_token)
+
+ if found.token_type == '$var':
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+ yield id_token
+ pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
+
+ eq_token = ParseToken(lines, pos, EQ_REGEX, '=')
+ yield eq_token
+ pos = Skip(lines, eq_token.end, r'\s*')
+
+ if SubString(lines, pos, pos + 2) != '[[':
+ exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp')
+ yield exp_token
+ pos = Cursor(exp_token.end.line + 1, 0)
+ elif found.token_type == '$for':
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+ yield id_token
+ pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX)
+ elif found.token_type == '$range':
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+ yield id_token
+ pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
+
+ dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..')
+ yield MakeToken(lines, pos, dots_pos, 'exp')
+ yield MakeToken(lines, dots_pos, dots_pos + 2, '..')
+ pos = dots_pos + 2
+ new_pos = Cursor(pos.line + 1, 0)
+ yield MakeToken(lines, pos, new_pos, 'exp')
+ pos = new_pos
+ elif found.token_type == '$':
+ if prev_token:
+ yield prev_token
+ yield found
+ exp_token = ParseExpTokenInParens(lines, found.end)
+ yield exp_token
+ pos = exp_token.end
+ elif (found.token_type == ']]' or found.token_type == '$if' or
+ found.token_type == '$elif' or found.token_type == '$else'):
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ pos = found.end
+ else:
+ if prev_token:
+ yield prev_token
+ yield found
+ pos = found.end
+
+
+def Tokenize(s):
+ """A generator that yields the tokens in the given string."""
+ if s != '':
+ lines = s.splitlines(True)
+ for token in TokenizeLines(lines, Cursor(0, 0)):
+ yield token
+
+
+class CodeNode:
+ def __init__(self, atomic_code_list=None):
+ self.atomic_code = atomic_code_list
+
+
+class VarNode:
+ def __init__(self, identifier=None, atomic_code=None):
+ self.identifier = identifier
+ self.atomic_code = atomic_code
+
+
+class RangeNode:
+ def __init__(self, identifier=None, exp1=None, exp2=None):
+ self.identifier = identifier
+ self.exp1 = exp1
+ self.exp2 = exp2
+
+
+class ForNode:
+ def __init__(self, identifier=None, sep=None, code=None):
+ self.identifier = identifier
+ self.sep = sep
+ self.code = code
+
+
+class ElseNode:
+ def __init__(self, else_branch=None):
+ self.else_branch = else_branch
+
+
+class IfNode:
+ def __init__(self, exp=None, then_branch=None, else_branch=None):
+ self.exp = exp
+ self.then_branch = then_branch
+ self.else_branch = else_branch
+
+
+class RawCodeNode:
+ def __init__(self, token=None):
+ self.raw_code = token
+
+
+class LiteralDollarNode:
+ def __init__(self, token):
+ self.token = token
+
+
+class ExpNode:
+ def __init__(self, token, python_exp):
+ self.token = token
+ self.python_exp = python_exp
+
+
+def PopFront(a_list):
+ head = a_list[0]
+ a_list[:1] = []
+ return head
+
+
+def PushFront(a_list, elem):
+ a_list[:0] = [elem]
+
+
+def PopToken(a_list, token_type=None):
+ token = PopFront(a_list)
+ if token_type is not None and token.token_type != token_type:
+ print 'ERROR: %s expected at %s' % (token_type, token.start)
+ print 'ERROR: %s found instead' % (token,)
+ sys.exit(1)
+
+ return token
+
+
+def PeekToken(a_list):
+ if not a_list:
+ return None
+
+ return a_list[0]
+
+
+def ParseExpNode(token):
+ python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value)
+ return ExpNode(token, python_exp)
+
+
+def ParseElseNode(tokens):
+ def Pop(token_type=None):
+ return PopToken(tokens, token_type)
+
+ next = PeekToken(tokens)
+ if not next:
+ return None
+ if next.token_type == '$else':
+ Pop('$else')
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return code_node
+ elif next.token_type == '$elif':
+ Pop('$elif')
+ exp = Pop('code')
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ inner_else_node = ParseElseNode(tokens)
+ return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)])
+ elif not next.value.strip():
+ Pop('code')
+ return ParseElseNode(tokens)
+ else:
+ return None
+
+
+def ParseAtomicCodeNode(tokens):
+ def Pop(token_type=None):
+ return PopToken(tokens, token_type)
+
+ head = PopFront(tokens)
+ t = head.token_type
+ if t == 'code':
+ return RawCodeNode(head)
+ elif t == '$var':
+ id_token = Pop('id')
+ Pop('=')
+ next = PeekToken(tokens)
+ if next.token_type == 'exp':
+ exp_token = Pop()
+ return VarNode(id_token, ParseExpNode(exp_token))
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return VarNode(id_token, code_node)
+ elif t == '$for':
+ id_token = Pop('id')
+ next_token = PeekToken(tokens)
+ if next_token.token_type == 'code':
+ sep_token = next_token
+ Pop('code')
+ else:
+ sep_token = None
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return ForNode(id_token, sep_token, code_node)
+ elif t == '$if':
+ exp_token = Pop('code')
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ else_node = ParseElseNode(tokens)
+ return IfNode(ParseExpNode(exp_token), code_node, else_node)
+ elif t == '$range':
+ id_token = Pop('id')
+ exp1_token = Pop('exp')
+ Pop('..')
+ exp2_token = Pop('exp')
+ return RangeNode(id_token, ParseExpNode(exp1_token),
+ ParseExpNode(exp2_token))
+ elif t == '$id':
+ return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id'))
+ elif t == '$($)':
+ return LiteralDollarNode(head)
+ elif t == '$':
+ exp_token = Pop('exp')
+ return ParseExpNode(exp_token)
+ elif t == '[[':
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return code_node
+ else:
+ PushFront(tokens, head)
+ return None
+
+
+def ParseCodeNode(tokens):
+ atomic_code_list = []
+ while True:
+ if not tokens:
+ break
+ atomic_code_node = ParseAtomicCodeNode(tokens)
+ if atomic_code_node:
+ atomic_code_list.append(atomic_code_node)
+ else:
+ break
+ return CodeNode(atomic_code_list)
+
+
+def ParseToAST(pump_src_text):
+ """Convert the given Pump source text into an AST."""
+ tokens = list(Tokenize(pump_src_text))
+ code_node = ParseCodeNode(tokens)
+ return code_node
+
+
+class Env:
+ def __init__(self):
+ self.variables = []
+ self.ranges = []
+
+ def Clone(self):
+ clone = Env()
+ clone.variables = self.variables[:]
+ clone.ranges = self.ranges[:]
+ return clone
+
+ def PushVariable(self, var, value):
+ # If value looks like an int, store it as an int.
+ try:
+ int_value = int(value)
+ if ('%s' % int_value) == value:
+ value = int_value
+ except Exception:
+ pass
+ self.variables[:0] = [(var, value)]
+
+ def PopVariable(self):
+ self.variables[:1] = []
+
+ def PushRange(self, var, lower, upper):
+ self.ranges[:0] = [(var, lower, upper)]
+
+ def PopRange(self):
+ self.ranges[:1] = []
+
+ def GetValue(self, identifier):
+ for (var, value) in self.variables:
+ if identifier == var:
+ return value
+
+ print 'ERROR: meta variable %s is undefined.' % (identifier,)
+ sys.exit(1)
+
+ def EvalExp(self, exp):
+ try:
+ result = eval(exp.python_exp)
+ except Exception, e:
+ print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e)
+ print ('ERROR: failed to evaluate meta expression %s at %s' %
+ (exp.python_exp, exp.token.start))
+ sys.exit(1)
+ return result
+
+ def GetRange(self, identifier):
+ for (var, lower, upper) in self.ranges:
+ if identifier == var:
+ return (lower, upper)
+
+ print 'ERROR: range %s is undefined.' % (identifier,)
+ sys.exit(1)
+
+
+class Output:
+ def __init__(self):
+ self.string = ''
+
+ def GetLastLine(self):
+ index = self.string.rfind('\n')
+ if index < 0:
+ return ''
+
+ return self.string[index + 1:]
+
+ def Append(self, s):
+ self.string += s
+
+
+def RunAtomicCode(env, node, output):
+ if isinstance(node, VarNode):
+ identifier = node.identifier.value.strip()
+ result = Output()
+ RunAtomicCode(env.Clone(), node.atomic_code, result)
+ value = result.string
+ env.PushVariable(identifier, value)
+ elif isinstance(node, RangeNode):
+ identifier = node.identifier.value.strip()
+ lower = int(env.EvalExp(node.exp1))
+ upper = int(env.EvalExp(node.exp2))
+ env.PushRange(identifier, lower, upper)
+ elif isinstance(node, ForNode):
+ identifier = node.identifier.value.strip()
+ if node.sep is None:
+ sep = ''
+ else:
+ sep = node.sep.value
+ (lower, upper) = env.GetRange(identifier)
+ for i in range(lower, upper + 1):
+ new_env = env.Clone()
+ new_env.PushVariable(identifier, i)
+ RunCode(new_env, node.code, output)
+ if i != upper:
+ output.Append(sep)
+ elif isinstance(node, RawCodeNode):
+ output.Append(node.raw_code.value)
+ elif isinstance(node, IfNode):
+ cond = env.EvalExp(node.exp)
+ if cond:
+ RunCode(env.Clone(), node.then_branch, output)
+ elif node.else_branch is not None:
+ RunCode(env.Clone(), node.else_branch, output)
+ elif isinstance(node, ExpNode):
+ value = env.EvalExp(node)
+ output.Append('%s' % (value,))
+ elif isinstance(node, LiteralDollarNode):
+ output.Append('$')
+ elif isinstance(node, CodeNode):
+ RunCode(env.Clone(), node, output)
+ else:
+ print 'BAD'
+ print node
+ sys.exit(1)
+
+
+def RunCode(env, code_node, output):
+ for atomic_code in code_node.atomic_code:
+ RunAtomicCode(env, atomic_code, output)
+
+
+def IsSingleLineComment(cur_line):
+ return '//' in cur_line
+
+
+def IsInPreprocessorDirective(prev_lines, cur_line):
+ if cur_line.lstrip().startswith('#'):
+ return True
+ return prev_lines and prev_lines[-1].endswith('\\')
+
+
+def WrapComment(line, output):
+ loc = line.find('//')
+ before_comment = line[:loc].rstrip()
+ if before_comment == '':
+ indent = loc
+ else:
+ output.append(before_comment)
+ indent = len(before_comment) - len(before_comment.lstrip())
+ prefix = indent*' ' + '// '
+ max_len = 80 - len(prefix)
+ comment = line[loc + 2:].strip()
+ segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != '']
+ cur_line = ''
+ for seg in segs:
+ if len((cur_line + seg).rstrip()) < max_len:
+ cur_line += seg
+ else:
+ if cur_line.strip() != '':
+ output.append(prefix + cur_line.rstrip())
+ cur_line = seg.lstrip()
+ if cur_line.strip() != '':
+ output.append(prefix + cur_line.strip())
+
+
+def WrapCode(line, line_concat, output):
+ indent = len(line) - len(line.lstrip())
+ prefix = indent*' ' # Prefix of the current line
+ max_len = 80 - indent - len(line_concat) # Maximum length of the current line
+ new_prefix = prefix + 4*' ' # Prefix of a continuation line
+ new_max_len = max_len - 4 # Maximum length of a continuation line
+ # Prefers to wrap a line after a ',' or ';'.
+ segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != '']
+ cur_line = '' # The current line without leading spaces.
+ for seg in segs:
+ # If the line is still too long, wrap at a space.
+ while cur_line == '' and len(seg.strip()) > max_len:
+ seg = seg.lstrip()
+ split_at = seg.rfind(' ', 0, max_len)
+ output.append(prefix + seg[:split_at].strip() + line_concat)
+ seg = seg[split_at + 1:]
+ prefix = new_prefix
+ max_len = new_max_len
+
+ if len((cur_line + seg).rstrip()) < max_len:
+ cur_line = (cur_line + seg).lstrip()
+ else:
+ output.append(prefix + cur_line.rstrip() + line_concat)
+ prefix = new_prefix
+ max_len = new_max_len
+ cur_line = seg.lstrip()
+ if cur_line.strip() != '':
+ output.append(prefix + cur_line.strip())
+
+
+def WrapPreprocessorDirective(line, output):
+ WrapCode(line, ' \\', output)
+
+
+def WrapPlainCode(line, output):
+ WrapCode(line, '', output)
+
+
+def IsMultiLineIWYUPragma(line):
+ return re.search(r'/\* IWYU pragma: ', line)
+
+
+def IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
+ return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or
+ re.match(r'^#include\s', line) or
+ # Don't break IWYU pragmas, either; that causes iwyu.py problems.
+ re.search(r'// IWYU pragma: ', line))
+
+
+def WrapLongLine(line, output):
+ line = line.rstrip()
+ if len(line) <= 80:
+ output.append(line)
+ elif IsSingleLineComment(line):
+ if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
+ # The style guide made an exception to allow long header guard lines,
+ # includes and IWYU pragmas.
+ output.append(line)
+ else:
+ WrapComment(line, output)
+ elif IsInPreprocessorDirective(output, line):
+ if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
+ # The style guide made an exception to allow long header guard lines,
+ # includes and IWYU pragmas.
+ output.append(line)
+ else:
+ WrapPreprocessorDirective(line, output)
+ elif IsMultiLineIWYUPragma(line):
+ output.append(line)
+ else:
+ WrapPlainCode(line, output)
+
+
+def BeautifyCode(string):
+ lines = string.splitlines()
+ output = []
+ for line in lines:
+ WrapLongLine(line, output)
+ output2 = [line.rstrip() for line in output]
+ return '\n'.join(output2) + '\n'
+
+
+def ConvertFromPumpSource(src_text):
+ """Return the text generated from the given Pump source text."""
+ ast = ParseToAST(StripMetaComments(src_text))
+ output = Output()
+ RunCode(Env(), ast, output)
+ return BeautifyCode(output.string)
+
+
+def main(argv):
+ if len(argv) == 1:
+ print __doc__
+ sys.exit(1)
+
+ file_path = argv[-1]
+ output_str = ConvertFromPumpSource(file(file_path, 'r').read())
+ if file_path.endswith('.pump'):
+ output_file_path = file_path[:-5]
+ else:
+ output_file_path = '-'
+ if output_file_path == '-':
+ print output_str,
+ else:
+ output_file = file(output_file_path, 'w')
+ output_file.write('// This file was GENERATED by command:\n')
+ output_file.write('// %s %s\n' %
+ (os.path.basename(__file__), os.path.basename(file_path)))
+ output_file.write('// DO NOT EDIT BY HAND!!!\n\n')
+ output_file.write(output_str)
+ output_file.close()
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/external/gtest-1.6.0/scripts/test/Makefile b/external/gtest-1.6.0/scripts/test/Makefile
new file mode 100644
index 0000000..cdff584
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/test/Makefile
@@ -0,0 +1,59 @@
+# A Makefile for fusing Google Test and building a sample test against it.
+#
+# SYNOPSIS:
+#
+# make [all] - makes everything.
+# make TARGET - makes the given target.
+# make check - makes everything and runs the built sample test.
+# make clean - removes all files generated by make.
+
+# Points to the root of fused Google Test, relative to where this file is.
+FUSED_GTEST_DIR = output
+
+# Paths to the fused gtest files.
+FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h
+FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc
+
+# Where to find the sample test.
+SAMPLE_DIR = ../../samples
+
+# Where to find gtest_main.cc.
+GTEST_MAIN_CC = ../../src/gtest_main.cc
+
+# Flags passed to the preprocessor.
+# We have no idea here whether pthreads is available in the system, so
+# disable its use.
+CPPFLAGS += -I$(FUSED_GTEST_DIR) -DGTEST_HAS_PTHREAD=0
+
+# Flags passed to the C++ compiler.
+CXXFLAGS += -g
+
+all : sample1_unittest
+
+check : all
+ ./sample1_unittest
+
+clean :
+ rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o
+
+$(FUSED_GTEST_H) :
+ ../fuse_gtest_files.py $(FUSED_GTEST_DIR)
+
+$(FUSED_GTEST_ALL_CC) :
+ ../fuse_gtest_files.py $(FUSED_GTEST_DIR)
+
+gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc
+
+gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC)
+
+sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc
+
+sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \
+ $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc
+
+sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
diff --git a/external/gtest-1.6.0/scripts/upload.py b/external/gtest-1.6.0/scripts/upload.py
new file mode 100755
index 0000000..6e6f9a1
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/upload.py
@@ -0,0 +1,1387 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tool for uploading diffs from a version control system to the codereview app.
+
+Usage summary: upload.py [options] [-- diff_options]
+
+Diff options are passed to the diff command of the underlying system.
+
+Supported version control systems:
+ Git
+ Mercurial
+ Subversion
+
+It is important for Git/Mercurial users to specify a tree/node/branch to diff
+against by using the '--rev' option.
+"""
+# This code is derived from appcfg.py in the App Engine SDK (open source),
+# and from ASPN recipe #146306.
+
+import cookielib
+import getpass
+import logging
+import md5
+import mimetypes
+import optparse
+import os
+import re
+import socket
+import subprocess
+import sys
+import urllib
+import urllib2
+import urlparse
+
+try:
+ import readline
+except ImportError:
+ pass
+
+# The logging verbosity:
+# 0: Errors only.
+# 1: Status messages.
+# 2: Info logs.
+# 3: Debug logs.
+verbosity = 1
+
+# Max size of patch or base file.
+MAX_UPLOAD_SIZE = 900 * 1024
+
+
+def GetEmail(prompt):
+ """Prompts the user for their email address and returns it.
+
+ The last used email address is saved to a file and offered up as a suggestion
+ to the user. If the user presses enter without typing in anything the last
+ used email address is used. If the user enters a new address, it is saved
+ for next time we prompt.
+
+ """
+ last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
+ last_email = ""
+ if os.path.exists(last_email_file_name):
+ try:
+ last_email_file = open(last_email_file_name, "r")
+ last_email = last_email_file.readline().strip("\n")
+ last_email_file.close()
+ prompt += " [%s]" % last_email
+ except IOError, e:
+ pass
+ email = raw_input(prompt + ": ").strip()
+ if email:
+ try:
+ last_email_file = open(last_email_file_name, "w")
+ last_email_file.write(email)
+ last_email_file.close()
+ except IOError, e:
+ pass
+ else:
+ email = last_email
+ return email
+
+
+def StatusUpdate(msg):
+ """Print a status message to stdout.
+
+ If 'verbosity' is greater than 0, print the message.
+
+ Args:
+ msg: The string to print.
+ """
+ if verbosity > 0:
+ print msg
+
+
+def ErrorExit(msg):
+ """Print an error message to stderr and exit."""
+ print >>sys.stderr, msg
+ sys.exit(1)
+
+
+class ClientLoginError(urllib2.HTTPError):
+ """Raised to indicate there was an error authenticating with ClientLogin."""
+
+ def __init__(self, url, code, msg, headers, args):
+ urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
+ self.args = args
+ self.reason = args["Error"]
+
+
+class AbstractRpcServer(object):
+ """Provides a common interface for a simple RPC server."""
+
+ def __init__(self, host, auth_function, host_override=None, extra_headers={},
+ save_cookies=False):
+ """Creates a new HttpRpcServer.
+
+ Args:
+ host: The host to send requests to.
+ auth_function: A function that takes no arguments and returns an
+ (email, password) tuple when called. Will be called if authentication
+ is required.
+ host_override: The host header to send to the server (defaults to host).
+ extra_headers: A dict of extra headers to append to every request.
+ save_cookies: If True, save the authentication cookies to local disk.
+ If False, use an in-memory cookiejar instead. Subclasses must
+ implement this functionality. Defaults to False.
+ """
+ self.host = host
+ self.host_override = host_override
+ self.auth_function = auth_function
+ self.authenticated = False
+ self.extra_headers = extra_headers
+ self.save_cookies = save_cookies
+ self.opener = self._GetOpener()
+ if self.host_override:
+ logging.info("Server: %s; Host: %s", self.host, self.host_override)
+ else:
+ logging.info("Server: %s", self.host)
+
+ def _GetOpener(self):
+ """Returns an OpenerDirector for making HTTP requests.
+
+ Returns:
+ A urllib2.OpenerDirector object.
+ """
+ raise NotImplementedError()
+
+ def _CreateRequest(self, url, data=None):
+ """Creates a new urllib request."""
+ logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
+ req = urllib2.Request(url, data=data)
+ if self.host_override:
+ req.add_header("Host", self.host_override)
+ for key, value in self.extra_headers.iteritems():
+ req.add_header(key, value)
+ return req
+
+ def _GetAuthToken(self, email, password):
+ """Uses ClientLogin to authenticate the user, returning an auth token.
+
+ Args:
+ email: The user's email address
+ password: The user's password
+
+ Raises:
+ ClientLoginError: If there was an error authenticating with ClientLogin.
+ HTTPError: If there was some other form of HTTP error.
+
+ Returns:
+ The authentication token returned by ClientLogin.
+ """
+ account_type = "GOOGLE"
+ if self.host.endswith(".google.com"):
+ # Needed for use inside Google.
+ account_type = "HOSTED"
+ req = self._CreateRequest(
+ url="https://www.google.com/accounts/ClientLogin",
+ data=urllib.urlencode({
+ "Email": email,
+ "Passwd": password,
+ "service": "ah",
+ "source": "rietveld-codereview-upload",
+ "accountType": account_type,
+ }),
+ )
+ try:
+ response = self.opener.open(req)
+ response_body = response.read()
+ response_dict = dict(x.split("=")
+ for x in response_body.split("\n") if x)
+ return response_dict["Auth"]
+ except urllib2.HTTPError, e:
+ if e.code == 403:
+ body = e.read()
+ response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
+ raise ClientLoginError(req.get_full_url(), e.code, e.msg,
+ e.headers, response_dict)
+ else:
+ raise
+
+ def _GetAuthCookie(self, auth_token):
+ """Fetches authentication cookies for an authentication token.
+
+ Args:
+ auth_token: The authentication token returned by ClientLogin.
+
+ Raises:
+ HTTPError: If there was an error fetching the authentication cookies.
+ """
+ # This is a dummy value to allow us to identify when we're successful.
+ continue_location = "http://localhost/"
+ args = {"continue": continue_location, "auth": auth_token}
+ req = self._CreateRequest("http://%s/_ah/login?%s" %
+ (self.host, urllib.urlencode(args)))
+ try:
+ response = self.opener.open(req)
+ except urllib2.HTTPError, e:
+ response = e
+ if (response.code != 302 or
+ response.info()["location"] != continue_location):
+ raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
+ response.headers, response.fp)
+ self.authenticated = True
+
+ def _Authenticate(self):
+ """Authenticates the user.
+
+ The authentication process works as follows:
+ 1) We get a username and password from the user
+ 2) We use ClientLogin to obtain an AUTH token for the user
+ (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
+ 3) We pass the auth token to /_ah/login on the server to obtain an
+ authentication cookie. If login was successful, it tries to redirect
+ us to the URL we provided.
+
+ If we attempt to access the upload API without first obtaining an
+ authentication cookie, it returns a 401 response and directs us to
+ authenticate ourselves with ClientLogin.
+ """
+ for i in range(3):
+ credentials = self.auth_function()
+ try:
+ auth_token = self._GetAuthToken(credentials[0], credentials[1])
+ except ClientLoginError, e:
+ if e.reason == "BadAuthentication":
+ print >>sys.stderr, "Invalid username or password."
+ continue
+ if e.reason == "CaptchaRequired":
+ print >>sys.stderr, (
+ "Please go to\n"
+ "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
+ "and verify you are a human. Then try again.")
+ break
+ if e.reason == "NotVerified":
+ print >>sys.stderr, "Account not verified."
+ break
+ if e.reason == "TermsNotAgreed":
+ print >>sys.stderr, "User has not agreed to TOS."
+ break
+ if e.reason == "AccountDeleted":
+ print >>sys.stderr, "The user account has been deleted."
+ break
+ if e.reason == "AccountDisabled":
+ print >>sys.stderr, "The user account has been disabled."
+ break
+ if e.reason == "ServiceDisabled":
+ print >>sys.stderr, ("The user's access to the service has been "
+ "disabled.")
+ break
+ if e.reason == "ServiceUnavailable":
+ print >>sys.stderr, "The service is not available; try again later."
+ break
+ raise
+ self._GetAuthCookie(auth_token)
+ return
+
+ def Send(self, request_path, payload=None,
+ content_type="application/octet-stream",
+ timeout=None,
+ **kwargs):
+ """Sends an RPC and returns the response.
+
+ Args:
+ request_path: The path to send the request to, eg /api/appversion/create.
+ payload: The body of the request, or None to send an empty request.
+ content_type: The Content-Type header to use.
+ timeout: timeout in seconds; default None i.e. no timeout.
+ (Note: for large requests on OS X, the timeout doesn't work right.)
+ kwargs: Any keyword arguments are converted into query string parameters.
+
+ Returns:
+ The response body, as a string.
+ """
+ # TODO: Don't require authentication. Let the server say
+ # whether it is necessary.
+ if not self.authenticated:
+ self._Authenticate()
+
+ old_timeout = socket.getdefaulttimeout()
+ socket.setdefaulttimeout(timeout)
+ try:
+ tries = 0
+ while True:
+ tries += 1
+ args = dict(kwargs)
+ url = "http://%s%s" % (self.host, request_path)
+ if args:
+ url += "?" + urllib.urlencode(args)
+ req = self._CreateRequest(url=url, data=payload)
+ req.add_header("Content-Type", content_type)
+ try:
+ f = self.opener.open(req)
+ response = f.read()
+ f.close()
+ return response
+ except urllib2.HTTPError, e:
+ if tries > 3:
+ raise
+ elif e.code == 401:
+ self._Authenticate()
+## elif e.code >= 500 and e.code < 600:
+## # Server Error - try again.
+## continue
+ else:
+ raise
+ finally:
+ socket.setdefaulttimeout(old_timeout)
+
+
+class HttpRpcServer(AbstractRpcServer):
+ """Provides a simplified RPC-style interface for HTTP requests."""
+
+ def _Authenticate(self):
+ """Save the cookie jar after authentication."""
+ super(HttpRpcServer, self)._Authenticate()
+ if self.save_cookies:
+ StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
+ self.cookie_jar.save()
+
+ def _GetOpener(self):
+ """Returns an OpenerDirector that supports cookies and ignores redirects.
+
+ Returns:
+ A urllib2.OpenerDirector object.
+ """
+ opener = urllib2.OpenerDirector()
+ opener.add_handler(urllib2.ProxyHandler())
+ opener.add_handler(urllib2.UnknownHandler())
+ opener.add_handler(urllib2.HTTPHandler())
+ opener.add_handler(urllib2.HTTPDefaultErrorHandler())
+ opener.add_handler(urllib2.HTTPSHandler())
+ opener.add_handler(urllib2.HTTPErrorProcessor())
+ if self.save_cookies:
+ self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
+ self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
+ if os.path.exists(self.cookie_file):
+ try:
+ self.cookie_jar.load()
+ self.authenticated = True
+ StatusUpdate("Loaded authentication cookies from %s" %
+ self.cookie_file)
+ except (cookielib.LoadError, IOError):
+ # Failed to load cookies - just ignore them.
+ pass
+ else:
+ # Create an empty cookie file with mode 600
+ fd = os.open(self.cookie_file, os.O_CREAT, 0600)
+ os.close(fd)
+ # Always chmod the cookie file
+ os.chmod(self.cookie_file, 0600)
+ else:
+ # Don't save cookies across runs of update.py.
+ self.cookie_jar = cookielib.CookieJar()
+ opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
+ return opener
+
+
+parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]")
+parser.add_option("-y", "--assume_yes", action="store_true",
+ dest="assume_yes", default=False,
+ help="Assume that the answer to yes/no questions is 'yes'.")
+# Logging
+group = parser.add_option_group("Logging options")
+group.add_option("-q", "--quiet", action="store_const", const=0,
+ dest="verbose", help="Print errors only.")
+group.add_option("-v", "--verbose", action="store_const", const=2,
+ dest="verbose", default=1,
+ help="Print info level logs (default).")
+group.add_option("--noisy", action="store_const", const=3,
+ dest="verbose", help="Print all logs.")
+# Review server
+group = parser.add_option_group("Review server options")
+group.add_option("-s", "--server", action="store", dest="server",
+ default="codereview.appspot.com",
+ metavar="SERVER",
+ help=("The server to upload to. The format is host[:port]. "
+ "Defaults to 'codereview.appspot.com'."))
+group.add_option("-e", "--email", action="store", dest="email",
+ metavar="EMAIL", default=None,
+ help="The username to use. Will prompt if omitted.")
+group.add_option("-H", "--host", action="store", dest="host",
+ metavar="HOST", default=None,
+ help="Overrides the Host header sent with all RPCs.")
+group.add_option("--no_cookies", action="store_false",
+ dest="save_cookies", default=True,
+ help="Do not save authentication cookies to local disk.")
+# Issue
+group = parser.add_option_group("Issue options")
+group.add_option("-d", "--description", action="store", dest="description",
+ metavar="DESCRIPTION", default=None,
+ help="Optional description when creating an issue.")
+group.add_option("-f", "--description_file", action="store",
+ dest="description_file", metavar="DESCRIPTION_FILE",
+ default=None,
+ help="Optional path of a file that contains "
+ "the description when creating an issue.")
+group.add_option("-r", "--reviewers", action="store", dest="reviewers",
+ metavar="REVIEWERS", default=None,
+ help="Add reviewers (comma separated email addresses).")
+group.add_option("--cc", action="store", dest="cc",
+ metavar="CC", default=None,
+ help="Add CC (comma separated email addresses).")
+# Upload options
+group = parser.add_option_group("Patch options")
+group.add_option("-m", "--message", action="store", dest="message",
+ metavar="MESSAGE", default=None,
+ help="A message to identify the patch. "
+ "Will prompt if omitted.")
+group.add_option("-i", "--issue", type="int", action="store",
+ metavar="ISSUE", default=None,
+ help="Issue number to which to add. Defaults to new issue.")
+group.add_option("--download_base", action="store_true",
+ dest="download_base", default=False,
+ help="Base files will be downloaded by the server "
+ "(side-by-side diffs may not work on files with CRs).")
+group.add_option("--rev", action="store", dest="revision",
+ metavar="REV", default=None,
+ help="Branch/tree/revision to diff against (used by DVCS).")
+group.add_option("--send_mail", action="store_true",
+ dest="send_mail", default=False,
+ help="Send notification email to reviewers.")
+
+
+def GetRpcServer(options):
+ """Returns an instance of an AbstractRpcServer.
+
+ Returns:
+ A new AbstractRpcServer, on which RPC calls can be made.
+ """
+
+ rpc_server_class = HttpRpcServer
+
+ def GetUserCredentials():
+ """Prompts the user for a username and password."""
+ email = options.email
+ if email is None:
+ email = GetEmail("Email (login for uploading to %s)" % options.server)
+ password = getpass.getpass("Password for %s: " % email)
+ return (email, password)
+
+ # If this is the dev_appserver, use fake authentication.
+ host = (options.host or options.server).lower()
+ if host == "localhost" or host.startswith("localhost:"):
+ email = options.email
+ if email is None:
+ email = "test at example.com"
+ logging.info("Using debug user %s. Override with --email" % email)
+ server = rpc_server_class(
+ options.server,
+ lambda: (email, "password"),
+ host_override=options.host,
+ extra_headers={"Cookie":
+ 'dev_appserver_login="%s:False"' % email},
+ save_cookies=options.save_cookies)
+ # Don't try to talk to ClientLogin.
+ server.authenticated = True
+ return server
+
+ return rpc_server_class(options.server, GetUserCredentials,
+ host_override=options.host,
+ save_cookies=options.save_cookies)
+
+
+def EncodeMultipartFormData(fields, files):
+ """Encode form fields for multipart/form-data.
+
+ Args:
+ fields: A sequence of (name, value) elements for regular form fields.
+ files: A sequence of (name, filename, value) elements for data to be
+ uploaded as files.
+ Returns:
+ (content_type, body) ready for httplib.HTTP instance.
+
+ Source:
+ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
+ """
+ BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
+ CRLF = '\r\n'
+ lines = []
+ for (key, value) in fields:
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"' % key)
+ lines.append('')
+ lines.append(value)
+ for (key, filename, value) in files:
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
+ (key, filename))
+ lines.append('Content-Type: %s' % GetContentType(filename))
+ lines.append('')
+ lines.append(value)
+ lines.append('--' + BOUNDARY + '--')
+ lines.append('')
+ body = CRLF.join(lines)
+ content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+ return content_type, body
+
+
+def GetContentType(filename):
+ """Helper to guess the content-type from the filename."""
+ return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+
+
+# Use a shell for subcommands on Windows to get a PATH search.
+use_shell = sys.platform.startswith("win")
+
+def RunShellWithReturnCode(command, print_output=False,
+ universal_newlines=True):
+ """Executes a command and returns the output from stdout and the return code.
+
+ Args:
+ command: Command to execute.
+ print_output: If True, the output is printed to stdout.
+ If False, both stdout and stderr are ignored.
+ universal_newlines: Use universal_newlines flag (default: True).
+
+ Returns:
+ Tuple (output, return code)
+ """
+ logging.info("Running %s", command)
+ p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ shell=use_shell, universal_newlines=universal_newlines)
+ if print_output:
+ output_array = []
+ while True:
+ line = p.stdout.readline()
+ if not line:
+ break
+ print line.strip("\n")
+ output_array.append(line)
+ output = "".join(output_array)
+ else:
+ output = p.stdout.read()
+ p.wait()
+ errout = p.stderr.read()
+ if print_output and errout:
+ print >>sys.stderr, errout
+ p.stdout.close()
+ p.stderr.close()
+ return output, p.returncode
+
+
+def RunShell(command, silent_ok=False, universal_newlines=True,
+ print_output=False):
+ data, retcode = RunShellWithReturnCode(command, print_output,
+ universal_newlines)
+ if retcode:
+ ErrorExit("Got error status from %s:\n%s" % (command, data))
+ if not silent_ok and not data:
+ ErrorExit("No output from %s" % command)
+ return data
+
+
+class VersionControlSystem(object):
+ """Abstract base class providing an interface to the VCS."""
+
+ def __init__(self, options):
+ """Constructor.
+
+ Args:
+ options: Command line options.
+ """
+ self.options = options
+
+ def GenerateDiff(self, args):
+ """Return the current diff as a string.
+
+ Args:
+ args: Extra arguments to pass to the diff command.
+ """
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ def GetUnknownFiles(self):
+ """Return a list of files unknown to the VCS."""
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ def CheckForUnknownFiles(self):
+ """Show an "are you sure?" prompt if there are unknown files."""
+ unknown_files = self.GetUnknownFiles()
+ if unknown_files:
+ print "The following files are not added to version control:"
+ for line in unknown_files:
+ print line
+ prompt = "Are you sure to continue?(y/N) "
+ answer = raw_input(prompt).strip()
+ if answer != "y":
+ ErrorExit("User aborted")
+
+ def GetBaseFile(self, filename):
+ """Get the content of the upstream version of a file.
+
+ Returns:
+ A tuple (base_content, new_content, is_binary, status)
+ base_content: The contents of the base file.
+ new_content: For text files, this is empty. For binary files, this is
+ the contents of the new file, since the diff output won't contain
+ information to reconstruct the current file.
+ is_binary: True iff the file is binary.
+ status: The status of the file.
+ """
+
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+
+ def GetBaseFiles(self, diff):
+ """Helper that calls GetBase file for each file in the patch.
+
+ Returns:
+ A dictionary that maps from filename to GetBaseFile's tuple. Filenames
+ are retrieved based on lines that start with "Index:" or
+ "Property changes on:".
+ """
+ files = {}
+ for line in diff.splitlines(True):
+ if line.startswith('Index:') or line.startswith('Property changes on:'):
+ unused, filename = line.split(':', 1)
+ # On Windows if a file has property changes its filename uses '\'
+ # instead of '/'.
+ filename = filename.strip().replace('\\', '/')
+ files[filename] = self.GetBaseFile(filename)
+ return files
+
+
+ def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
+ files):
+ """Uploads the base files (and if necessary, the current ones as well)."""
+
+ def UploadFile(filename, file_id, content, is_binary, status, is_base):
+ """Uploads a file to the server."""
+ file_too_large = False
+ if is_base:
+ type = "base"
+ else:
+ type = "current"
+ if len(content) > MAX_UPLOAD_SIZE:
+ print ("Not uploading the %s file for %s because it's too large." %
+ (type, filename))
+ file_too_large = True
+ content = ""
+ checksum = md5.new(content).hexdigest()
+ if options.verbose > 0 and not file_too_large:
+ print "Uploading %s file for %s" % (type, filename)
+ url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
+ form_fields = [("filename", filename),
+ ("status", status),
+ ("checksum", checksum),
+ ("is_binary", str(is_binary)),
+ ("is_current", str(not is_base)),
+ ]
+ if file_too_large:
+ form_fields.append(("file_too_large", "1"))
+ if options.email:
+ form_fields.append(("user", options.email))
+ ctype, body = EncodeMultipartFormData(form_fields,
+ [("data", filename, content)])
+ response_body = rpc_server.Send(url, body,
+ content_type=ctype)
+ if not response_body.startswith("OK"):
+ StatusUpdate(" --> %s" % response_body)
+ sys.exit(1)
+
+ patches = dict()
+ [patches.setdefault(v, k) for k, v in patch_list]
+ for filename in patches.keys():
+ base_content, new_content, is_binary, status = files[filename]
+ file_id_str = patches.get(filename)
+ if file_id_str.find("nobase") != -1:
+ base_content = None
+ file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
+ file_id = int(file_id_str)
+ if base_content != None:
+ UploadFile(filename, file_id, base_content, is_binary, status, True)
+ if new_content != None:
+ UploadFile(filename, file_id, new_content, is_binary, status, False)
+
+ def IsImage(self, filename):
+ """Returns true if the filename has an image extension."""
+ mimetype = mimetypes.guess_type(filename)[0]
+ if not mimetype:
+ return False
+ return mimetype.startswith("image/")
+
+
+class SubversionVCS(VersionControlSystem):
+ """Implementation of the VersionControlSystem interface for Subversion."""
+
+ def __init__(self, options):
+ super(SubversionVCS, self).__init__(options)
+ if self.options.revision:
+ match = re.match(r"(\d+)(:(\d+))?", self.options.revision)
+ if not match:
+ ErrorExit("Invalid Subversion revision %s." % self.options.revision)
+ self.rev_start = match.group(1)
+ self.rev_end = match.group(3)
+ else:
+ self.rev_start = self.rev_end = None
+ # Cache output from "svn list -r REVNO dirname".
+ # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
+ self.svnls_cache = {}
+ # SVN base URL is required to fetch files deleted in an older revision.
+ # Result is cached to not guess it over and over again in GetBaseFile().
+ required = self.options.download_base or self.options.revision is not None
+ self.svn_base = self._GuessBase(required)
+
+ def GuessBase(self, required):
+ """Wrapper for _GuessBase."""
+ return self.svn_base
+
+ def _GuessBase(self, required):
+ """Returns the SVN base URL.
+
+ Args:
+ required: If true, exits if the url can't be guessed, otherwise None is
+ returned.
+ """
+ info = RunShell(["svn", "info"])
+ for line in info.splitlines():
+ words = line.split()
+ if len(words) == 2 and words[0] == "URL:":
+ url = words[1]
+ scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
+ username, netloc = urllib.splituser(netloc)
+ if username:
+ logging.info("Removed username from base URL")
+ if netloc.endswith("svn.python.org"):
+ if netloc == "svn.python.org":
+ if path.startswith("/projects/"):
+ path = path[9:]
+ elif netloc != "pythondev at svn.python.org":
+ ErrorExit("Unrecognized Python URL: %s" % url)
+ base = "http://svn.python.org/view/*checkout*%s/" % path
+ logging.info("Guessed Python base = %s", base)
+ elif netloc.endswith("svn.collab.net"):
+ if path.startswith("/repos/"):
+ path = path[6:]
+ base = "http://svn.collab.net/viewvc/*checkout*%s/" % path
+ logging.info("Guessed CollabNet base = %s", base)
+ elif netloc.endswith(".googlecode.com"):
+ path = path + "/"
+ base = urlparse.urlunparse(("http", netloc, path, params,
+ query, fragment))
+ logging.info("Guessed Google Code base = %s", base)
+ else:
+ path = path + "/"
+ base = urlparse.urlunparse((scheme, netloc, path, params,
+ query, fragment))
+ logging.info("Guessed base = %s", base)
+ return base
+ if required:
+ ErrorExit("Can't find URL in output from svn info")
+ return None
+
+ def GenerateDiff(self, args):
+ cmd = ["svn", "diff"]
+ if self.options.revision:
+ cmd += ["-r", self.options.revision]
+ cmd.extend(args)
+ data = RunShell(cmd)
+ count = 0
+ for line in data.splitlines():
+ if line.startswith("Index:") or line.startswith("Property changes on:"):
+ count += 1
+ logging.info(line)
+ if not count:
+ ErrorExit("No valid patches found in output from svn diff")
+ return data
+
+ def _CollapseKeywords(self, content, keyword_str):
+ """Collapses SVN keywords."""
+ # svn cat translates keywords but svn diff doesn't. As a result of this
+ # behavior patching.PatchChunks() fails with a chunk mismatch error.
+ # This part was originally written by the Review Board development team
+ # who had the same problem (http://reviews.review-board.org/r/276/).
+ # Mapping of keywords to known aliases
+ svn_keywords = {
+ # Standard keywords
+ 'Date': ['Date', 'LastChangedDate'],
+ 'Revision': ['Revision', 'LastChangedRevision', 'Rev'],
+ 'Author': ['Author', 'LastChangedBy'],
+ 'HeadURL': ['HeadURL', 'URL'],
+ 'Id': ['Id'],
+
+ # Aliases
+ 'LastChangedDate': ['LastChangedDate', 'Date'],
+ 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'],
+ 'LastChangedBy': ['LastChangedBy', 'Author'],
+ 'URL': ['URL', 'HeadURL'],
+ }
+
+ def repl(m):
+ if m.group(2):
+ return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
+ return "$%s$" % m.group(1)
+ keywords = [keyword
+ for name in keyword_str.split(" ")
+ for keyword in svn_keywords.get(name, [])]
+ return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content)
+
+ def GetUnknownFiles(self):
+ status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True)
+ unknown_files = []
+ for line in status.split("\n"):
+ if line and line[0] == "?":
+ unknown_files.append(line)
+ return unknown_files
+
+ def ReadFile(self, filename):
+ """Returns the contents of a file."""
+ file = open(filename, 'rb')
+ result = ""
+ try:
+ result = file.read()
+ finally:
+ file.close()
+ return result
+
+ def GetStatus(self, filename):
+ """Returns the status of a file."""
+ if not self.options.revision:
+ status = RunShell(["svn", "status", "--ignore-externals", filename])
+ if not status:
+ ErrorExit("svn status returned no output for %s" % filename)
+ status_lines = status.splitlines()
+ # If file is in a cl, the output will begin with
+ # "\n--- Changelist 'cl_name':\n". See
+ # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
+ if (len(status_lines) == 3 and
+ not status_lines[0] and
+ status_lines[1].startswith("--- Changelist")):
+ status = status_lines[2]
+ else:
+ status = status_lines[0]
+ # If we have a revision to diff against we need to run "svn list"
+ # for the old and the new revision and compare the results to get
+ # the correct status for a file.
+ else:
+ dirname, relfilename = os.path.split(filename)
+ if dirname not in self.svnls_cache:
+ cmd = ["svn", "list", "-r", self.rev_start, dirname or "."]
+ out, returncode = RunShellWithReturnCode(cmd)
+ if returncode:
+ ErrorExit("Failed to get status for %s." % filename)
+ old_files = out.splitlines()
+ args = ["svn", "list"]
+ if self.rev_end:
+ args += ["-r", self.rev_end]
+ cmd = args + [dirname or "."]
+ out, returncode = RunShellWithReturnCode(cmd)
+ if returncode:
+ ErrorExit("Failed to run command %s" % cmd)
+ self.svnls_cache[dirname] = (old_files, out.splitlines())
+ old_files, new_files = self.svnls_cache[dirname]
+ if relfilename in old_files and relfilename not in new_files:
+ status = "D "
+ elif relfilename in old_files and relfilename in new_files:
+ status = "M "
+ else:
+ status = "A "
+ return status
+
+ def GetBaseFile(self, filename):
+ status = self.GetStatus(filename)
+ base_content = None
+ new_content = None
+
+ # If a file is copied its status will be "A +", which signifies
+ # "addition-with-history". See "svn st" for more information. We need to
+ # upload the original file or else diff parsing will fail if the file was
+ # edited.
+ if status[0] == "A" and status[3] != "+":
+ # We'll need to upload the new content if we're adding a binary file
+ # since diff's output won't contain it.
+ mimetype = RunShell(["svn", "propget", "svn:mime-type", filename],
+ silent_ok=True)
+ base_content = ""
+ is_binary = mimetype and not mimetype.startswith("text/")
+ if is_binary and self.IsImage(filename):
+ new_content = self.ReadFile(filename)
+ elif (status[0] in ("M", "D", "R") or
+ (status[0] == "A" and status[3] == "+") or # Copied file.
+ (status[0] == " " and status[1] == "M")): # Property change.
+ args = []
+ if self.options.revision:
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+ else:
+ # Don't change filename, it's needed later.
+ url = filename
+ args += ["-r", "BASE"]
+ cmd = ["svn"] + args + ["propget", "svn:mime-type", url]
+ mimetype, returncode = RunShellWithReturnCode(cmd)
+ if returncode:
+ # File does not exist in the requested revision.
+ # Reset mimetype, it contains an error message.
+ mimetype = ""
+ get_base = False
+ is_binary = mimetype and not mimetype.startswith("text/")
+ if status[0] == " ":
+ # Empty base content just to force an upload.
+ base_content = ""
+ elif is_binary:
+ if self.IsImage(filename):
+ get_base = True
+ if status[0] == "M":
+ if not self.rev_end:
+ new_content = self.ReadFile(filename)
+ else:
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end)
+ new_content = RunShell(["svn", "cat", url],
+ universal_newlines=True, silent_ok=True)
+ else:
+ base_content = ""
+ else:
+ get_base = True
+
+ if get_base:
+ if is_binary:
+ universal_newlines = False
+ else:
+ universal_newlines = True
+ if self.rev_start:
+ # "svn cat -r REV delete_file.txt" doesn't work. cat requires
+ # the full URL with "@REV" appended instead of using "-r" option.
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+ base_content = RunShell(["svn", "cat", url],
+ universal_newlines=universal_newlines,
+ silent_ok=True)
+ else:
+ base_content = RunShell(["svn", "cat", filename],
+ universal_newlines=universal_newlines,
+ silent_ok=True)
+ if not is_binary:
+ args = []
+ if self.rev_start:
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+ else:
+ url = filename
+ args += ["-r", "BASE"]
+ cmd = ["svn"] + args + ["propget", "svn:keywords", url]
+ keywords, returncode = RunShellWithReturnCode(cmd)
+ if keywords and not returncode:
+ base_content = self._CollapseKeywords(base_content, keywords)
+ else:
+ StatusUpdate("svn status returned unexpected output: %s" % status)
+ sys.exit(1)
+ return base_content, new_content, is_binary, status[0:5]
+
+
+class GitVCS(VersionControlSystem):
+ """Implementation of the VersionControlSystem interface for Git."""
+
+ def __init__(self, options):
+ super(GitVCS, self).__init__(options)
+ # Map of filename -> hash of base file.
+ self.base_hashes = {}
+
+ def GenerateDiff(self, extra_args):
+ # This is more complicated than svn's GenerateDiff because we must convert
+ # the diff output to include an svn-style "Index:" line as well as record
+ # the hashes of the base files, so we can upload them along with our diff.
+ if self.options.revision:
+ extra_args = [self.options.revision] + extra_args
+ gitdiff = RunShell(["git", "diff", "--full-index"] + extra_args)
+ svndiff = []
+ filecount = 0
+ filename = None
+ for line in gitdiff.splitlines():
+ match = re.match(r"diff --git a/(.*) b/.*$", line)
+ if match:
+ filecount += 1
+ filename = match.group(1)
+ svndiff.append("Index: %s\n" % filename)
+ else:
+ # The "index" line in a git diff looks like this (long hashes elided):
+ # index 82c0d44..b2cee3f 100755
+ # We want to save the left hash, as that identifies the base file.
+ match = re.match(r"index (\w+)\.\.", line)
+ if match:
+ self.base_hashes[filename] = match.group(1)
+ svndiff.append(line + "\n")
+ if not filecount:
+ ErrorExit("No valid patches found in output from git diff")
+ return "".join(svndiff)
+
+ def GetUnknownFiles(self):
+ status = RunShell(["git", "ls-files", "--exclude-standard", "--others"],
+ silent_ok=True)
+ return status.splitlines()
+
+ def GetBaseFile(self, filename):
+ hash = self.base_hashes[filename]
+ base_content = None
+ new_content = None
+ is_binary = False
+ if hash == "0" * 40: # All-zero hash indicates no base file.
+ status = "A"
+ base_content = ""
+ else:
+ status = "M"
+ base_content, returncode = RunShellWithReturnCode(["git", "show", hash])
+ if returncode:
+ ErrorExit("Got error status from 'git show %s'" % hash)
+ return (base_content, new_content, is_binary, status)
+
+
+class MercurialVCS(VersionControlSystem):
+ """Implementation of the VersionControlSystem interface for Mercurial."""
+
+ def __init__(self, options, repo_dir):
+ super(MercurialVCS, self).__init__(options)
+ # Absolute path to repository (we can be in a subdir)
+ self.repo_dir = os.path.normpath(repo_dir)
+ # Compute the subdir
+ cwd = os.path.normpath(os.getcwd())
+ assert cwd.startswith(self.repo_dir)
+ self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
+ if self.options.revision:
+ self.base_rev = self.options.revision
+ else:
+ self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip()
+
+ def _GetRelPath(self, filename):
+ """Get relative path of a file according to the current directory,
+ given its logical path in the repo."""
+ assert filename.startswith(self.subdir), filename
+ return filename[len(self.subdir):].lstrip(r"\/")
+
+ def GenerateDiff(self, extra_args):
+ # If no file specified, restrict to the current subdir
+ extra_args = extra_args or ["."]
+ cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
+ data = RunShell(cmd, silent_ok=True)
+ svndiff = []
+ filecount = 0
+ for line in data.splitlines():
+ m = re.match("diff --git a/(\S+) b/(\S+)", line)
+ if m:
+ # Modify line to make it look like as it comes from svn diff.
+ # With this modification no changes on the server side are required
+ # to make upload.py work with Mercurial repos.
+ # NOTE: for proper handling of moved/copied files, we have to use
+ # the second filename.
+ filename = m.group(2)
+ svndiff.append("Index: %s" % filename)
+ svndiff.append("=" * 67)
+ filecount += 1
+ logging.info(line)
+ else:
+ svndiff.append(line)
+ if not filecount:
+ ErrorExit("No valid patches found in output from hg diff")
+ return "\n".join(svndiff) + "\n"
+
+ def GetUnknownFiles(self):
+ """Return a list of files unknown to the VCS."""
+ args = []
+ status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
+ silent_ok=True)
+ unknown_files = []
+ for line in status.splitlines():
+ st, fn = line.split(" ", 1)
+ if st == "?":
+ unknown_files.append(fn)
+ return unknown_files
+
+ def GetBaseFile(self, filename):
+ # "hg status" and "hg cat" both take a path relative to the current subdir
+ # rather than to the repo root, but "hg diff" has given us the full path
+ # to the repo root.
+ base_content = ""
+ new_content = None
+ is_binary = False
+ oldrelpath = relpath = self._GetRelPath(filename)
+ # "hg status -C" returns two lines for moved/copied files, one otherwise
+ out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
+ out = out.splitlines()
+ # HACK: strip error message about missing file/directory if it isn't in
+ # the working copy
+ if out[0].startswith('%s: ' % relpath):
+ out = out[1:]
+ if len(out) > 1:
+ # Moved/copied => considered as modified, use old filename to
+ # retrieve base contents
+ oldrelpath = out[1].strip()
+ status = "M"
+ else:
+ status, _ = out[0].split(' ', 1)
+ if status != "A":
+ base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath],
+ silent_ok=True)
+ is_binary = "\0" in base_content # Mercurial's heuristic
+ if status != "R":
+ new_content = open(relpath, "rb").read()
+ is_binary = is_binary or "\0" in new_content
+ if is_binary and base_content:
+ # Fetch again without converting newlines
+ base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath],
+ silent_ok=True, universal_newlines=False)
+ if not is_binary or not self.IsImage(relpath):
+ new_content = None
+ return base_content, new_content, is_binary, status
+
+
+# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync.
+def SplitPatch(data):
+ """Splits a patch into separate pieces for each file.
+
+ Args:
+ data: A string containing the output of svn diff.
+
+ Returns:
+ A list of 2-tuple (filename, text) where text is the svn diff output
+ pertaining to filename.
+ """
+ patches = []
+ filename = None
+ diff = []
+ for line in data.splitlines(True):
+ new_filename = None
+ if line.startswith('Index:'):
+ unused, new_filename = line.split(':', 1)
+ new_filename = new_filename.strip()
+ elif line.startswith('Property changes on:'):
+ unused, temp_filename = line.split(':', 1)
+ # When a file is modified, paths use '/' between directories, however
+ # when a property is modified '\' is used on Windows. Make them the same
+ # otherwise the file shows up twice.
+ temp_filename = temp_filename.strip().replace('\\', '/')
+ if temp_filename != filename:
+ # File has property changes but no modifications, create a new diff.
+ new_filename = temp_filename
+ if new_filename:
+ if filename and diff:
+ patches.append((filename, ''.join(diff)))
+ filename = new_filename
+ diff = [line]
+ continue
+ if diff is not None:
+ diff.append(line)
+ if filename and diff:
+ patches.append((filename, ''.join(diff)))
+ return patches
+
+
+def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
+ """Uploads a separate patch for each file in the diff output.
+
+ Returns a list of [patch_key, filename] for each file.
+ """
+ patches = SplitPatch(data)
+ rv = []
+ for patch in patches:
+ if len(patch[1]) > MAX_UPLOAD_SIZE:
+ print ("Not uploading the patch for " + patch[0] +
+ " because the file is too large.")
+ continue
+ form_fields = [("filename", patch[0])]
+ if not options.download_base:
+ form_fields.append(("content_upload", "1"))
+ files = [("data", "data.diff", patch[1])]
+ ctype, body = EncodeMultipartFormData(form_fields, files)
+ url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
+ print "Uploading patch for " + patch[0]
+ response_body = rpc_server.Send(url, body, content_type=ctype)
+ lines = response_body.splitlines()
+ if not lines or lines[0] != "OK":
+ StatusUpdate(" --> %s" % response_body)
+ sys.exit(1)
+ rv.append([lines[1], patch[0]])
+ return rv
+
+
+def GuessVCS(options):
+ """Helper to guess the version control system.
+
+ This examines the current directory, guesses which VersionControlSystem
+ we're using, and returns an instance of the appropriate class. Exit with an
+ error if we can't figure it out.
+
+ Returns:
+ A VersionControlSystem instance. Exits if the VCS can't be guessed.
+ """
+ # Mercurial has a command to get the base directory of a repository
+ # Try running it, but don't die if we don't have hg installed.
+ # NOTE: we try Mercurial first as it can sit on top of an SVN working copy.
+ try:
+ out, returncode = RunShellWithReturnCode(["hg", "root"])
+ if returncode == 0:
+ return MercurialVCS(options, out.strip())
+ except OSError, (errno, message):
+ if errno != 2: # ENOENT -- they don't have hg installed.
+ raise
+
+ # Subversion has a .svn in all working directories.
+ if os.path.isdir('.svn'):
+ logging.info("Guessed VCS = Subversion")
+ return SubversionVCS(options)
+
+ # Git has a command to test if you're in a git tree.
+ # Try running it, but don't die if we don't have git installed.
+ try:
+ out, returncode = RunShellWithReturnCode(["git", "rev-parse",
+ "--is-inside-work-tree"])
+ if returncode == 0:
+ return GitVCS(options)
+ except OSError, (errno, message):
+ if errno != 2: # ENOENT -- they don't have git installed.
+ raise
+
+ ErrorExit(("Could not guess version control system. "
+ "Are you in a working copy directory?"))
+
+
+def RealMain(argv, data=None):
+ """The real main function.
+
+ Args:
+ argv: Command line arguments.
+ data: Diff contents. If None (default) the diff is generated by
+ the VersionControlSystem implementation returned by GuessVCS().
+
+ Returns:
+ A 2-tuple (issue id, patchset id).
+ The patchset id is None if the base files are not uploaded by this
+ script (applies only to SVN checkouts).
+ """
+ logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
+ "%(lineno)s %(message)s "))
+ os.environ['LC_ALL'] = 'C'
+ options, args = parser.parse_args(argv[1:])
+ global verbosity
+ verbosity = options.verbose
+ if verbosity >= 3:
+ logging.getLogger().setLevel(logging.DEBUG)
+ elif verbosity >= 2:
+ logging.getLogger().setLevel(logging.INFO)
+ vcs = GuessVCS(options)
+ if isinstance(vcs, SubversionVCS):
+ # base field is only allowed for Subversion.
+ # Note: Fetching base files may become deprecated in future releases.
+ base = vcs.GuessBase(options.download_base)
+ else:
+ base = None
+ if not base and options.download_base:
+ options.download_base = True
+ logging.info("Enabled upload of base file")
+ if not options.assume_yes:
+ vcs.CheckForUnknownFiles()
+ if data is None:
+ data = vcs.GenerateDiff(args)
+ files = vcs.GetBaseFiles(data)
+ if verbosity >= 1:
+ print "Upload server:", options.server, "(change with -s/--server)"
+ if options.issue:
+ prompt = "Message describing this patch set: "
+ else:
+ prompt = "New issue subject: "
+ message = options.message or raw_input(prompt).strip()
+ if not message:
+ ErrorExit("A non-empty message is required")
+ rpc_server = GetRpcServer(options)
+ form_fields = [("subject", message)]
+ if base:
+ form_fields.append(("base", base))
+ if options.issue:
+ form_fields.append(("issue", str(options.issue)))
+ if options.email:
+ form_fields.append(("user", options.email))
+ if options.reviewers:
+ for reviewer in options.reviewers.split(','):
+ if "@" in reviewer and not reviewer.split("@")[1].count(".") == 1:
+ ErrorExit("Invalid email address: %s" % reviewer)
+ form_fields.append(("reviewers", options.reviewers))
+ if options.cc:
+ for cc in options.cc.split(','):
+ if "@" in cc and not cc.split("@")[1].count(".") == 1:
+ ErrorExit("Invalid email address: %s" % cc)
+ form_fields.append(("cc", options.cc))
+ description = options.description
+ if options.description_file:
+ if options.description:
+ ErrorExit("Can't specify description and description_file")
+ file = open(options.description_file, 'r')
+ description = file.read()
+ file.close()
+ if description:
+ form_fields.append(("description", description))
+ # Send a hash of all the base file so the server can determine if a copy
+ # already exists in an earlier patchset.
+ base_hashes = ""
+ for file, info in files.iteritems():
+ if not info[0] is None:
+ checksum = md5.new(info[0]).hexdigest()
+ if base_hashes:
+ base_hashes += "|"
+ base_hashes += checksum + ":" + file
+ form_fields.append(("base_hashes", base_hashes))
+ # If we're uploading base files, don't send the email before the uploads, so
+ # that it contains the file status.
+ if options.send_mail and options.download_base:
+ form_fields.append(("send_mail", "1"))
+ if not options.download_base:
+ form_fields.append(("content_upload", "1"))
+ if len(data) > MAX_UPLOAD_SIZE:
+ print "Patch is large, so uploading file patches separately."
+ uploaded_diff_file = []
+ form_fields.append(("separate_patches", "1"))
+ else:
+ uploaded_diff_file = [("data", "data.diff", data)]
+ ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
+ response_body = rpc_server.Send("/upload", body, content_type=ctype)
+ patchset = None
+ if not options.download_base or not uploaded_diff_file:
+ lines = response_body.splitlines()
+ if len(lines) >= 2:
+ msg = lines[0]
+ patchset = lines[1].strip()
+ patches = [x.split(" ", 1) for x in lines[2:]]
+ else:
+ msg = response_body
+ else:
+ msg = response_body
+ StatusUpdate(msg)
+ if not response_body.startswith("Issue created.") and \
+ not response_body.startswith("Issue updated."):
+ sys.exit(0)
+ issue = msg[msg.rfind("/")+1:]
+
+ if not uploaded_diff_file:
+ result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
+ if not options.download_base:
+ patches = result
+
+ if not options.download_base:
+ vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files)
+ if options.send_mail:
+ rpc_server.Send("/" + issue + "/mail", payload="")
+ return issue, patchset
+
+
+def main():
+ try:
+ RealMain(sys.argv)
+ except KeyboardInterrupt:
+ print
+ StatusUpdate("Interrupted.")
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/external/gtest-1.6.0/scripts/upload_gtest.py b/external/gtest-1.6.0/scripts/upload_gtest.py
new file mode 100755
index 0000000..be19ae8
--- /dev/null
+++ b/external/gtest-1.6.0/scripts/upload_gtest.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""upload_gtest.py v0.1.0 -- uploads a Google Test patch for review.
+
+This simple wrapper passes all command line flags and
+--cc=googletestframework at googlegroups.com to upload.py.
+
+USAGE: upload_gtest.py [options for upload.py]
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import sys
+
+CC_FLAG = '--cc='
+GTEST_GROUP = 'googletestframework at googlegroups.com'
+
+
+def main():
+ # Finds the path to upload.py, assuming it is in the same directory
+ # as this file.
+ my_dir = os.path.dirname(os.path.abspath(__file__))
+ upload_py_path = os.path.join(my_dir, 'upload.py')
+
+ # Adds Google Test discussion group to the cc line if it's not there
+ # already.
+ upload_py_argv = [upload_py_path]
+ found_cc_flag = False
+ for arg in sys.argv[1:]:
+ if arg.startswith(CC_FLAG):
+ found_cc_flag = True
+ cc_line = arg[len(CC_FLAG):]
+ cc_list = [addr for addr in cc_line.split(',') if addr]
+ if GTEST_GROUP not in cc_list:
+ cc_list.append(GTEST_GROUP)
+ upload_py_argv.append(CC_FLAG + ','.join(cc_list))
+ else:
+ upload_py_argv.append(arg)
+
+ if not found_cc_flag:
+ upload_py_argv.append(CC_FLAG + GTEST_GROUP)
+
+ # Invokes upload.py with the modified command line flags.
+ os.execv(upload_py_path, upload_py_argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/external/gtest-1.6.0/src/gtest-all.cc b/external/gtest-1.6.0/src/gtest-all.cc
new file mode 100644
index 0000000..0a9cee5
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-all.cc
@@ -0,0 +1,48 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule at google.com (Markus Heule)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#include "gtest/gtest.h"
+
+// The following lines pull in the real gtest *.cc files.
+#include "src/gtest.cc"
+#include "src/gtest-death-test.cc"
+#include "src/gtest-filepath.cc"
+#include "src/gtest-port.cc"
+#include "src/gtest-printers.cc"
+#include "src/gtest-test-part.cc"
+#include "src/gtest-typed-test.cc"
diff --git a/external/gtest-1.6.0/src/gtest-death-test.cc b/external/gtest-1.6.0/src/gtest-death-test.cc
new file mode 100644
index 0000000..8b55f97
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-death-test.cc
@@ -0,0 +1,1388 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan), vladl at google.com (Vlad Losev)
+//
+// This file implements death tests.
+
+#include "gtest/gtest-death-test.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_OS_MAC
+# include <crt_externs.h>
+# endif // GTEST_OS_MAC
+
+# include <errno.h>
+# include <fcntl.h>
+# include <limits.h>
+
+# if GTEST_OS_LINUX
+# include <signal.h>
+# endif // GTEST_OS_LINUX
+
+# include <stdarg.h>
+
+# if GTEST_OS_WINDOWS
+# include <windows.h>
+# else
+# include <sys/mman.h>
+# include <sys/wait.h>
+# endif // GTEST_OS_WINDOWS
+
+# if GTEST_OS_QNX
+# include <spawn.h>
+# endif // GTEST_OS_QNX
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-string.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+ death_test_style,
+ internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+ "Indicates how to run a death test in a forked child process: "
+ "\"threadsafe\" (child process re-executes the test binary "
+ "from the beginning, running only the specific death test) or "
+ "\"fast\" (child process runs the death test immediately "
+ "after forking).");
+
+GTEST_DEFINE_bool_(
+ death_test_use_fork,
+ internal::BoolFromGTestEnv("death_test_use_fork", false),
+ "Instructs to use fork()/_exit() instead of clone() in death tests. "
+ "Ignored and always uses fork() on POSIX systems where clone() is not "
+ "implemented. Useful when running under valgrind or similar tools if "
+ "those do not support clone(). Valgrind 3.3.1 will just fail if "
+ "it sees an unsupported combination of clone() flags. "
+ "It is not recommended to use this flag w/o valgrind though it will "
+ "work in 99% of the cases. Once valgrind is fixed, this flag will "
+ "most likely be removed.");
+
+namespace internal
+{
+GTEST_DEFINE_string_(
+ internal_run_death_test, "",
+ "Indicates the file, line number, temporal index of "
+ "the single death test to run, and a file descriptor to "
+ "which a success code may be sent, all separated by "
+ "the '|' characters. This flag is specified if and only if the current "
+ "process is a sub-process launched for running a thread-safe "
+ "death test. FOR INTERNAL USE ONLY.");
+} // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal
+{
+
+// Valid only for fast death tests. Indicates the code is running in the
+// child process of a fast style death test.
+static bool g_in_fast_death_test_child = false;
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process. Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests. IMPORTANT: This is an internal utility. Using it may break the
+// implementation of death tests. User code MUST NOT use it.
+bool InDeathTestChild()
+{
+# if GTEST_OS_WINDOWS
+
+ // On Windows, death tests are thread-safe regardless of the value of the
+ // death_test_style flag.
+ return !GTEST_FLAG(internal_run_death_test).empty();
+
+# else
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe")
+ return !GTEST_FLAG(internal_run_death_test).empty();
+ else
+ return g_in_fast_death_test_child;
+#endif
+}
+
+} // namespace internal
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code)
+{
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const
+{
+# if GTEST_OS_WINDOWS
+
+ return exit_status == exit_code_;
+
+# else
+
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+
+# endif // GTEST_OS_WINDOWS
+}
+
+# if !GTEST_OS_WINDOWS
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum)
+{
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const
+{
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+# endif // !GTEST_OS_WINDOWS
+
+namespace internal
+{
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static std::string ExitSummary(int exit_code)
+{
+ Message m;
+
+# if GTEST_OS_WINDOWS
+
+ m << "Exited with exit status " << exit_code;
+
+# else
+
+ if (WIFEXITED(exit_code)) {
+ m << "Exited with exit status " << WEXITSTATUS(exit_code);
+ } else if (WIFSIGNALED(exit_code)) {
+ m << "Terminated by signal " << WTERMSIG(exit_code);
+ }
+# ifdef WCOREDUMP
+ if (WCOREDUMP(exit_code)) {
+ m << " (core dumped)";
+ }
+# endif
+# endif // GTEST_OS_WINDOWS
+
+ return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status)
+{
+ return !ExitedWithCode(0)(exit_status);
+}
+
+# if !GTEST_OS_WINDOWS
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement. It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static std::string DeathTestThreadWarning(size_t thread_count)
+{
+ Message msg;
+ msg << "Death tests use fork(), which is unsafe particularly"
+ << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+ if (thread_count == 0)
+ msg << "couldn't detect the number of threads.";
+ else
+ msg << "detected " << thread_count << " threads.";
+ return msg.GetString();
+}
+# endif // !GTEST_OS_WINDOWS
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestThrew = 'T';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test can
+// conclude. DIED means that the process died while executing the test
+// code; LIVED means that process lived beyond the end of the test code;
+// RETURNED means that the test statement attempted to execute a return
+// statement, which is not allowed; THREW means that the test statement
+// returned control by throwing an exception. IN_PROGRESS means the test
+// has not yet concluded.
+// TODO(vladl at google.com): Unify names and possibly values for
+// AbortReason, DeathTestOutcome, and flag characters above.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process. Otherwise, the
+// message is simply printed to stderr. In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const std::string& message)
+{
+ // On a POSIX system, this function may be called from a threadsafe-style
+ // death test child process, which operates on a very small stack. Use
+ // the heap for any additional non-minuscule memory requirements.
+ const InternalRunDeathTestFlag* const flag =
+ GetUnitTestImpl()->internal_run_death_test_flag();
+ if (flag != NULL) {
+ FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+ fputc(kDeathTestInternalError, parent);
+ fprintf(parent, "%s", message.c_str());
+ fflush(parent);
+ _exit(1);
+ } else {
+ fprintf(stderr, "%s", message.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+# define GTEST_DEATH_TEST_CHECK_(expression) \
+ do { \
+ if (!::testing::internal::IsTrue(expression)) { \
+ DeathTestAbort( \
+ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
+ + ::testing::internal::StreamableToString(__LINE__) + ": " \
+ + #expression); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again. The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR. If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+ do { \
+ int gtest_retval; \
+ do { \
+ gtest_retval = (expression); \
+ } while (gtest_retval == -1 && errno == EINTR); \
+ if (gtest_retval == -1) { \
+ DeathTestAbort( \
+ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
+ + ::testing::internal::StreamableToString(__LINE__) + ": " \
+ + #expression + " != -1"); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+std::string GetLastErrnoDescription()
+{
+ return errno == 0 ? "" : posix::StrError(errno);
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd)
+{
+ Message error;
+ char buffer[256];
+ int num_read;
+
+ do {
+ while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ if (num_read == 0) {
+ GTEST_LOG_(FATAL) << error.GetString();
+ } else {
+ const int last_error = errno;
+ GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+ << GetLastErrnoDescription() << " [" << last_error << "]";
+ }
+}
+
+// Death test constructor. Increments the running death test count
+// for the current test.
+DeathTest::DeathTest()
+{
+ TestInfo* const info = GetUnitTestImpl()->current_test_info();
+ if (info == NULL) {
+ DeathTestAbort("Cannot run a death test outside of a TEST or "
+ "TEST_F construct");
+ }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test)
+{
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage()
+{
+ return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const std::string& message)
+{
+ last_death_test_message_ = message;
+}
+
+std::string DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest
+{
+ protected:
+ DeathTestImpl(const char* a_statement, const RE* a_regex)
+ : statement_(a_statement),
+ regex_(a_regex),
+ spawned_(false),
+ status_(-1),
+ outcome_(IN_PROGRESS),
+ read_fd_(-1),
+ write_fd_(-1) {}
+
+ // read_fd_ is expected to be closed and cleared by a derived class.
+ ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+ void Abort(AbortReason reason);
+ virtual bool Passed(bool status_ok);
+
+ const char* statement() const { return statement_; }
+ const RE* regex() const { return regex_; }
+ bool spawned() const { return spawned_; }
+ void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
+ int status() const { return status_; }
+ void set_status(int a_status) { status_ = a_status; }
+ DeathTestOutcome outcome() const { return outcome_; }
+ void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+ int read_fd() const { return read_fd_; }
+ void set_read_fd(int fd) { read_fd_ = fd; }
+ int write_fd() const { return write_fd_; }
+ void set_write_fd(int fd) { write_fd_ = fd; }
+
+ // Called in the parent process only. Reads the result code of the death
+ // test child process via a pipe, interprets it to set the outcome_
+ // member, and closes read_fd_. Outputs diagnostics and terminates in
+ // case of unexpected codes.
+ void ReadAndInterpretStatusByte();
+
+ private:
+ // The textual content of the code this object is testing. This class
+ // doesn't own this string and should not attempt to delete it.
+ const char* const statement_;
+ // The regular expression which test output must match. DeathTestImpl
+ // doesn't own this object and should not attempt to delete it.
+ const RE* const regex_;
+ // True if the death test child process has been successfully spawned.
+ bool spawned_;
+ // The exit status of the child process.
+ int status_;
+ // How the death test concluded.
+ DeathTestOutcome outcome_;
+ // Descriptor to the read end of the pipe to the child process. It is
+ // always -1 in the child process. The child keeps its write end of the
+ // pipe in write_fd_.
+ int read_fd_;
+ // Descriptor to the child's write end of the pipe to the parent process.
+ // It is always -1 in the parent process. The parent keeps its end of the
+ // pipe in read_fd_.
+ int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_. Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte()
+{
+ char flag;
+ int bytes_read;
+
+ // The read() here blocks until data is available (signifying the
+ // failure of the death test) or until the pipe is closed (signifying
+ // its success), so it's okay to call this in the parent before
+ // the child process has exited.
+ do {
+ bytes_read = posix::Read(read_fd(), &flag, 1);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0) {
+ set_outcome(DIED);
+ } else if (bytes_read == 1) {
+ switch (flag) {
+ case kDeathTestReturned:
+ set_outcome(RETURNED);
+ break;
+ case kDeathTestThrew:
+ set_outcome(THREW);
+ break;
+ case kDeathTestLived:
+ set_outcome(LIVED);
+ break;
+ case kDeathTestInternalError:
+ FailFromInternalError(read_fd()); // Does not return.
+ break;
+ default:
+ GTEST_LOG_(FATAL) << "Death test child process reported "
+ << "unexpected status byte ("
+ << static_cast<unsigned int>(flag) << ")";
+ }
+ } else {
+ GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+ << GetLastErrnoDescription();
+ }
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+ set_read_fd(-1);
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason)
+{
+ // The parent process considers the death test to be a failure if
+ // it finds any data in our pipe. So, here we write a single flag byte
+ // to the pipe, then exit.
+ const char status_ch =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived :
+ reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;
+
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+ // We are leaking the descriptor here because on some platforms (i.e.,
+ // when built as Windows DLL), destructors of global objects will still
+ // run after calling _exit(). On such systems, write_fd_ will be
+ // indirectly closed from the destructor of UnitTestImpl, causing double
+ // close if it is also closed here. On debug configurations, double close
+ // may assert. As there are no in-process buffers to flush here, we are
+ // relying on the OS to close the descriptor after the process terminates
+ // when the destructors are not run.
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Returns an indented copy of stderr output for a death test.
+// This makes distinguishing death test output lines from regular log lines
+// much easier.
+static ::std::string FormatDeathTestOutput(const ::std::string& output)
+{
+ ::std::string ret;
+ for (size_t at = 0; ;) {
+ const size_t line_end = output.find('\n', at);
+ ret += "[ DEATH ] ";
+ if (line_end == ::std::string::npos) {
+ ret += output.substr(at);
+ break;
+ }
+ ret += output.substr(at, line_end + 1 - at);
+ at = line_end + 1;
+ }
+ return ret;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+// outcome: An enumeration describing how the death test
+// concluded: DIED, LIVED, THREW, or RETURNED. The death test
+// fails in the latter three cases.
+// status: The exit status of the child process. On *nix, it is in the
+// in the format specified by wait(2). On Windows, this is the
+// value supplied to the ExitProcess() API or a numeric code
+// of the exception that terminated the program.
+// regex: A regular expression object to be applied to
+// the test's captured standard error output; the death test
+// fails if it does not match.
+//
+// Argument:
+// status_ok: true if exit_status is acceptable in the context of
+// this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met. Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok)
+{
+ if (!spawned())
+ return false;
+
+ const std::string error_message = GetCapturedStderr();
+
+ bool success = false;
+ Message buffer;
+
+ buffer << "Death test: " << statement() << "\n";
+ switch (outcome()) {
+ case LIVED:
+ buffer << " Result: failed to die.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case THREW:
+ buffer << " Result: threw an exception.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case RETURNED:
+ buffer << " Result: illegal return in test statement.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case DIED:
+ if (status_ok) {
+ const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
+ if (matched) {
+ success = true;
+ } else {
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << regex()->pattern() << "\n"
+ << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ }
+ } else {
+ buffer << " Result: died but not with expected exit code:\n"
+ << " " << ExitSummary(status()) << "\n"
+ << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ }
+ break;
+ case IN_PROGRESS:
+ default:
+ GTEST_LOG_(FATAL)
+ << "DeathTest::Passed somehow called before conclusion of test";
+ }
+
+ DeathTest::set_last_death_test_message(buffer.GetString());
+ return success;
+}
+
+# if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes: Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+// ends of it.
+// 2. The parent starts the child and provides it with the information
+// necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+// using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+// this is done before step 3, the object's reference count goes down to
+// 0 and it is destroyed, preventing the child from acquiring it. The
+// parent now has to release it, or read operations on the read end of
+// the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+// any possible error messages) from the pipe, and its stderr and then
+// determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl
+{
+ public:
+ WindowsDeathTest(const char* a_statement,
+ const RE* a_regex,
+ const char* file,
+ int line)
+ : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual TestRole AssumeRole();
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+ // Handle to the write end of the pipe to the child process.
+ AutoHandle write_handle_;
+ // Child process handle.
+ AutoHandle child_handle_;
+ // Event the child process uses to signal the parent that it has
+ // acquired the handle to the write end of the pipe. After seeing this
+ // event the parent can release its own handles to make sure its
+ // ReadFile() calls return when the child terminates.
+ AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait()
+{
+ if (!spawned())
+ return 0;
+
+ // Wait until the child either signals that it has acquired the write end
+ // of the pipe or it dies.
+ const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+ switch (::WaitForMultipleObjects(2,
+ wait_handles,
+ FALSE, // Waits for any of the handles.
+ INFINITE)) {
+ case WAIT_OBJECT_0:
+ case WAIT_OBJECT_0 + 1:
+ break;
+ default:
+ GTEST_DEATH_TEST_CHECK_(false); // Should not get here.
+ }
+
+ // The child has acquired the write end of the pipe or exited.
+ // We release the handle on our side and continue.
+ write_handle_.Reset();
+ event_handle_.Reset();
+
+ ReadAndInterpretStatusByte();
+
+ // Waits for the child process to exit if it haven't already. This
+ // returns immediately if the child has already exited, regardless of
+ // whether previous calls to WaitForMultipleObjects synchronized on this
+ // handle or not.
+ GTEST_DEATH_TEST_CHECK_(
+ WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+ INFINITE));
+ DWORD status_code;
+ GTEST_DEATH_TEST_CHECK_(
+ ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE);
+ child_handle_.Reset();
+ set_status(static_cast<int>(status_code));
+ return status();
+}
+
+// The AssumeRole process for a Windows death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole()
+{
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ // WindowsDeathTest uses an anonymous pipe to communicate results of
+ // a death test.
+ SECURITY_ATTRIBUTES handles_are_inheritable = {
+ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE
+ };
+ HANDLE read_handle, write_handle;
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+ 0) // Default buffer size.
+ != FALSE);
+ set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+ O_RDONLY));
+ write_handle_.Reset(write_handle);
+ event_handle_.Reset(::CreateEvent(
+ &handles_are_inheritable,
+ TRUE, // The event will automatically reset to non-signaled state.
+ FALSE, // The initial state is non-signalled.
+ NULL)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
+ const std::string filter_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
+ info->test_case_name() + "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
+ "=" + file_ + "|" + StreamableToString(line_) + "|" +
+ StreamableToString(death_test_index) + "|" +
+ StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
+ // size_t has the same width as pointers on both 32-bit and 64-bit
+ // Windows platforms.
+ // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+ "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
+ "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
+
+ char executable_path[_MAX_PATH + 1]; // NOLINT
+ GTEST_DEATH_TEST_CHECK_(
+ _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
+ executable_path,
+ _MAX_PATH));
+
+ std::string command_line =
+ std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
+ internal_flag + "\"";
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // The child process will share the standard handles with the parent.
+ STARTUPINFOA startup_info;
+ memset(&startup_info, 0, sizeof(STARTUPINFO));
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+ startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+ PROCESS_INFORMATION process_info;
+ GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
+ executable_path,
+ const_cast<char*>(command_line.c_str()),
+ NULL, // Retuned process handle is not inheritable.
+ NULL, // Retuned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ NULL, // Inherit the parent's environment.
+ UnitTest::GetInstance()->original_working_dir(),
+ &startup_info,
+ &process_info) != FALSE);
+ child_handle_.Reset(process_info.hProcess);
+ ::CloseHandle(process_info.hThread);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+# else // We are not on Windows.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface. Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl
+{
+ public:
+ ForkingDeathTest(const char* statement, const RE* regex);
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+
+ protected:
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
+ : DeathTestImpl(a_statement, a_regex),
+ child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait()
+{
+ if (!spawned())
+ return 0;
+
+ ReadAndInterpretStatusByte();
+
+ int status_value;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+ set_status(status_value);
+ return status_value;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest
+{
+ public:
+ NoExecDeathTest(const char* a_statement, const RE* a_regex) :
+ ForkingDeathTest(a_statement, a_regex) { }
+ virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test. It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole()
+{
+ const size_t thread_count = GetThreadCount();
+ if (thread_count != 1) {
+ GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+ DeathTest::set_last_death_test_message("");
+ CaptureStderr();
+ // When we fork the process below, the log file buffers are copied, but the
+ // file descriptors are shared. We flush all log files here so that closing
+ // the file descriptors in the child process doesn't throw off the
+ // synchronization between descriptors and buffers in the parent process.
+ // This is as close to the fork as possible to avoid a race condition in case
+ // there are multiple threads running before the death test, and another
+ // thread writes to the log file.
+ FlushInfoLog();
+
+ const pid_t child_pid = fork();
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ set_child_pid(child_pid);
+ if (child_pid == 0) {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+ set_write_fd(pipe_fd[1]);
+ // Redirects all logging to stderr in the child process to prevent
+ // concurrent writes to the log files. We capture stderr in the parent
+ // process and append the child process' output to a log.
+ LogToStderr();
+ // Event forwarding to the listeners of event listener API mush be shut
+ // down in death test subprocesses.
+ GetUnitTestImpl()->listeners()->SuppressEventForwarding();
+ g_in_fast_death_test_child = true;
+ return EXECUTE_TEST;
+ } else {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+ }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest
+{
+ public:
+ ExecDeathTest(const char* a_statement, const RE* a_regex,
+ const char* file, int line) :
+ ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
+ virtual TestRole AssumeRole();
+ private:
+ static ::std::vector<testing::internal::string>
+ GetArgvsForDeathTestChildProcess() {
+ ::std::vector<testing::internal::string> args = GetInjectableArgvs();
+ return args;
+ }
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments
+{
+ public:
+ Arguments() {
+ args_.push_back(NULL);
+ }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+ char* const* argv; // Command-line arguments for the child's call to exec
+ int close_fd; // File descriptor to close; the read end of a pipe
+};
+
+# if GTEST_OS_MAC
+inline char** GetEnviron()
+{
+ // When Google Test is built as a framework on MacOS X, the environ variable
+ // is unavailable. Apple's documentation (man environ) recommends using
+ // _NSGetEnviron() instead.
+ return *_NSGetEnviron();
+}
+# else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+# endif // GTEST_OS_MAC
+
+# if !GTEST_OS_QNX
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg)
+{
+ ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+ GetLastErrnoDescription());
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execve() as it's a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // unsafe. Since execve() doesn't search the PATH, the user must
+ // invoke the test program via a valid path that contains at least
+ // one path separator.
+ execve(args->argv[0], args->argv, GetEnviron());
+ DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
+ original_dir + " failed: " +
+ GetLastErrnoDescription());
+ return EXIT_FAILURE;
+}
+# endif // !GTEST_OS_QNX
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+//
+// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
+// StackLowerThanAddress into StackGrowsDown, which then doesn't give
+// correct answer.
+void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
+void StackLowerThanAddress(const void* ptr, bool* result)
+{
+ int dummy;
+ *result = (&dummy < ptr);
+}
+
+bool StackGrowsDown()
+{
+ int dummy;
+ bool result;
+ StackLowerThanAddress(&dummy, &result);
+ return result;
+}
+
+// Spawns a child process with the same executable as the current process in
+// a thread-safe manner and instructs it to run the death test. The
+// implementation uses fork(2) + exec. On systems where clone(2) is
+// available, it is used instead, being slightly more thread-safe. On QNX,
+// fork supports only single-threaded environments, so this function uses
+// spawn(2) there instead. The function dies with an error message if
+// anything goes wrong.
+static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd)
+{
+ ExecDeathTestArgs args = { argv, close_fd };
+ pid_t child_pid = -1;
+
+# if GTEST_OS_QNX
+ // Obtains the current directory and sets it to be closed in the child
+ // process.
+ const int cwd_fd = open(".", O_RDONLY);
+ GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+ GetLastErrnoDescription());
+ return EXIT_FAILURE;
+ }
+
+ int fd_flags;
+ // Set close_fd to be closed after spawn.
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
+ fd_flags | FD_CLOEXEC));
+ struct inheritance inherit = {0};
+ // spawn is a system call.
+ child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
+ // Restores the current working directory.
+ GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
+
+# else // GTEST_OS_QNX
+# if GTEST_OS_LINUX
+ // When a SIGPROF signal is received while fork() or clone() are executing,
+ // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
+ // it after the call to fork()/clone() is complete.
+ struct sigaction saved_sigprof_action;
+ struct sigaction ignore_sigprof_action;
+ memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
+ sigemptyset(&ignore_sigprof_action.sa_mask);
+ ignore_sigprof_action.sa_handler = SIG_IGN;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
+ SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
+# endif // GTEST_OS_LINUX
+
+# if GTEST_HAS_CLONE
+ const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+ if (!use_fork) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const size_t stack_size = getpagesize();
+ // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+ void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+
+ // Maximum stack alignment in bytes: For a downward-growing stack, this
+ // amount is subtracted from size of the stack space to get an address
+ // that is within the stack space and is aligned on all systems we care
+ // about. As far as I know there is no ABI with stack alignment greater
+ // than 64. We assume stack and stack_size already have alignment of
+ // kMaxStackAlignment.
+ const size_t kMaxStackAlignment = 64;
+ void* const stack_top =
+ static_cast<char*>(stack) +
+ (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
+ GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
+ reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
+
+ child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+ GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+ }
+# else
+ const bool use_fork = true;
+# endif // GTEST_HAS_CLONE
+
+ if (use_fork && (child_pid = fork()) == 0) {
+ ExecDeathTestChildMain(&args);
+ _exit(0);
+ }
+# endif // GTEST_OS_QNX
+# if GTEST_OS_LINUX
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(
+ sigaction(SIGPROF, &saved_sigprof_action, NULL));
+# endif // GTEST_OS_LINUX
+
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test. It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole()
+{
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+ // Clear the close-on-exec flag on the write end of the pipe, lest
+ // it be closed when the child process does an exec:
+ GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+ const std::string filter_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
+ + info->test_case_name() + "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ + file_ + "|" + StreamableToString(line_) + "|"
+ + StreamableToString(death_test_index) + "|"
+ + StreamableToString(pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvsForDeathTestChildProcess());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // See the comment in NoExecDeathTest::AssumeRole for why the next line
+ // is necessary.
+ FlushInfoLog();
+
+ const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_child_pid(child_pid);
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+# endif // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address. If the test should be
+// skipped, sets that pointer to NULL. Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+ const char* file, int line,
+ DeathTest** test)
+{
+ UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const int death_test_index = impl->current_test_info()
+ ->increment_death_test_count();
+
+ if (flag != NULL) {
+ if (death_test_index > flag->index()) {
+ DeathTest::set_last_death_test_message(
+ "Death test count (" + StreamableToString(death_test_index)
+ + ") somehow exceeded expected maximum ("
+ + StreamableToString(flag->index()) + ")");
+ return false;
+ }
+
+ if (!(flag->file() == file && flag->line() == line &&
+ flag->index() == death_test_index)) {
+ *test = NULL;
+ return true;
+ }
+ }
+
+# if GTEST_OS_WINDOWS
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new WindowsDeathTest(statement, regex, file, line);
+ }
+
+# else
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, regex, file, line);
+ } else if (GTEST_FLAG(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, regex);
+ }
+
+# endif // GTEST_OS_WINDOWS
+
+ else { // NOLINT - this is more readable than unbalanced brackets inside #if.
+ DeathTest::set_last_death_test_message(
+ "Unknown death test style \"" + GTEST_FLAG(death_test_style)
+ + "\" encountered");
+ return false;
+ }
+
+ return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest)
+{
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (::testing::internal::AlwaysTrue()) {
+ const ::std::string::size_type colon = str.find(delimiter, pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
+# if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+int GetStatusFileDescriptor(unsigned int parent_process_id,
+ size_t write_handle_as_size_t,
+ size_t event_handle_as_size_t)
+{
+ AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+ FALSE, // Non-inheritable.
+ parent_process_id));
+ if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+ DeathTestAbort("Unable to open parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ // TODO(vladl at google.com): Replace the following check with a
+ // compile-time assertion when available.
+ GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+ const HANDLE write_handle =
+ reinterpret_cast<HANDLE>(write_handle_as_size_t);
+ HANDLE dup_write_handle;
+
+ // The newly initialized handle is accessible only in in the parent
+ // process. To obtain one accessible within the child, we need to use
+ // DuplicateHandle.
+ if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+ ::GetCurrentProcess(), &dup_write_handle,
+ 0x0, // Requested privileges ignored since
+ // DUPLICATE_SAME_ACCESS is used.
+ FALSE, // Request non-inheritable handler.
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort("Unable to duplicate the pipe handle " +
+ StreamableToString(write_handle_as_size_t) +
+ " from the parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+ HANDLE dup_event_handle;
+
+ if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+ ::GetCurrentProcess(), &dup_event_handle,
+ 0x0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort("Unable to duplicate the event handle " +
+ StreamableToString(event_handle_as_size_t) +
+ " from the parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ const int write_fd =
+ ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+ if (write_fd == -1) {
+ DeathTestAbort("Unable to convert pipe handle " +
+ StreamableToString(write_handle_as_size_t) +
+ " to a file descriptor");
+ }
+
+ // Signals the parent that the write end of the pipe has been acquired
+ // so the parent can release its own write end.
+ ::SetEvent(dup_event_handle);
+
+ return write_fd;
+}
+# endif // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag()
+{
+ if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ int line = -1;
+ int index = -1;
+ ::std::vector< ::std::string> fields;
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+ int write_fd = -1;
+
+# if GTEST_OS_WINDOWS
+
+ unsigned int parent_process_id = 0;
+ size_t write_handle_as_size_t = 0;
+ size_t event_handle_as_size_t = 0;
+
+ if (fields.size() != 6
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &parent_process_id)
+ || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+ || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
+ GTEST_FLAG(internal_run_death_test));
+ }
+ write_fd = GetStatusFileDescriptor(parent_process_id,
+ write_handle_as_size_t,
+ event_handle_as_size_t);
+# else
+
+ if (fields.size() != 4
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &write_fd)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+ + GTEST_FLAG(internal_run_death_test));
+ }
+
+# endif // GTEST_OS_WINDOWS
+
+ return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest-filepath.cc b/external/gtest-1.6.0/src/gtest-filepath.cc
new file mode 100644
index 0000000..527c3ff
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-filepath.cc
@@ -0,0 +1,402 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray at gmail.com (Keith Ray)
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-filepath.h"
+#include "gtest/internal/gtest-port.h"
+
+#include <stdlib.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>
+#elif GTEST_OS_WINDOWS
+# include <direct.h>
+# include <io.h>
+#elif GTEST_OS_SYMBIAN
+// Symbian OpenC has PATH_MAX in sys/syslimits.h
+# include <sys/syslimits.h>
+#else
+# include <limits.h>
+# include <climits> // Some Linux distributions define PATH_MAX here.
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+# define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif // GTEST_OS_WINDOWS
+
+#include "gtest/internal/gtest-string.h"
+
+namespace testing
+{
+namespace internal
+{
+
+#if GTEST_OS_WINDOWS
+// On Windows, '\\' is the standard path separator, but many tools and the
+// Windows API also accept '/' as an alternate path separator. Unless otherwise
+// noted, a file path can contain either kind of path separators, or a mixture
+// of them.
+const char kPathSeparator = '\\';
+const char kAlternatePathSeparator = '/';
+const char kPathSeparatorString[] = "\\";
+const char kAlternatePathSeparatorString[] = "/";
+# if GTEST_OS_WINDOWS_MOBILE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+# else
+const char kCurrentDirectoryString[] = ".\\";
+# endif // GTEST_OS_WINDOWS_MOBILE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif // GTEST_OS_WINDOWS
+
+// Returns whether the given character is a valid path separator.
+static bool IsPathSeparator(char c)
+{
+#if GTEST_HAS_ALT_PATH_SEP_
+ return (c == kPathSeparator) || (c == kAlternatePathSeparator);
+#else
+ return c == kPathSeparator;
+#endif
+}
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir()
+{
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE doesn't have a current directory, so we just return
+ // something reasonable.
+ return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const
+{
+ const std::string dot_extension = std::string(".") + extension;
+ if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
+ return FilePath(pathname_.substr(
+ 0, pathname_.length() - dot_extension.length()));
+ }
+ return *this;
+}
+
+// Returns a pointer to the last occurence of a valid path separator in
+// the FilePath. On Windows, for example, both '/' and '\' are valid path
+// separators. Returns NULL if no path separator was found.
+const char* FilePath::FindLastPathSeparator() const
+{
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+#if GTEST_HAS_ALT_PATH_SEP_
+ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
+ // Comparing two pointers of which only one is NULL is undefined.
+ if (last_alt_sep != NULL &&
+ (last_sep == NULL || last_alt_sep > last_sep)) {
+ return last_alt_sep;
+ }
+#endif
+ return last_sep;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const
+{
+ const char* const last_sep = FindLastPathSeparator();
+ return last_sep ? FilePath(last_sep + 1) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const
+{
+ const char* const last_sep = FindLastPathSeparator();
+ std::string dir;
+ if (last_sep) {
+ dir = std::string(c_str(), last_sep + 1 - c_str());
+ } else {
+ dir = kCurrentDirectoryString;
+ }
+ return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension)
+{
+ std::string file;
+ if (number == 0) {
+ file = base_name.string() + "." + extension;
+ } else {
+ file = base_name.string() + "_" + StreamableToString(number)
+ + "." + extension;
+ }
+ return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path)
+{
+ if (directory.IsEmpty())
+ return relative_path;
+ const FilePath dir(directory.RemoveTrailingPathSeparator());
+ return FilePath(dir.string() + kPathSeparator + relative_path.string());
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const
+{
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ return attributes != kInvalidFileAttributes;
+#else
+ posix::StatStruct file_stat;
+ return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const
+{
+ bool result = false;
+#if GTEST_OS_WINDOWS
+ // Don't strip off trailing separator if path is a root directory on
+ // Windows (like "C:\\").
+ const FilePath& path(IsRootDirectory() ? *this :
+ RemoveTrailingPathSeparator());
+#else
+ const FilePath& path(*this);
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ if ((attributes != kInvalidFileAttributes) &&
+ (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = true;
+ }
+#else
+ posix::StatStruct file_stat;
+ result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+ posix::IsDir(file_stat);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const
+{
+#if GTEST_OS_WINDOWS
+ // TODO(wan at google.com): on Windows a network share like
+ // \\server\share can be a root directory, although it cannot be the
+ // current directory. Handle this properly.
+ return pathname_.length() == 3 && IsAbsolutePath();
+#else
+ return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const
+{
+ const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+ return pathname_.length() >= 3 &&
+ ((name[0] >= 'a' && name[0] <= 'z') ||
+ (name[0] >= 'A' && name[0] <= 'Z')) &&
+ name[1] == ':' &&
+ IsPathSeparator(name[2]);
+#else
+ return IsPathSeparator(name[0]);
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension)
+{
+ FilePath full_pathname;
+ int number = 0;
+ do {
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+ } while (full_pathname.FileOrDirectoryExists());
+ return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const
+{
+ return !pathname_.empty() &&
+ IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const
+{
+ if (!this->IsDirectory()) {
+ return false;
+ }
+
+ if (pathname_.length() == 0 || this->DirectoryExists()) {
+ return true;
+ }
+
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const
+{
+#if GTEST_OS_WINDOWS_MOBILE
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
+ LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+ int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+ delete [] unicode;
+#elif GTEST_OS_WINDOWS
+ int result = _mkdir(pathname_.c_str());
+#else
+ int result = mkdir(pathname_.c_str(), 0777);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ if (result == -1) {
+ return this->DirectoryExists(); // An error is OK if the directory exists.
+ }
+ return true; // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const
+{
+ return IsDirectory()
+ ? FilePath(pathname_.substr(0, pathname_.length() - 1))
+ : *this;
+}
+
+// Removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+// TODO(wan at google.com): handle Windows network shares (e.g. \\server\share).
+void FilePath::Normalize()
+{
+ if (pathname_.c_str() == NULL) {
+ pathname_ = "";
+ return;
+ }
+ const char* src = pathname_.c_str();
+ char* const dest = new char[pathname_.length() + 1];
+ char* dest_ptr = dest;
+ memset(dest_ptr, 0, pathname_.length() + 1);
+
+ while (*src != '\0') {
+ *dest_ptr = *src;
+ if (!IsPathSeparator(*src)) {
+ src++;
+ } else {
+#if GTEST_HAS_ALT_PATH_SEP_
+ if (*dest_ptr == kAlternatePathSeparator) {
+ *dest_ptr = kPathSeparator;
+ }
+#endif
+ while (IsPathSeparator(*src))
+ src++;
+ }
+ dest_ptr++;
+ }
+ *dest_ptr = '\0';
+ pathname_ = dest;
+ delete[] dest;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest-internal-inl.h b/external/gtest-1.6.0/src/gtest-internal-inl.h
new file mode 100644
index 0000000..570ebf3
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-internal-inl.h
@@ -0,0 +1,1243 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
+// part of Google Test's implementation; otherwise it's undefined.
+#if !GTEST_IMPLEMENTATION_
+// A user is trying to include this from his code - just say no.
+# error "gtest-internal-inl.h is part of Google Test's internal implementation."
+# error "It must not be included except by Google Test itself."
+#endif // GTEST_IMPLEMENTATION_
+
+#ifndef _WIN32_WCE
+# include <errno.h>
+#endif // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h> // For strtoll/_strtoul64/malloc/free.
+#include <string.h> // For memmove.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h> // NOLINT
+# include <netdb.h> // NOLINT
+#endif
+
+#if GTEST_OS_WINDOWS
+# include <windows.h> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+#include "gtest/gtest.h" // NOLINT
+#include "gtest/gtest-spi.h"
+
+namespace testing
+{
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal
+{
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRandomSeedFlag[] = "random_seed";
+const char kRepeatFlag[] = "repeat";
+const char kShuffleFlag[] = "shuffle";
+const char kStackTraceDepthFlag[] = "stack_trace_depth";
+const char kStreamResultToFlag[] = "stream_result_to";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+GTEST_API_ extern bool g_help_flag;
+
+// Returns the current time in milliseconds.
+GTEST_API_ TimeInMillis GetTimeInMillis();
+
+// Returns true iff Google Test should use colors in the output.
+GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
+
+// Formats the given time in milliseconds as seconds.
+GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
+
+// Converts the given time in milliseconds to a date string in the ISO 8601
+// format, without the timezone information. N.B.: due to the use the
+// non-reentrant localtime() function, this function is not thread safe. Do
+// not use it in any code that can be called from multiple threads.
+GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
+
+// Parses a string for an Int32 flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+GTEST_API_ bool ParseInt32Flag(
+ const char* str, const char* flag, Int32* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(Int32 random_seed_flag)
+{
+ const unsigned int raw_seed = (random_seed_flag == 0) ?
+ static_cast<unsigned int>(GetTimeInMillis()) :
+ static_cast<unsigned int>(random_seed_flag);
+
+ // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+ // it's easy to type.
+ const int normalized_seed =
+ static_cast<int>((raw_seed - 1U) %
+ static_cast<unsigned int>(kMaxRandomSeed)) + 1;
+ return normalized_seed;
+}
+
+// Returns the first valid random seed after 'seed'. The behavior is
+// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is
+// considered to be 1.
+inline int GetNextRandomSeed(int seed)
+{
+ GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
+ << "Invalid random seed " << seed << " - must be in [1, "
+ << kMaxRandomSeed << "].";
+ const int next_seed = seed + 1;
+ return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
+}
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver
+{
+ public:
+ // The c'tor.
+ GTestFlagSaver() {
+ also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+ break_on_failure_ = GTEST_FLAG(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+ color_ = GTEST_FLAG(color);
+ death_test_style_ = GTEST_FLAG(death_test_style);
+ death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+ filter_ = GTEST_FLAG(filter);
+ internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+ list_tests_ = GTEST_FLAG(list_tests);
+ output_ = GTEST_FLAG(output);
+ print_time_ = GTEST_FLAG(print_time);
+ random_seed_ = GTEST_FLAG(random_seed);
+ repeat_ = GTEST_FLAG(repeat);
+ shuffle_ = GTEST_FLAG(shuffle);
+ stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
+ stream_result_to_ = GTEST_FLAG(stream_result_to);
+ throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+ GTEST_FLAG(break_on_failure) = break_on_failure_;
+ GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+ GTEST_FLAG(color) = color_;
+ GTEST_FLAG(death_test_style) = death_test_style_;
+ GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+ GTEST_FLAG(filter) = filter_;
+ GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+ GTEST_FLAG(list_tests) = list_tests_;
+ GTEST_FLAG(output) = output_;
+ GTEST_FLAG(print_time) = print_time_;
+ GTEST_FLAG(random_seed) = random_seed_;
+ GTEST_FLAG(repeat) = repeat_;
+ GTEST_FLAG(shuffle) = shuffle_;
+ GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
+ GTEST_FLAG(stream_result_to) = stream_result_to_;
+ GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+ }
+
+ private:
+ // Fields for saving the original values of flags.
+ bool also_run_disabled_tests_;
+ bool break_on_failure_;
+ bool catch_exceptions_;
+ std::string color_;
+ std::string death_test_style_;
+ bool death_test_use_fork_;
+ std::string filter_;
+ std::string internal_run_death_test_;
+ bool list_tests_;
+ std::string output_;
+ bool print_time_;
+ internal::Int32 random_seed_;
+ internal::Int32 repeat_;
+ bool shuffle_;
+ internal::Int32 stack_trace_depth_;
+ std::string stream_result_to_;
+ bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+GTEST_API_ bool ShouldShard(const char* total_shards_str,
+ const char* shard_index_str,
+ bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error and
+// and aborts.
+GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+GTEST_API_ bool ShouldRunTestOnShard(
+ int total_shards, int shard_index, int test_id);
+
+// STL container utilities.
+
+// Returns the number of elements in the given container that satisfy
+// the given predicate.
+template <class Container, typename Predicate>
+inline int CountIf(const Container& c, Predicate predicate)
+{
+ // Implemented as an explicit loop since std::count_if() in libCstd on
+ // Solaris has a non-standard signature.
+ int count = 0;
+ for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) {
+ if (predicate(*it))
+ ++count;
+ }
+ return count;
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+void ForEach(const Container& c, Functor functor)
+{
+ std::for_each(c.begin(), c.end(), functor);
+}
+
+// Returns the i-th element of the vector, or default_value if i is not
+// in range [0, v.size()).
+template <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value)
+{
+ return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+}
+
+// Performs an in-place shuffle of a range of the vector's elements.
+// 'begin' and 'end' are element indices as an STL-style range;
+// i.e. [begin, end) are shuffled, where 'end' == size() means to
+// shuffle to the end of the vector.
+template <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+ std::vector<E>* v)
+{
+ const int size = static_cast<int>(v->size());
+ GTEST_CHECK_(0 <= begin && begin <= size)
+ << "Invalid shuffle range start " << begin << ": must be in range [0, "
+ << size << "].";
+ GTEST_CHECK_(begin <= end && end <= size)
+ << "Invalid shuffle range finish " << end << ": must be in range ["
+ << begin << ", " << size << "].";
+
+ // Fisher-Yates shuffle, from
+ // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ for (int range_width = end - begin; range_width >= 2; range_width--) {
+ const int last_in_range = begin + range_width - 1;
+ const int selected = begin + random->Generate(range_width);
+ std::swap((*v)[selected], (*v)[last_in_range]);
+ }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v)
+{
+ ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T* x)
+{
+ delete x;
+}
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs
+{
+ public:
+ // Constructor.
+ //
+ // TestPropertyKeyIs has NO default constructor.
+ explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
+
+ // Returns true iff the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return test_property.key() == key_;
+ }
+
+ private:
+ std::string key_;
+};
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests. It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag. E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter. If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class GTEST_API_ UnitTestOptions
+{
+ public:
+ // Functions for processing the gtest_output flag.
+
+ // Returns the output format, or "" for normal printed output.
+ static std::string GetOutputFormat();
+
+ // Returns the absolute path of the requested output file, or the
+ // default (test_detail.xml in the original working directory) if
+ // none was explicitly specified.
+ static std::string GetAbsolutePathToOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true iff the wildcard pattern matches the string. The
+ // first ':' or '\0' character in pattern marks the end of it.
+ //
+ // This recursive algorithm isn't very efficient, but is clear and
+ // works well enough for matching test names, which are short.
+ static bool PatternMatchesString(const char* pattern, const char* str);
+
+ // Returns true iff the user-specified filter matches the test case
+ // name and the test name.
+ static bool FilterMatchesTest(const std::string& test_case_name,
+ const std::string& test_name);
+
+#if GTEST_OS_WINDOWS
+ // Function for supporting the gtest_catch_exception flag.
+
+ // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+ // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+ // This function is useful as an __except condition.
+ static int GTestShouldProcessSEH(DWORD exception_code);
+#endif // GTEST_OS_WINDOWS
+
+ // Returns true if "name" matches the ':' separated list of glob-style
+ // filters in "filter".
+ static bool MatchesFilter(const std::string& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present. Used by UnitTestOptions::GetOutputFile.
+GTEST_API_ FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface
+{
+ public:
+ OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface() {}
+
+ // Returns the current OS stack trace as an std::string. Parameters:
+ //
+ // max_depth - the maximum number of stack frames to be included
+ // in the trace.
+ // skip_count - the number of top frames to be skipped; doesn't count
+ // against max_depth.
+ virtual string CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+ // UponLeavingGTest() should be called immediately before Google Test calls
+ // user code. It saves some information about the current stack that
+ // CurrentStackTrace() will use to find and hide Google Test stack frames.
+ virtual void UponLeavingGTest() = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface
+{
+ public:
+ OsStackTraceGetter() : caller_frame_(NULL) {}
+
+ virtual string CurrentStackTrace(int max_depth, int skip_count)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ Mutex mutex_; // protects all internal state
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to CurrentStackTrace() from within the user code.
+ void* caller_frame_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ std::string message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+ : public TestPartResultReporterInterface
+{
+ public:
+ explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. Reports the test part
+ // result in the current test.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+ : public TestPartResultReporterInterface
+{
+ public:
+ explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. The implementation just
+ // delegates to the current global test part result reporter of *unit_test_.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class. We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class GTEST_API_ UnitTestImpl
+{
+ public:
+ explicit UnitTestImpl(UnitTest* parent);
+ virtual ~UnitTestImpl();
+
+ // There are two different ways to register your own TestPartResultReporter.
+ // You can register your own repoter to listen either only for test results
+ // from the current thread or for results from all threads.
+ // By default, each per-thread test result repoter just passes a new
+ // TestPartResult to the global test result reporter, which registers the
+ // test part result for the currently running test.
+
+ // Returns the global test part result reporter.
+ TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+ // Sets the global test part result reporter.
+ void SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter);
+
+ // Returns the test part result reporter for the current thread.
+ TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+ // Sets the test part result reporter for the current thread.
+ void SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter);
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ const TestCase* GetTestCase(int i) const {
+ const int index = GetElementOr(test_case_indices_, i, -1);
+ return index < 0 ? NULL : test_cases_[i];
+ }
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ TestCase* GetMutableTestCase(int i) {
+ const int index = GetElementOr(test_case_indices_, i, -1);
+ return index < 0 ? NULL : test_cases_[index];
+ }
+
+ // Provides access to the event listener list.
+ TestEventListeners* listeners() { return &listeners_; }
+
+ // Returns the TestResult for the test that's currently running, or
+ // the TestResult for the ad hoc test if no test is running.
+ TestResult* current_test_result();
+
+ // Returns the TestResult for the ad hoc test.
+ const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
+
+ // Sets the OS stack trace getter.
+ //
+ // Does nothing if the input and the current OS stack trace getter
+ // are the same; otherwise, deletes the old getter and makes the
+ // input the current getter.
+ void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+ // Returns the current OS stack trace getter if it is not NULL;
+ // otherwise, creates an OsStackTraceGetter, makes it the current
+ // getter, and returns it.
+ OsStackTraceGetterInterface* os_stack_trace_getter();
+
+ // Returns the current OS stack trace as an std::string.
+ //
+ // The maximum number of stack frames to be included is specified by
+ // the gtest_stack_trace_depth flag. The skip_count parameter
+ // specifies the number of top frames to be skipped, which doesn't
+ // count against the number of frames to be included.
+ //
+ // For example, if Foo() calls Bar(), which in turn calls
+ // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+ // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+ std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
+
+ // Finds and returns a TestCase with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_case_name: name of the test case
+ // type_param: the name of the test's type parameter, or NULL if
+ // this is not a typed or a type-parameterized test.
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase* GetTestCase(const char* test_case_name,
+ const char* type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ // test_info: the TestInfo object
+ void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestInfo* test_info) {
+ // In order to support thread-safe death tests, we need to
+ // remember the original working directory when the test program
+ // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
+ // the user may have changed the current directory before calling
+ // RUN_ALL_TESTS(). Therefore we capture the current directory in
+ // AddTestInfo(), which is called to register a TEST or TEST_F
+ // before main() is reached.
+ if (original_working_dir_.IsEmpty()) {
+ original_working_dir_.Set(FilePath::GetCurrentDir());
+ GTEST_CHECK_(!original_working_dir_.IsEmpty())
+ << "Failed to get the current working directory.";
+ }
+
+ GetTestCase(test_info->test_case_name(),
+ test_info->type_param(),
+ set_up_tc,
+ tear_down_tc)->AddTestInfo(test_info);
+ }
+
+#if GTEST_HAS_PARAM_TEST
+ // Returns ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+ return parameterized_test_registry_;
+ }
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Sets the TestCase object for the test that's currently running.
+ void set_current_test_case(TestCase* a_current_test_case) {
+ current_test_case_ = a_current_test_case;
+ }
+
+ // Sets the TestInfo object for the test that's currently running. If
+ // current_test_info is NULL, the assertion results will be stored in
+ // ad_hoc_test_result_.
+ void set_current_test_info(TestInfo* a_current_test_info) {
+ current_test_info_ = a_current_test_info;
+ }
+
+ // Registers all parameterized tests defined using TEST_P and
+ // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
+ // combination. This method can be called more then once; it has guards
+ // protecting from registering the tests more then once. If
+ // value-parameterized tests are disabled, RegisterParameterizedTests is
+ // present but does nothing.
+ void RegisterParameterizedTests();
+
+ // Runs all tests in this UnitTest object, prints the result, and
+ // returns true if all tests are successful. If any exception is
+ // thrown during a test, this test is considered to be failed, but
+ // the rest of the tests will still be run.
+ bool RunAllTests();
+
+ // Clears the results of all tests, except the ad hoc tests.
+ void ClearNonAdHocTestResult() {
+ ForEach(test_cases_, TestCase::ClearTestCaseResult);
+ }
+
+ // Clears the results of ad-hoc test assertions.
+ void ClearAdHocTestResult() {
+ ad_hoc_test_result_.Clear();
+ }
+
+ // Adds a TestProperty to the current TestResult object when invoked in a
+ // context of a test or a test case, or to the global property set. If the
+ // result already contains a property with the same key, the value will be
+ // updated.
+ void RecordProperty(const TestProperty& test_property);
+
+ enum ReactionToSharding {
+ HONOR_SHARDING_PROTOCOL,
+ IGNORE_SHARDING_PROTOCOL
+ };
+
+ // Matches the full name of each test against the user-specified
+ // filter to decide whether the test should run, then records the
+ // result in each TestCase and TestInfo object.
+ // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+ // based on sharding variables in the environment.
+ // Returns the number of tests that should run.
+ int FilterTests(ReactionToSharding shard_tests);
+
+ // Prints the names of the tests matching the user-specified filter flag.
+ void ListTestsMatchingFilter();
+
+ const TestCase* current_test_case() const { return current_test_case_; }
+ TestInfo* current_test_info() { return current_test_info_; }
+ const TestInfo* current_test_info() const { return current_test_info_; }
+
+ // Returns the vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*>& environments() { return environments_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ std::vector<TraceInfo>& gtest_trace_stack() {
+ return *(gtest_trace_stack_.pointer());
+ }
+ const std::vector<TraceInfo>& gtest_trace_stack() const {
+ return gtest_trace_stack_.get();
+ }
+
+#if GTEST_HAS_DEATH_TEST
+ void InitDeathTestSubprocessControlInfo() {
+ internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+ }
+ // Returns a pointer to the parsed --gtest_internal_run_death_test
+ // flag, or NULL if that flag was not specified.
+ // This information is useful only in a death test child process.
+ // Must not be called before a call to InitGoogleTest.
+ const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+ return internal_run_death_test_flag_.get();
+ }
+
+ // Returns a pointer to the current death test factory.
+ internal::DeathTestFactory* death_test_factory() {
+ return death_test_factory_.get();
+ }
+
+ void SuppressTestEventsIfInSubprocess();
+
+ friend class ReplaceDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Initializes the event listener performing XML output as specified by
+ // UnitTestOptions. Must not be called before InitGoogleTest.
+ void ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Initializes the event listener for streaming test results to a socket.
+ // Must not be called before InitGoogleTest.
+ void ConfigureStreamingOutput();
+#endif
+
+ // Performs initialization dependent upon flag values obtained in
+ // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+ // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+ // this function is also called from RunAllTests. Since this function can be
+ // called more than once, it has to be idempotent.
+ void PostFlagParsingInit();
+
+ // Gets the random seed used at the start of the current test iteration.
+ int random_seed() const { return random_seed_; }
+
+ // Gets the random number generator.
+ internal::Random* random() { return &random_; }
+
+ // Shuffles all test cases, and the tests within each test case,
+ // making sure that death tests are still run first.
+ void ShuffleTests();
+
+ // Restores the test cases and tests to their order before the first shuffle.
+ void UnshuffleTests();
+
+ // Returns the value of GTEST_FLAG(catch_exceptions) at the moment
+ // UnitTest::Run() starts.
+ bool catch_exceptions() const { return catch_exceptions_; }
+
+ private:
+ friend class ::testing::UnitTest;
+
+ // Used by UnitTest::Run() to capture the state of
+ // GTEST_FLAG(catch_exceptions) at the moment it starts.
+ void set_catch_exceptions(bool value) { catch_exceptions_ = value; }
+
+ // The UnitTest object that owns this implementation object.
+ UnitTest* const parent_;
+
+ // The working directory when the first TEST() or TEST_F() was
+ // executed.
+ internal::FilePath original_working_dir_;
+
+ // The default test part result reporters.
+ DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+ DefaultPerThreadTestPartResultReporter
+ default_per_thread_test_part_result_reporter_;
+
+ // Points to (but doesn't own) the global test part result reporter.
+ TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+ // Protects read and write access to global_test_part_result_reporter_.
+ internal::Mutex global_test_part_result_reporter_mutex_;
+
+ // Points to (but doesn't own) the per-thread test part result reporter.
+ internal::ThreadLocal<TestPartResultReporterInterface*>
+ per_thread_test_part_result_reporter_;
+
+ // The vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*> environments_;
+
+ // The vector of TestCases in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestCase*> test_cases_;
+
+ // Provides a level of indirection for the test case list to allow
+ // easy shuffling and restoring the test case order. The i-th
+ // element of this vector is the index of the i-th test case in the
+ // shuffled order.
+ std::vector<int> test_case_indices_;
+
+#if GTEST_HAS_PARAM_TEST
+ // ParameterizedTestRegistry object used to register value-parameterized
+ // tests.
+ internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+ // Indicates whether RegisterParameterizedTests() has been called already.
+ bool parameterized_tests_registered_;
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Index of the last death test case registered. Initially -1.
+ int last_death_test_case_;
+
+ // This points to the TestCase for the currently running test. It
+ // changes as Google Test goes through one test case after another.
+ // When no test is running, this is set to NULL and Google Test
+ // stores assertion results in ad_hoc_test_result_. Initially NULL.
+ TestCase* current_test_case_;
+
+ // This points to the TestInfo for the currently running test. It
+ // changes as Google Test goes through one test after another. When
+ // no test is running, this is set to NULL and Google Test stores
+ // assertion results in ad_hoc_test_result_. Initially NULL.
+ TestInfo* current_test_info_;
+
+ // Normally, a user only writes assertions inside a TEST or TEST_F,
+ // or inside a function called by a TEST or TEST_F. Since Google
+ // Test keeps track of which test is current running, it can
+ // associate such an assertion with the test it belongs to.
+ //
+ // If an assertion is encountered when no TEST or TEST_F is running,
+ // Google Test attributes the assertion result to an imaginary "ad hoc"
+ // test, and records the result in ad_hoc_test_result_.
+ TestResult ad_hoc_test_result_;
+
+ // The list of event listeners that can be used to track events inside
+ // Google Test.
+ TestEventListeners listeners_;
+
+ // The OS stack trace getter. Will be deleted when the UnitTest
+ // object is destructed. By default, an OsStackTraceGetter is used,
+ // but the user can set this field to use a custom getter if that is
+ // desired.
+ OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+ // True iff PostFlagParsingInit() has been called.
+ bool post_flag_parse_init_performed_;
+
+ // The random number seed used at the beginning of the test run.
+ int random_seed_;
+
+ // Our random number generator.
+ internal::Random random_;
+
+ // The time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp_;
+
+ // How long the test took to run, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+ // The decomposed components of the gtest_internal_run_death_test flag,
+ // parsed when RUN_ALL_TESTS is called.
+ internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+ // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
+ // starts.
+ bool catch_exceptions_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+}; // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl()
+{
+ return UnitTest::GetInstance()->impl();
+}
+
+#if GTEST_USES_SIMPLE_RE
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+GTEST_API_ bool IsInSet(char ch, const char* str);
+GTEST_API_ bool IsAsciiDigit(char ch);
+GTEST_API_ bool IsAsciiPunct(char ch);
+GTEST_API_ bool IsRepeat(char ch);
+GTEST_API_ bool IsAsciiWhiteSpace(char ch);
+GTEST_API_ bool IsAsciiWordChar(char ch);
+GTEST_API_ bool IsValidEscape(char ch);
+GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
+GTEST_API_ bool ValidateRegex(const char* regex);
+GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
+GTEST_API_ bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char ch, char repeat, const char* regex, const char* str);
+GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
+
+#endif // GTEST_USES_SIMPLE_RE
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+GTEST_API_ std::string GetLastErrnoDescription();
+
+# if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+class AutoHandle
+{
+ public:
+ AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+ explicit AutoHandle(HANDLE handle) : handle_(handle) {}
+
+ ~AutoHandle() { Reset(); }
+
+ HANDLE Get() const { return handle_; }
+ void Reset() { Reset(INVALID_HANDLE_VALUE); }
+ void Reset(HANDLE handle) {
+ if (handle != handle_) {
+ if (handle_ != INVALID_HANDLE_VALUE)
+ ::CloseHandle(handle_);
+ handle_ = handle;
+ }
+ }
+
+ private:
+ HANDLE handle_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+# endif // GTEST_OS_WINDOWS
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter. Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number)
+{
+ // Fail fast if the given string does not begin with a digit;
+ // this bypasses strtoXXX's "optional leading whitespace and plus
+ // or minus sign" semantics, which are undesirable here.
+ if (str.empty() || !IsDigit(str[0])) {
+ return false;
+ }
+ errno = 0;
+
+ char* end;
+ // BiggestConvertible is the largest integer type that system-provided
+ // string-to-number conversion routines can return.
+
+# if GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+ // MSVC and C++ Builder define __int64 instead of the standard long long.
+ typedef unsigned __int64 BiggestConvertible;
+ const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
+
+# else
+
+ typedef unsigned long long BiggestConvertible; // NOLINT
+ const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
+
+# endif // GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+ const bool parse_success = *end == '\0' && errno == 0;
+
+ // TODO(vladl at google.com): Convert this to compile time assertion when it is
+ // available.
+ GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+ const Integer result = static_cast<Integer>(parsed);
+ if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+ *number = result;
+ return true;
+ }
+ return false;
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// TestResult contains some private methods that should be hidden from
+// Google Test user but are required for testing. This class allow our tests
+// to access them.
+//
+// This class is supplied only for the purpose of testing Google Test's own
+// constructs. Do not use it in user tests, either directly or indirectly.
+class TestResultAccessor
+{
+ public:
+ static void RecordProperty(TestResult* test_result,
+ const std::string& xml_element,
+ const TestProperty& property) {
+ test_result->RecordProperty(xml_element, property);
+ }
+
+ static void ClearTestPartResults(TestResult* test_result) {
+ test_result->ClearTestPartResults();
+ }
+
+ static const std::vector<testing::TestPartResult>& test_part_results(
+ const TestResult& test_result) {
+ return test_result.test_part_results();
+ }
+};
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Streams test results to the given port on the given host machine.
+class StreamingListener : public EmptyTestEventListener
+{
+ public:
+ // Abstract base class for writing strings to a socket.
+ class AbstractSocketWriter
+ {
+ public:
+ virtual ~AbstractSocketWriter() {}
+
+ // Sends a string to the socket.
+ virtual void Send(const string& message) = 0;
+
+ // Closes the socket.
+ virtual void CloseConnection() {}
+
+ // Sends a string and a newline to the socket.
+ void SendLn(const string& message) {
+ Send(message + "\n");
+ }
+ };
+
+ // Concrete class for actually writing strings to a socket.
+ class SocketWriter : public AbstractSocketWriter
+ {
+ public:
+ SocketWriter(const string& host, const string& port)
+ : sockfd_(-1), host_name_(host), port_num_(port) {
+ MakeConnection();
+ }
+
+ virtual ~SocketWriter() {
+ if (sockfd_ != -1)
+ CloseConnection();
+ }
+
+ // Sends a string to the socket.
+ virtual void Send(const string& message) {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "Send() can be called only when there is a connection.";
+
+ const int len = static_cast<int>(message.length());
+ if (write(sockfd_, message.c_str(), len) != len) {
+ GTEST_LOG_(WARNING)
+ << "stream_result_to: failed to stream to "
+ << host_name_ << ":" << port_num_;
+ }
+ }
+
+ private:
+ // Creates a client socket and connects to the server.
+ void MakeConnection();
+
+ // Closes the socket.
+ void CloseConnection() {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "CloseConnection() can be called only when there is a connection.";
+
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+
+ int sockfd_; // socket file descriptor
+ const string host_name_;
+ const string port_num_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
+ }; // class SocketWriter
+
+ // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
+ static string UrlEncode(const char* str);
+
+ StreamingListener(const string& host, const string& port)
+ : socket_writer_(new SocketWriter(host, port)) { Start(); }
+
+ explicit StreamingListener(AbstractSocketWriter* socket_writer)
+ : socket_writer_(socket_writer) { Start(); }
+
+ void OnTestProgramStart(const UnitTest& /* unit_test */) {
+ SendLn("event=TestProgramStart");
+ }
+
+ void OnTestProgramEnd(const UnitTest& unit_test) {
+ // Note that Google Test current only report elapsed time for each
+ // test iteration, not for the entire test program.
+ SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
+
+ // Notify the streaming server to stop.
+ socket_writer_->CloseConnection();
+ }
+
+ void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
+ SendLn("event=TestIterationStart&iteration=" +
+ StreamableToString(iteration));
+ }
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
+ SendLn("event=TestIterationEnd&passed=" +
+ FormatBool(unit_test.Passed()) + "&elapsed_time=" +
+ StreamableToString(unit_test.elapsed_time()) + "ms");
+ }
+
+ void OnTestCaseStart(const TestCase& test_case) {
+ SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
+ }
+
+ void OnTestCaseEnd(const TestCase& test_case) {
+ SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
+ + "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
+ + "ms");
+ }
+
+ void OnTestStart(const TestInfo& test_info) {
+ SendLn(std::string("event=TestStart&name=") + test_info.name());
+ }
+
+ void OnTestEnd(const TestInfo& test_info) {
+ SendLn("event=TestEnd&passed=" +
+ FormatBool((test_info.result())->Passed()) +
+ "&elapsed_time=" +
+ StreamableToString((test_info.result())->elapsed_time()) + "ms");
+ }
+
+ void OnTestPartResult(const TestPartResult& test_part_result) {
+ const char* file_name = test_part_result.file_name();
+ if (file_name == NULL)
+ file_name = "";
+ SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
+ "&line=" + StreamableToString(test_part_result.line_number()) +
+ "&message=" + UrlEncode(test_part_result.message()));
+ }
+
+ private:
+ // Sends the given message and a newline to the socket.
+ void SendLn(const string& message) { socket_writer_->SendLn(message); }
+
+ // Called at the start of streaming to notify the receiver what
+ // protocol we are using.
+ void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
+
+ string FormatBool(bool value) { return value ? "1" : "0"; }
+
+ const scoped_ptr<AbstractSocketWriter> socket_writer_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
+}; // class StreamingListener
+
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/external/gtest-1.6.0/src/gtest-port.cc b/external/gtest-1.6.0/src/gtest-port.cc
new file mode 100644
index 0000000..273dbdb
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-port.cc
@@ -0,0 +1,850 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/internal/gtest-port.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h> // For TerminateProcess()
+#elif GTEST_OS_WINDOWS
+# include <io.h>
+# include <sys/stat.h>
+#else
+# include <unistd.h>
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_MAC
+# include <mach/mach_init.h>
+# include <mach/task.h>
+# include <mach/vm_map.h>
+#endif // GTEST_OS_MAC
+
+#if GTEST_OS_QNX
+# include <devctl.h>
+# include <sys/procfs.h>
+#endif // GTEST_OS_QNX
+
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+namespace internal
+{
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdOutFileno = 1;
+const int kStdErrFileno = 2;
+#else
+const int kStdOutFileno = STDOUT_FILENO;
+const int kStdErrFileno = STDERR_FILENO;
+#endif // _MSC_VER
+
+#if GTEST_OS_MAC
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount()
+{
+ const task_t task = mach_task_self();
+ mach_msg_type_number_t thread_count;
+ thread_act_array_t thread_list;
+ const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+ if (status == KERN_SUCCESS) {
+ // task_threads allocates resources in thread_list and we need to free them
+ // to avoid leaks.
+ vm_deallocate(task,
+ reinterpret_cast<vm_address_t>(thread_list),
+ sizeof(thread_t) * thread_count);
+ return static_cast<size_t>(thread_count);
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_QNX
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount()
+{
+ const int fd = open("/proc/self/as", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+ procfs_info process_info;
+ const int status =
+ devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
+ close(fd);
+ if (status == EOK) {
+ return static_cast<size_t>(process_info.num_threads);
+ } else {
+ return 0;
+ }
+}
+
+#else
+
+size_t GetThreadCount()
+{
+ // There's no portable way to detect the number of threads, so we just
+ // return 0 to indicate that we cannot detect it.
+ return 0;
+}
+
+#endif // GTEST_OS_MAC
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE. Currently only needed for death tests.
+
+RE::~RE()
+{
+ if (is_valid_) {
+ // regfree'ing an invalid regex might crash because the content
+ // of the regex is undefined. Since the regex's are essentially
+ // the same, one cannot be valid (or invalid) without the other
+ // being so too.
+ regfree(&partial_regex_);
+ regfree(&full_regex_);
+ }
+ free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re)
+{
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re)
+{
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex)
+{
+ pattern_ = posix::StrDup(regex);
+
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match.
+ const size_t full_regex_len = strlen(regex) + 10;
+ char* const full_pattern = new char[full_regex_len];
+
+ snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+ is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+ // We want to call regcomp(&partial_regex_, ...) even if the
+ // previous expression returns false. Otherwise partial_regex_ may
+ // not be properly initialized can may cause trouble when it's
+ // freed.
+ //
+ // Some implementation of POSIX regex (e.g. on at least some
+ // versions of Cygwin) doesn't accept the empty string as a valid
+ // regex. We change it to an equivalent form "()" to be safe.
+ if (is_valid_) {
+ const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+ is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
+ }
+ EXPECT_TRUE(is_valid_)
+ << "Regular expression \"" << regex
+ << "\" is not a valid POSIX Extended regular expression.";
+
+ delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true iff ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str)
+{
+ return ch != '\0' && strchr(str, ch) != NULL;
+}
+
+// Returns true iff ch belongs to the given classification. Unlike
+// similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsAsciiPunct(char ch)
+{
+ return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsAsciiWordChar(char ch)
+{
+ return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true iff "\\c" is a supported escape sequence.
+bool IsValidEscape(char c)
+{
+ return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true iff the given atom (specified by escaped and pattern)
+// matches ch. The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch)
+{
+ if (escaped) { // "\\p" where p is pattern_char.
+ switch (pattern_char) {
+ case 'd': return IsAsciiDigit(ch);
+ case 'D': return !IsAsciiDigit(ch);
+ case 'f': return ch == '\f';
+ case 'n': return ch == '\n';
+ case 'r': return ch == '\r';
+ case 's': return IsAsciiWhiteSpace(ch);
+ case 'S': return !IsAsciiWhiteSpace(ch);
+ case 't': return ch == '\t';
+ case 'v': return ch == '\v';
+ case 'w': return IsAsciiWordChar(ch);
+ case 'W': return !IsAsciiWordChar(ch);
+ }
+ return IsAsciiPunct(pattern_char) && pattern_char == ch;
+ }
+
+ return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+std::string FormatRegexSyntaxError(const char* regex, int index)
+{
+ return (Message() << "Syntax error at index " << index
+ << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex)
+{
+ if (regex == NULL) {
+ // TODO(wan at google.com): fix the source file location in the
+ // assertion failures to match where the regex is used in user
+ // code.
+ ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+ return false;
+ }
+
+ bool is_valid = true;
+
+ // True iff ?, *, or + can follow the previous atom.
+ bool prev_repeatable = false;
+ for (int i = 0; regex[i]; i++) {
+ if (regex[i] == '\\') { // An escape sequence
+ i++;
+ if (regex[i] == '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "'\\' cannot appear at the end.";
+ return false;
+ }
+
+ if (!IsValidEscape(regex[i])) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "invalid escape sequence \"\\" << regex[i] << "\".";
+ is_valid = false;
+ }
+ prev_repeatable = true;
+ } else { // Not an escape sequence.
+ const char ch = regex[i];
+
+ if (ch == '^' && i > 0) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'^' can only appear at the beginning.";
+ is_valid = false;
+ } else if (ch == '$' && regex[i + 1] != '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'$' can only appear at the end.";
+ is_valid = false;
+ } else if (IsInSet(ch, "()[]{}|")) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' is unsupported.";
+ is_valid = false;
+ } else if (IsRepeat(ch) && !prev_repeatable) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' can only follow a repeatable token.";
+ is_valid = false;
+ }
+
+ prev_repeatable = !IsInSet(ch, "^$?*+");
+ }
+ }
+
+ return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression. The regex atom is defined as c if escaped is false,
+// or \c otherwise. repeat is the repetition meta character (?, *,
+// or +). The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway. We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char c, char repeat, const char* regex,
+ const char* str)
+{
+ const size_t min_count = (repeat == '+') ? 1 : 0;
+ const size_t max_count = (repeat == '?') ? 1 :
+ static_cast<size_t>(-1) - 1;
+ // We cannot call numeric_limits::max() as it conflicts with the
+ // max() macro on Windows.
+
+ for (size_t i = 0; i <= max_count; ++i) {
+ // We know that the atom matches each of the first i characters in str.
+ if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+ // We have enough matches at the head, and the tail matches too.
+ // Since we only care about *whether* the pattern matches str
+ // (as opposed to *how* it matches), there is no need to find a
+ // greedy match.
+ return true;
+ }
+ if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+ return false;
+ }
+ return false;
+}
+
+// Returns true iff regex matches a prefix of str. regex must be a
+// valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str)
+{
+ if (*regex == '\0') // An empty regex matches a prefix of anything.
+ return true;
+
+ // "$" only matches the end of a string. Note that regex being
+ // valid guarantees that there's nothing after "$" in it.
+ if (*regex == '$')
+ return *str == '\0';
+
+ // Is the first thing in regex an escape sequence?
+ const bool escaped = *regex == '\\';
+ if (escaped)
+ ++regex;
+ if (IsRepeat(regex[1])) {
+ // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+ // here's an indirect recursion. It terminates as the regex gets
+ // shorter in each recursion.
+ return MatchRepetitionAndRegexAtHead(
+ escaped, regex[0], regex[1], regex + 2, str);
+ } else {
+ // regex isn't empty, isn't "$", and doesn't start with a
+ // repetition. We match the first atom of regex with the first
+ // character of str and recurse.
+ return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+ MatchRegexAtHead(regex + 1, str + 1);
+ }
+}
+
+// Returns true iff regex matches any substring of str. regex must be
+// a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally. In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str)
+{
+ if (regex == NULL || str == NULL)
+ return false;
+
+ if (*regex == '^')
+ return MatchRegexAtHead(regex + 1, str);
+
+ // A successful match can be anywhere in str.
+ do {
+ if (MatchRegexAtHead(regex, str))
+ return true;
+ } while (*str++ != '\0');
+ return false;
+}
+
+// Implements the RE class.
+
+RE::~RE()
+{
+ free(const_cast<char*>(pattern_));
+ free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re)
+{
+ return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re)
+{
+ return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex)
+{
+ pattern_ = full_pattern_ = NULL;
+ if (regex != NULL) {
+ pattern_ = posix::StrDup(regex);
+ }
+
+ is_valid_ = ValidateRegex(regex);
+ if (!is_valid_) {
+ // No need to calculate the full pattern when the regex is invalid.
+ return;
+ }
+
+ const size_t len = strlen(regex);
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match: we need space to prepend a '^', append a '$', and
+ // terminate the string with '\0'.
+ char* buffer = static_cast<char*>(malloc(len + 3));
+ full_pattern_ = buffer;
+
+ if (*regex != '^')
+ *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'.
+
+ // We don't use snprintf or strncpy, as they trigger a warning when
+ // compiled with VC++ 8.0.
+ memcpy(buffer, regex, len);
+ buffer += len;
+
+ if (len == 0 || regex[len - 1] != '$')
+ *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'.
+
+ *buffer = '\0';
+}
+
+#endif // GTEST_USES_POSIX_RE
+
+const char kUnknownFile[] = "unknown file";
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line)
+{
+ const std::string file_name(file == NULL ? kUnknownFile : file);
+
+ if (line < 0) {
+ return file_name + ":";
+ }
+#ifdef _MSC_VER
+ return file_name + "(" + StreamableToString(line) + "):";
+#else
+ return file_name + ":" + StreamableToString(line) + ":";
+#endif // _MSC_VER
+}
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+// Note that FormatCompilerIndependentFileLocation() does NOT append colon
+// to the file location it produces, unlike FormatFileLocation().
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
+ const char* file, int line)
+{
+ const std::string file_name(file == NULL ? kUnknownFile : file);
+
+ if (line < 0)
+ return file_name;
+ else
+ return file_name + ":" + StreamableToString(line);
+}
+
+
+GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
+ : severity_(severity)
+{
+ const char* const marker =
+ severity == GTEST_INFO ? "[ INFO ]" :
+ severity == GTEST_WARNING ? "[WARNING]" :
+ severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
+ GetStream() << ::std::endl << marker << " "
+ << FormatFileLocation(file, line).c_str() << ": ";
+}
+
+// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+GTestLog::~GTestLog()
+{
+ GetStream() << ::std::endl;
+ if (severity_ == GTEST_FATAL) {
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996)
+#endif // _MSC_VER
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Object that captures an output stream (stdout/stderr).
+class CapturedStream
+{
+ public:
+ // The ctor redirects the stream to a temporary file.
+ explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
+# if GTEST_OS_WINDOWS
+ char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+ char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+
+ ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+ const UINT success = ::GetTempFileNameA(temp_dir_path,
+ "gtest_redir",
+ 0, // Generate unique file name.
+ temp_file_path);
+ GTEST_CHECK_(success != 0)
+ << "Unable to create a temporary file in " << temp_dir_path;
+ const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+ GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
+ << temp_file_path;
+ filename_ = temp_file_path;
+# else
+ // There's no guarantee that a test has write access to the current
+ // directory, so we create the temporary file in the /tmp directory
+ // instead. We use /tmp on most systems, and /sdcard on Android.
+ // That's because Android doesn't have /tmp.
+# if GTEST_OS_LINUX_ANDROID
+ // Note: Android applications are expected to call the framework's
+ // Context.getExternalStorageDirectory() method through JNI to get
+ // the location of the world-writable SD Card directory. However,
+ // this requires a Context handle, which cannot be retrieved
+ // globally from native code. Doing so also precludes running the
+ // code as part of a regular standalone executable, which doesn't
+ // run in a Dalvik process (e.g. when running it through 'adb shell').
+ //
+ // The location /sdcard is directly accessible from native code
+ // and is the only location (unofficially) supported by the Android
+ // team. It's generally a symlink to the real SD Card mount point
+ // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
+ // other OEM-customized locations. Never rely on these, and always
+ // use /sdcard.
+ char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
+# else
+ char name_template[] = "/tmp/captured_stream.XXXXXX";
+# endif // GTEST_OS_LINUX_ANDROID
+ const int captured_fd = mkstemp(name_template);
+ filename_ = name_template;
+# endif // GTEST_OS_WINDOWS
+ fflush(NULL);
+ dup2(captured_fd, fd_);
+ close(captured_fd);
+ }
+
+ ~CapturedStream() {
+ remove(filename_.c_str());
+ }
+
+ std::string GetCapturedString() {
+ if (uncaptured_fd_ != -1) {
+ // Restores the original stream.
+ fflush(NULL);
+ dup2(uncaptured_fd_, fd_);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ FILE* const file = posix::FOpen(filename_.c_str(), "r");
+ const std::string content = ReadEntireFile(file);
+ posix::FClose(file);
+ return content;
+ }
+
+ private:
+ // Reads the entire content of a file as an std::string.
+ static std::string ReadEntireFile(FILE* file);
+
+ // Returns the size (in bytes) of a file.
+ static size_t GetFileSize(FILE* file);
+
+ const int fd_; // A stream to capture.
+ int uncaptured_fd_;
+ // Name of the temporary file holding the stderr output.
+ ::std::string filename_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
+};
+
+// Returns the size (in bytes) of a file.
+size_t CapturedStream::GetFileSize(FILE* file)
+{
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+std::string CapturedStream::ReadEntireFile(FILE* file)
+{
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const std::string content(buffer, bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+# ifdef _MSC_VER
+# pragma warning(pop)
+# endif // _MSC_VER
+
+static CapturedStream* g_captured_stderr = NULL;
+static CapturedStream* g_captured_stdout = NULL;
+
+// Starts capturing an output stream (stdout/stderr).
+void CaptureStream(int fd, const char* stream_name, CapturedStream** stream)
+{
+ if (*stream != NULL) {
+ GTEST_LOG_(FATAL) << "Only one " << stream_name
+ << " capturer can exist at a time.";
+ }
+ *stream = new CapturedStream(fd);
+}
+
+// Stops capturing the output stream and returns the captured string.
+std::string GetCapturedStream(CapturedStream** captured_stream)
+{
+ const std::string content = (*captured_stream)->GetCapturedString();
+
+ delete *captured_stream;
+ *captured_stream = NULL;
+
+ return content;
+}
+
+// Starts capturing stdout.
+void CaptureStdout()
+{
+ CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
+}
+
+// Starts capturing stderr.
+void CaptureStderr()
+{
+ CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
+}
+
+// Stops capturing stdout and returns the captured string.
+std::string GetCapturedStdout()
+{
+ return GetCapturedStream(&g_captured_stdout);
+}
+
+// Stops capturing stderr and returns the captured string.
+std::string GetCapturedStderr()
+{
+ return GetCapturedStream(&g_captured_stderr);
+}
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+::std::vector<testing::internal::string> g_argvs;
+
+static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
+ NULL; // Owned.
+
+void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs)
+{
+ if (g_injected_test_argvs != argvs)
+ delete g_injected_test_argvs;
+ g_injected_test_argvs = argvs;
+}
+
+const ::std::vector<testing::internal::string>& GetInjectableArgvs()
+{
+ if (g_injected_test_argvs != NULL) {
+ return *g_injected_test_argvs;
+ }
+ return g_argvs;
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS_MOBILE
+namespace posix
+{
+void Abort()
+{
+ DebugBreak();
+ TerminateProcess(GetCurrentProcess(), 1);
+}
+} // namespace posix
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Returns the name of the environment variable corresponding to the
+// given flag. For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static std::string FlagToEnvVar(const char* flag)
+{
+ const std::string full_flag =
+ (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+ Message env_var;
+ for (size_t i = 0; i != full_flag.length(); i++) {
+ env_var << ToUpper(full_flag.c_str()[i]);
+ }
+
+ return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value)
+{
+ // Parses the environment variable as a decimal integer.
+ char* end = NULL;
+ const long long_value = strtol(str, &end, 10); // NOLINT
+
+ // Has strtol() consumed all characters in the string?
+ if (*end != '\0') {
+ // No - an invalid character was encountered.
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value \"" << str << "\".\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ // Is the parsed value in the range of an Int32?
+ const Int32 result = static_cast<Int32>(long_value);
+ if (long_value == LONG_MAX || long_value == LONG_MIN ||
+ // The parsed value overflows as a long. (strtol() returns
+ // LONG_MAX or LONG_MIN when the input overflows.)
+ result != long_value
+ // The parsed value overflows as an Int32.
+ ) {
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value " << str << ", which overflows.\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ *value = result;
+ return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value)
+{
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ return string_value == NULL ?
+ default_value : strcmp(string_value, "0") != 0;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value)
+{
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ if (string_value == NULL) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ Int32 result = default_value;
+ if (!ParseInt32(Message() << "Environment variable " << env_var,
+ string_value, &result)) {
+ printf("The default value %s is used.\n",
+ (Message() << default_value).GetString().c_str());
+ fflush(stdout);
+ return default_value;
+ }
+
+ return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value)
+{
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const value = posix::GetEnv(env_var.c_str());
+ return value == NULL ? default_value : value;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest-printers.cc b/external/gtest-1.6.0/src/gtest-printers.cc
new file mode 100644
index 0000000..cd7dff1
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-printers.cc
@@ -0,0 +1,388 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// It uses the << operator when possible, and prints the bytes in the
+// object otherwise. A user can override its behavior for a class
+// type Foo by defining either operator<<(::std::ostream&, const Foo&)
+// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
+// defines Foo.
+
+#include "gtest/gtest-printers.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <ostream> // NOLINT
+#include <string>
+#include "gtest/internal/gtest-port.h"
+
+namespace testing
+{
+
+namespace
+{
+
+using ::std::ostream;
+
+// Prints a segment of bytes in the given object.
+void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
+ size_t count, ostream* os)
+{
+ char text[5] = "";
+ for (size_t i = 0; i != count; i++) {
+ const size_t j = start + i;
+ if (i != 0) {
+ // Organizes the bytes into groups of 2 for easy parsing by
+ // human.
+ if ((j % 2) == 0)
+ *os << ' ';
+ else
+ *os << '-';
+ }
+ GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
+ *os << text;
+ }
+}
+
+// Prints the bytes in the given value to the given ostream.
+void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
+ ostream* os)
+{
+ // Tells the user how big the object is.
+ *os << count << "-byte object <";
+
+ const size_t kThreshold = 132;
+ const size_t kChunkSize = 64;
+ // If the object size is bigger than kThreshold, we'll have to omit
+ // some details by printing only the first and the last kChunkSize
+ // bytes.
+ // TODO(wan): let the user control the threshold using a flag.
+ if (count < kThreshold) {
+ PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
+ } else {
+ PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
+ *os << " ... ";
+ // Rounds up to 2-byte boundary.
+ const size_t resume_pos = (count - kChunkSize + 1)/2*2;
+ PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
+ }
+ *os << ">";
+}
+
+} // namespace
+
+namespace internal2
+{
+
+// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
+// given object. The delegation simplifies the implementation, which
+// uses the << operator and thus is easier done outside of the
+// ::testing::internal namespace, which contains a << operator that
+// sometimes conflicts with the one in STL.
+void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
+ ostream* os)
+{
+ PrintBytesInObjectToImpl(obj_bytes, count, os);
+}
+
+} // namespace internal2
+
+namespace internal
+{
+
+// Depending on the value of a char (or wchar_t), we print it in one
+// of three formats:
+// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
+// - as a hexidecimal escape sequence (e.g. '\x7F'), or
+// - as a special escape sequence (e.g. '\r', '\n').
+enum CharFormat {
+ kAsIs,
+ kHexEscape,
+ kSpecialEscape
+};
+
+// Returns true if c is a printable ASCII character. We test the
+// value of c directly instead of calling isprint(), which is buggy on
+// Windows Mobile.
+inline bool IsPrintableAscii(wchar_t c)
+{
+ return 0x20 <= c && c <= 0x7E;
+}
+
+// Prints a wide or narrow char c as a character literal without the
+// quotes, escaping it when necessary; returns how c was formatted.
+// The template argument UnsignedChar is the unsigned version of Char,
+// which is the type of c.
+template <typename UnsignedChar, typename Char>
+static CharFormat PrintAsCharLiteralTo(Char c, ostream* os)
+{
+ switch (static_cast<wchar_t>(c)) {
+ case L'\0':
+ *os << "\\0";
+ break;
+ case L'\'':
+ *os << "\\'";
+ break;
+ case L'\\':
+ *os << "\\\\";
+ break;
+ case L'\a':
+ *os << "\\a";
+ break;
+ case L'\b':
+ *os << "\\b";
+ break;
+ case L'\f':
+ *os << "\\f";
+ break;
+ case L'\n':
+ *os << "\\n";
+ break;
+ case L'\r':
+ *os << "\\r";
+ break;
+ case L'\t':
+ *os << "\\t";
+ break;
+ case L'\v':
+ *os << "\\v";
+ break;
+ default:
+ if (IsPrintableAscii(c)) {
+ *os << static_cast<char>(c);
+ return kAsIs;
+ } else {
+ *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
+ return kHexEscape;
+ }
+ }
+ return kSpecialEscape;
+}
+
+// Prints a wchar_t c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os)
+{
+ switch (c) {
+ case L'\'':
+ *os << "'";
+ return kAsIs;
+ case L'"':
+ *os << "\\\"";
+ return kSpecialEscape;
+ default:
+ return PrintAsCharLiteralTo<wchar_t>(c, os);
+ }
+}
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char c, ostream* os)
+{
+ return PrintAsStringLiteralTo(
+ static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
+}
+
+// Prints a wide or narrow character c and its code. '\0' is printed
+// as "'\\0'", other unprintable characters are also properly escaped
+// using the standard C++ escape sequence. The template argument
+// UnsignedChar is the unsigned version of Char, which is the type of c.
+template <typename UnsignedChar, typename Char>
+void PrintCharAndCodeTo(Char c, ostream* os)
+{
+ // First, print c as a literal in the most readable form we can find.
+ *os << ((sizeof(c) > 1) ? "L'" : "'");
+ const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
+ *os << "'";
+
+ // To aid user debugging, we also print c's code in decimal, unless
+ // it's 0 (in which case c was printed as '\\0', making the code
+ // obvious).
+ if (c == 0)
+ return;
+ *os << " (" << static_cast<int>(c);
+
+ // For more convenience, we print c's code again in hexidecimal,
+ // unless c was already printed in the form '\x##' or the code is in
+ // [1, 9].
+ if (format == kHexEscape || (1 <= c && c <= 9)) {
+ // Do nothing.
+ } else {
+ *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
+ }
+ *os << ")";
+}
+
+void PrintTo(unsigned char c, ::std::ostream* os)
+{
+ PrintCharAndCodeTo<unsigned char>(c, os);
+}
+void PrintTo(signed char c, ::std::ostream* os)
+{
+ PrintCharAndCodeTo<unsigned char>(c, os);
+}
+
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
+void PrintTo(wchar_t wc, ostream* os)
+{
+ PrintCharAndCodeTo<wchar_t>(wc, os);
+}
+
+// Prints the given array of characters to the ostream. CharType must be either
+// char or wchar_t.
+// The array starts at begin, the length is len, it may include '\0' characters
+// and may not be NUL-terminated.
+template <typename CharType>
+static void PrintCharsAsStringTo(
+ const CharType* begin, size_t len, ostream* os)
+{
+ const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
+ *os << kQuoteBegin;
+ bool is_previous_hex = false;
+ for (size_t index = 0; index < len; ++index) {
+ const CharType cur = begin[index];
+ if (is_previous_hex && IsXDigit(cur)) {
+ // Previous character is of '\x..' form and this character can be
+ // interpreted as another hexadecimal digit in its number. Break string to
+ // disambiguate.
+ *os << "\" " << kQuoteBegin;
+ }
+ is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
+ }
+ *os << "\"";
+}
+
+// Prints a (const) char/wchar_t array of 'len' elements, starting at address
+// 'begin'. CharType must be either char or wchar_t.
+template <typename CharType>
+static void UniversalPrintCharArray(
+ const CharType* begin, size_t len, ostream* os)
+{
+ // The code
+ // const char kFoo[] = "foo";
+ // generates an array of 4, not 3, elements, with the last one being '\0'.
+ //
+ // Therefore when printing a char array, we don't print the last element if
+ // it's '\0', such that the output matches the string literal as it's
+ // written in the source code.
+ if (len > 0 && begin[len - 1] == '\0') {
+ PrintCharsAsStringTo(begin, len - 1, os);
+ return;
+ }
+
+ // If, however, the last element in the array is not '\0', e.g.
+ // const char kFoo[] = { 'f', 'o', 'o' };
+ // we must print the entire array. We also print a message to indicate
+ // that the array is not NUL-terminated.
+ PrintCharsAsStringTo(begin, len, os);
+ *os << " (no terminating NUL)";
+}
+
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os)
+{
+ UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) wchar_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os)
+{
+ UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints the given C string to the ostream.
+void PrintTo(const char* s, ostream* os)
+{
+ if (s == NULL) {
+ *os << "NULL";
+ } else {
+ *os << ImplicitCast_<const void*>(s) << " pointing to ";
+ PrintCharsAsStringTo(s, strlen(s), os);
+ }
+}
+
+// MSVC compiler can be configured to define whar_t as a typedef
+// of unsigned short. Defining an overload for const wchar_t* in that case
+// would cause pointers to unsigned shorts be printed as wide strings,
+// possibly accessing more memory than intended and causing invalid
+// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
+// wchar_t is implemented as a native type.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Prints the given wide C string to the ostream.
+void PrintTo(const wchar_t* s, ostream* os)
+{
+ if (s == NULL) {
+ *os << "NULL";
+ } else {
+ *os << ImplicitCast_<const void*>(s) << " pointing to ";
+ PrintCharsAsStringTo(s, wcslen(s), os);
+ }
+}
+#endif // wchar_t is native
+
+// Prints a ::string object.
+#if GTEST_HAS_GLOBAL_STRING
+void PrintStringTo(const ::string& s, ostream* os)
+{
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+void PrintStringTo(const ::std::string& s, ostream* os)
+{
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+// Prints a ::wstring object.
+#if GTEST_HAS_GLOBAL_WSTRING
+void PrintWideStringTo(const ::wstring& s, ostream* os)
+{
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+void PrintWideStringTo(const ::std::wstring& s, ostream* os)
+{
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+} // namespace internal
+
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest-test-part.cc b/external/gtest-1.6.0/src/gtest-test-part.cc
new file mode 100644
index 0000000..2f04641
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-test-part.cc
@@ -0,0 +1,120 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule at google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include "gtest/gtest-test-part.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+std::string TestPartResult::ExtractSummary(const char* message)
+{
+ const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+ return stack_trace == NULL ? message :
+ std::string(message, stack_trace);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result)
+{
+ return os
+ << result.file_name() << ":" << result.line_number() << ": "
+ << (result.type() == TestPartResult::kSuccess ? "Success" :
+ result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
+ "Non-fatal failure") << ":\n"
+ << result.message() << std::endl;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result)
+{
+ array_.push_back(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const
+{
+ if (index < 0 || index >= size()) {
+ printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+ internal::posix::Abort();
+ }
+
+ return array_[index];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const
+{
+ return static_cast<int>(array_.size());
+}
+
+namespace internal
+{
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+ : has_new_fatal_failure_(false),
+ original_reporter_(GetUnitTestImpl()->
+ GetTestPartResultReporterForCurrentThread())
+{
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper()
+{
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
+ original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+ const TestPartResult& result)
+{
+ if (result.fatally_failed())
+ has_new_fatal_failure_ = true;
+ original_reporter_->ReportTestPartResult(result);
+}
+
+} // namespace internal
+
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest-typed-test.cc b/external/gtest-1.6.0/src/gtest-typed-test.cc
new file mode 100644
index 0000000..bfbfaf3
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest-typed-test.cc
@@ -0,0 +1,114 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest-typed-test.h"
+#include "gtest/gtest.h"
+
+namespace testing
+{
+namespace internal
+{
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Skips to the first non-space char in str. Returns an empty string if str
+// contains only whitespace characters.
+static const char* SkipSpaces(const char* str)
+{
+ while (IsSpace(*str))
+ str++;
+ return str;
+}
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests)
+{
+ typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+ registered_ = true;
+
+ // Skip initial whitespace in registered_tests since some
+ // preprocessors prefix stringizied literals with whitespace.
+ registered_tests = SkipSpaces(registered_tests);
+
+ Message errors;
+ ::std::set<std::string> tests;
+ for (const char* names = registered_tests; names != NULL;
+ names = SkipComma(names)) {
+ const std::string name = GetPrefixUntilComma(names);
+ if (tests.count(name) != 0) {
+ errors << "Test " << name << " is listed more than once.\n";
+ continue;
+ }
+
+ bool found = false;
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (name == *it) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ tests.insert(name);
+ } else {
+ errors << "No test named " << name
+ << " can be found in this test case.\n";
+ }
+ }
+
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (tests.count(*it) == 0) {
+ errors << "You forgot to list test " << *it << ".\n";
+ }
+ }
+
+ const std::string& errors_str = errors.GetString();
+ if (errors_str != "") {
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors_str.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+
+ return registered_tests;
+}
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest.cc b/external/gtest-1.6.0/src/gtest.cc
new file mode 100644
index 0000000..e872eb4
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest.cc
@@ -0,0 +1,5253 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include "gtest/gtest.h"
+#include "gtest/gtest-spi.h"
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <limits>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <vector>
+
+#if GTEST_OS_LINUX
+
+// TODO(kenton at google.com): Use autoconf to detect availability of
+// gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+# include <fcntl.h> // NOLINT
+# include <limits.h> // NOLINT
+# include <sched.h> // NOLINT
+// Declares vsnprintf(). This header is not available on Windows.
+# include <strings.h> // NOLINT
+# include <sys/mman.h> // NOLINT
+# include <sys/time.h> // NOLINT
+# include <unistd.h> // NOLINT
+# include <string>
+
+#elif GTEST_OS_SYMBIAN
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h> // NOLINT
+
+#elif GTEST_OS_ZOS
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h> // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+# include <strings.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
+
+# include <windows.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS // We are on Windows proper.
+
+# include <io.h> // NOLINT
+# include <sys/timeb.h> // NOLINT
+# include <sys/types.h> // NOLINT
+# include <sys/stat.h> // NOLINT
+
+# if GTEST_OS_WINDOWS_MINGW
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton at google.com): Use autoconf to detect availability of
+// gettimeofday().
+// TODO(kenton at google.com): There are other ways to get the time on
+// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW
+// supports these. consider using them instead.
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h> // NOLINT
+# endif // GTEST_OS_WINDOWS_MINGW
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <windows.h> // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton at google.com): Use autoconf to detect availability of
+// gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <sys/time.h> // NOLINT
+# include <unistd.h> // NOLINT
+
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h> // NOLINT
+# include <netdb.h> // NOLINT
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS
+# define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+namespace testing
+{
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal
+{
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+bool g_help_flag = false;
+
+} // namespace internal
+
+static const char* GetDefaultFilter()
+{
+ return kUniversalFilter;
+}
+
+GTEST_DEFINE_bool_(
+ also_run_disabled_tests,
+ internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+ "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+ break_on_failure,
+ internal::BoolFromGTestEnv("break_on_failure", false),
+ "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+ catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", true),
+ "True iff " GTEST_NAME_
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+ color,
+ internal::StringFromGTestEnv("color", "auto"),
+ "Whether to use colors in the output. Valid values: yes, no, "
+ "and auto. 'auto' means to use colors if the output is "
+ "being sent to a terminal and the TERM environment variable "
+ "is set to a terminal type that supports colors.");
+
+GTEST_DEFINE_string_(
+ filter,
+ internal::StringFromGTestEnv("filter", GetDefaultFilter()),
+ "A colon-separated list of glob (not regex) patterns "
+ "for filtering the tests to run, optionally followed by a "
+ "'-' and a : separated list of negative patterns (tests to "
+ "exclude). A test is run if it matches one of the positive "
+ "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+ "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+ output,
+ internal::StringFromGTestEnv("output", ""),
+ "A format (currently must be \"xml\"), optionally followed "
+ "by a colon and an output file name or directory. A directory "
+ "is indicated by a trailing pathname separator. "
+ "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+ "If a directory is specified, output files will be created "
+ "within that directory, with file-names based on the test "
+ "executable's name and, if necessary, made unique by adding "
+ "digits.");
+
+GTEST_DEFINE_bool_(
+ print_time,
+ internal::BoolFromGTestEnv("print_time", true),
+ "True iff " GTEST_NAME_
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+ random_seed,
+ internal::Int32FromGTestEnv("random_seed", 0),
+ "Random number seed to use when shuffling test orders. Must be in range "
+ "[1, 99999], or 0 to use a seed based on the current time.");
+
+GTEST_DEFINE_int32_(
+ repeat,
+ internal::Int32FromGTestEnv("repeat", 1),
+ "How many times to repeat each test. Specify a negative number "
+ "for repeating forever. Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_bool_(
+ show_internal_stack_frames, false,
+ "True iff " GTEST_NAME_ " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(
+ shuffle,
+ internal::BoolFromGTestEnv("shuffle", false),
+ "True iff " GTEST_NAME_
+ " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+ stack_trace_depth,
+ internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+ "The maximum number of stack frames to print when an "
+ "assertion fails. The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_string_(
+ stream_result_to,
+ internal::StringFromGTestEnv("stream_result_to", ""),
+ "This flag specifies the host name and the port number on which to stream "
+ "test results. Example: \"localhost:555\". The flag is effective only on "
+ "Linux.");
+
+GTEST_DEFINE_bool_(
+ throw_on_failure,
+ internal::BoolFromGTestEnv("throw_on_failure", false),
+ "When this flag is specified, a failed assertion will throw an exception "
+ "if exceptions are enabled or exit the program with a non-zero code "
+ "otherwise.");
+
+namespace internal
+{
+
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG). Crashes if 'range' is 0 or greater
+// than kMaxRange.
+UInt32 Random::Generate(UInt32 range)
+{
+ // These constants are the same as are used in glibc's rand(3).
+ state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+
+ GTEST_CHECK_(range > 0)
+ << "Cannot generate a number in the range [0, 0).";
+ GTEST_CHECK_(range <= kMaxRange)
+ << "Generation of a number in [0, " << range << ") was requested, "
+ << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+ // Converting via modulus introduces a bit of downward bias, but
+ // it's simple, and a linear congruential generator isn't too good
+ // to begin with.
+ return state_ % range;
+}
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test. g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called. We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+GTEST_API_ int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a vector of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
+ int (TestCase::*method)() const)
+{
+ int sum = 0;
+ for (size_t i = 0; i < case_list.size(); i++) {
+ sum += (case_list[i]->*method)();
+ }
+ return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case)
+{
+ return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case)
+{
+ return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case)
+{
+ return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message)
+ : data_(new AssertHelperData(type, file, line, message))
+{
+}
+
+AssertHelper::~AssertHelper()
+{
+ delete data_;
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const
+{
+ UnitTest::GetInstance()->
+ AddTestPartResult(data_->type, data_->file, data_->line,
+ AppendUserMessage(data_->message, message),
+ UnitTest::GetInstance()->impl()
+ ->CurrentOsStackTraceExceptTop(1)
+ // Skips the stack frame for this function itself.
+ ); // NOLINT
+}
+
+// Mutex for linked pointers.
+GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// Application pathname gotten in InitGoogleTest.
+std::string g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName()
+{
+ FilePath result;
+
+#if GTEST_OS_WINDOWS
+ result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(g_executable_path));
+#endif // GTEST_OS_WINDOWS
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+std::string UnitTestOptions::GetOutputFormat()
+{
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL) return std::string("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == NULL) ?
+ std::string(gtest_output_flag) :
+ std::string(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+std::string UnitTestOptions::GetAbsolutePathToOutputFile()
+{
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL)
+ return "";
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == NULL)
+ return internal::FilePath::ConcatPaths(
+ internal::FilePath(
+ UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(kDefaultOutputFile)).string();
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsAbsolutePath())
+ // TODO(wan at google.com): on Windows \some\path is not an absolute
+ // path (as its meaning depends on the current drive), yet the
+ // following logic for turning it into an absolute path is wrong.
+ // Fix it.
+ output_name = internal::FilePath::ConcatPaths(
+ internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(colon + 1));
+
+ if (!output_name.IsDirectory())
+ return output_name.string();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.string();
+}
+
+// Returns true iff the wildcard pattern matches the string. The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char* pattern,
+ const char* str)
+{
+ switch (*pattern) {
+ case '\0':
+ case ':': // Either ':' or '\0' marks the end of the pattern.
+ return *str == '\0';
+ case '?': // Matches any single character.
+ return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+ case '*': // Matches any string (possibly empty) of characters.
+ return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+ PatternMatchesString(pattern + 1, str);
+ default: // Non-special character. Matches itself.
+ return *pattern == *str &&
+ PatternMatchesString(pattern + 1, str + 1);
+ }
+}
+
+bool UnitTestOptions::MatchesFilter(
+ const std::string& name, const char* filter)
+{
+ const char* cur_pattern = filter;
+ for (;;) {
+ if (PatternMatchesString(cur_pattern, name.c_str())) {
+ return true;
+ }
+
+ // Finds the next pattern in the filter.
+ cur_pattern = strchr(cur_pattern, ':');
+
+ // Returns if no more pattern can be found.
+ if (cur_pattern == NULL) {
+ return false;
+ }
+
+ // Skips the pattern separater (the ':' character).
+ cur_pattern++;
+ }
+}
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const std::string& test_case_name,
+ const std::string& test_name)
+{
+ const std::string& full_name = test_case_name + "." + test_name.c_str();
+
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ const char* const p = GTEST_FLAG(filter).c_str();
+ const char* const dash = strchr(p, '-');
+ std::string positive;
+ std::string negative;
+ if (dash == NULL) {
+ positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
+ negative = "";
+ } else {
+ positive = std::string(p, dash); // Everything up to the dash
+ negative = std::string(dash + 1); // Everything after the dash
+ if (positive.empty()) {
+ // Treat '-test1' as the same as '*-test1'
+ positive = kUniversalFilter;
+ }
+ }
+
+ // A filter is a colon-separated list of patterns. It matches a
+ // test if any pattern in it matches the test.
+ return (MatchesFilter(full_name, positive.c_str()) &&
+ !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_HAS_SEH
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code)
+{
+ // Google Test should handle a SEH exception if:
+ // 1. the user wants it to, AND
+ // 2. this is not a breakpoint exception, AND
+ // 3. this is not a C++ exception (VC++ implements them via SEH,
+ // apparently).
+ //
+ // SEH exception code for C++ exceptions.
+ // (see http://support.microsoft.com/kb/185294 for more information).
+ const DWORD kCxxExceptionCode = 0xe06d7363;
+
+ bool should_handle = true;
+
+ if (!GTEST_FLAG(catch_exceptions))
+ should_handle = false;
+ else if (exception_code == EXCEPTION_BREAKPOINT)
+ should_handle = false;
+ else if (exception_code == kCxxExceptionCode)
+ should_handle = false;
+
+ return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // GTEST_HAS_SEH
+
+} // namespace internal
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ TestPartResultArray* result)
+ : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+ result_(result)
+{
+ Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ InterceptMode intercept_mode, TestPartResultArray* result)
+ : intercept_mode_(intercept_mode),
+ result_(result)
+{
+ Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init()
+{
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ old_reporter_ = impl->GetGlobalTestPartResultReporter();
+ impl->SetGlobalTestPartResultReporter(this);
+ } else {
+ old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+ impl->SetTestPartResultReporterForCurrentThread(this);
+ }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter()
+{
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ impl->SetGlobalTestPartResultReporter(old_reporter_);
+ } else {
+ impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+ }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result)
+{
+ result_->Append(result);
+}
+
+namespace internal
+{
+
+// Returns the type ID of ::testing::Test. We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test. This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X. The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code. GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId()
+{
+ return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResult::Type type,
+ const string& substr)
+{
+ const std::string expected(type == TestPartResult::kFatalFailure ?
+ "1 fatal failure" :
+ "1 non-fatal failure");
+ Message msg;
+ if (results.size() != 1) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual: " << results.size() << " failures";
+ for (int i = 0; i < results.size(); i++) {
+ msg << "\n" << results.GetTestPartResult(i);
+ }
+ return AssertionFailure() << msg;
+ }
+
+ const TestPartResult& r = results.GetTestPartResult(0);
+ if (r.type() != type) {
+ return AssertionFailure() << "Expected: " << expected << "\n"
+ << " Actual:\n"
+ << r;
+ }
+
+ if (strstr(r.message(), substr.c_str()) == NULL) {
+ return AssertionFailure() << "Expected: " << expected << " containing \""
+ << substr << "\"\n"
+ << " Actual:\n"
+ << r;
+ }
+
+ return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+ const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const string& substr)
+ : results_(results),
+ type_(type),
+ substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker()
+{
+ EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_);
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result)
+{
+ unit_test_->current_test_result()->AddTestPartResult(result);
+ unit_test_->listeners()->repeater()->OnTestPartResult(result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result)
+{
+ unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter()
+{
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter)
+{
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread()
+{
+ return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter)
+{
+ per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const
+{
+ return CountIf(test_cases_, TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const
+{
+ return CountIf(test_cases_, TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const
+{
+ return static_cast<int>(test_cases_.size());
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const
+{
+ return CountIf(test_cases_, ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const
+{
+ return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const
+{
+ return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTestImpl::reportable_disabled_test_count() const
+{
+ return SumOverTestCaseList(test_cases_,
+ &TestCase::reportable_disabled_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const
+{
+ return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTestImpl::reportable_test_count() const
+{
+ return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const
+{
+ return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const
+{
+ return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count)
+{
+ (void)skip_count;
+ return "";
+}
+
+// Returns the current time in milliseconds.
+TimeInMillis GetTimeInMillis()
+{
+#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
+ // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
+ // http://analogous.blogspot.com/2005/04/epoch.html
+ const TimeInMillis kJavaEpochToWinFileTimeDelta =
+ static_cast<TimeInMillis>(116444736UL) * 100000UL;
+ const DWORD kTenthMicrosInMilliSecond = 10000;
+
+ SYSTEMTIME now_systime;
+ FILETIME now_filetime;
+ ULARGE_INTEGER now_int64;
+ // TODO(kenton at google.com): Shouldn't this just use
+ // GetSystemTimeAsFileTime()?
+ GetSystemTime(&now_systime);
+ if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+ now_int64.LowPart = now_filetime.dwLowDateTime;
+ now_int64.HighPart = now_filetime.dwHighDateTime;
+ now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+ kJavaEpochToWinFileTimeDelta;
+ return now_int64.QuadPart;
+ }
+ return 0;
+#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
+ __timeb64 now;
+
+# ifdef _MSC_VER
+
+ // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+ // (deprecated function) there.
+ // TODO(kenton at google.com): Use GetTickCount()? Or use
+ // SystemTimeToFileTime()
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4996) // Temporarily disables warning 4996.
+ _ftime64(&now);
+# pragma warning(pop) // Restores the warning state.
+# else
+
+ _ftime64(&now);
+
+# endif // _MSC_VER
+
+ return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif GTEST_HAS_GETTIMEOFDAY_
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+# error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String.
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi)
+{
+ if (!ansi) return NULL;
+ const int length = strlen(ansi);
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ NULL, 0);
+ WCHAR* unicode = new WCHAR[unicode_length + 1];
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ unicode, unicode_length);
+ unicode[unicode_length] = 0;
+ return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str)
+{
+ if (!utf16_str) return NULL;
+ const int ansi_length =
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ NULL, 0, NULL, NULL);
+ char* ansi = new char[ansi_length + 1];
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ ansi, ansi_length, NULL, NULL);
+ ansi[ansi_length] = 0;
+ return ansi;
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings. Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char* lhs, const char* rhs)
+{
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
+ Message* msg)
+{
+ for (size_t i = 0; i != length;) { // NOLINT
+ if (wstr[i] != L'\0') {
+ *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+ while (i != length && wstr[i] != L'\0')
+ i++;
+ } else {
+ *msg << '\0';
+ i++;
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+} // namespace internal
+
+// Constructs an empty Message.
+// We allocate the stringstream separately because otherwise each use of
+// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+// stack frame leading to huge stack frames in some cases; gcc does not reuse
+// the stack space.
+Message::Message() : ss_(new ::std::stringstream)
+{
+ // By default, we want there to be enough precision when printing
+ // a double to a Message.
+ *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
+}
+
+// These two overloads allow streaming a wide C string to a Message
+// using the UTF-8 encoding.
+Message& Message::operator <<(const wchar_t* wide_c_str)
+{
+ return *this << internal::String::ShowWideCString(wide_c_str);
+}
+Message& Message::operator <<(wchar_t* wide_c_str)
+{
+ return *this << internal::String::ShowWideCString(wide_c_str);
+}
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr)
+{
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr)
+{
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Gets the text streamed to this object so far as an std::string.
+// Each '\0' character in the buffer is replaced with "\\0".
+std::string Message::GetString() const
+{
+ return internal::StringStreamToString(ss_.get());
+}
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+ : success_(other.success_),
+ message_(other.message_.get() != NULL ?
+ new ::std::string(*other.message_) :
+ static_cast< ::std::string*>(NULL))
+{
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const
+{
+ AssertionResult negation(!success_);
+ if (message_.get() != NULL)
+ negation << *message_;
+ return negation;
+}
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess()
+{
+ return AssertionResult(true);
+}
+
+// Makes a failed assertion result.
+AssertionResult AssertionFailure()
+{
+ return AssertionResult(false);
+}
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << message.
+AssertionResult AssertionFailure(const Message& message)
+{
+ return AssertionFailure() << message;
+}
+
+namespace internal
+{
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const std::string& expected_value,
+ const std::string& actual_value,
+ bool ignoring_case)
+{
+ Message msg;
+ msg << "Value of: " << actual_expression;
+ if (actual_value != actual_expression) {
+ msg << "\n Actual: " << actual_value;
+ }
+
+ msg << "\nExpected: " << expected_expression;
+ if (ignoring_case) {
+ msg << " (ignoring case)";
+ }
+ if (expected_value != expected_expression) {
+ msg << "\nWhich is: " << expected_value;
+ }
+
+ return AssertionFailure() << msg;
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+std::string GetBoolAssertionFailureMessage(
+ const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value)
+{
+ const char* actual_message = assertion_result.message();
+ Message msg;
+ msg << "Value of: " << expression_text
+ << "\n Actual: " << actual_predicate_value;
+ if (actual_message[0] != '\0')
+ msg << " (" << actual_message << ")";
+ msg << "\nExpected: " << expected_predicate_value;
+ return msg.GetString();
+}
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error)
+{
+ const double diff = fabs(val1 - val2);
+ if (diff <= abs_error) return AssertionSuccess();
+
+ // TODO(wan): do not print the value of an expression if it's
+ // already a literal.
+ return AssertionFailure()
+ << "The difference between " << expr1 << " and " << expr2
+ << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ", and\n"
+ << abs_error_expr << " evaluates to " << abs_error << ".";
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+ const char* expr2,
+ RawType val1,
+ RawType val2)
+{
+ // Returns success if val1 is less than val2,
+ if (val1 < val2) {
+ return AssertionSuccess();
+ }
+
+ // or if val1 is almost equal to val2.
+ const FloatingPoint<RawType> lhs(val1), rhs(val2);
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ // Note that the above two checks will both fail if either val1 or
+ // val2 is NaN, as the IEEE floating-point standard requires that
+ // any predicate involving a NaN must return false.
+
+ ::std::stringstream val1_ss;
+ val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val1;
+
+ ::std::stringstream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val2;
+
+ return AssertionFailure()
+ << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+ << " Actual: " << StringStreamToString(&val1_ss) << " vs "
+ << StringStreamToString(&val2_ss);
+}
+
+} // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2)
+{
+ return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2)
+{
+ return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal
+{
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual)
+{
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ return AssertionFailure() \
+ << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, <)
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, >)
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual)
+{
+ if (String::CStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ PrintToString(expected),
+ PrintToString(actual),
+ false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual)
+{
+ if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ PrintToString(expected),
+ PrintToString(actual),
+ true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2)
+{
+ if (!String::CStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2)
+{
+ if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ return AssertionFailure()
+ << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << ") (ignoring case), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ }
+}
+
+} // namespace internal
+
+namespace
+{
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack. NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack)
+{
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack)
+{
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+ const StringType& haystack)
+{
+ return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+ bool expected_to_be_substring,
+ const char* needle_expr, const char* haystack_expr,
+ const StringType& needle, const StringType& haystack)
+{
+ if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(needle[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure()
+ << "Value of: " << needle_expr << "\n"
+ << " Actual: " << begin_string_quote << needle << "\"\n"
+ << "Expected: " << (expected_to_be_substring ? "" : "not ")
+ << "a substring of " << haystack_expr << "\n"
+ << "Which is: " << begin_string_quote << haystack << "\"";
+}
+
+} // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack)
+{
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack)
+{
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack)
+{
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack)
+{
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack)
+{
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack)
+{
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack)
+{
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack)
+{
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal
+{
+
+#if GTEST_OS_WINDOWS
+
+namespace
+{
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+ const char* expected,
+ long hr) // NOLINT
+{
+# if GTEST_OS_WINDOWS_MOBILE
+
+ // Windows CE doesn't support FormatMessage.
+ const char error_text[] = "";
+
+# else
+
+ // Looks up the human-readable system message for the HRESULT code
+ // and since we're not passing any params to FormatMessage, we don't
+ // want inserts expanded.
+ const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+ const DWORD kBufSize = 4096;
+ // Gets the system's human readable message string for this HRESULT.
+ char error_text[kBufSize] = { '\0' };
+ DWORD message_length = ::FormatMessageA(kFlags,
+ 0, // no source, we're asking system
+ hr, // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ NULL); // no arguments for inserts
+ // Trims tailing white space (FormatMessage leaves a trailing CR-LF)
+ for (; message_length && IsSpace(error_text[message_length - 1]);
+ --message_length) {
+ error_text[message_length - 1] = '\0';
+ }
+
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+ const std::string error_hex("0x" + String::FormatHexInt(hr));
+ return ::testing::AssertionFailure()
+ << "Expected: " << expr << " " << expected << ".\n"
+ << " Actual: " << error_hex << " " << error_text << "\n";
+}
+
+} // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) // NOLINT
+{
+ if (SUCCEEDED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) // NOLINT
+{
+ if (FAILED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length Encoding
+// 0 - 7 bits 0xxxxxxx
+// 8 - 11 bits 110xxxxx 10xxxxxx
+// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
+// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern. Returns the n
+// lowest bits. As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n)
+{
+ const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+ *bits >>= n;
+ return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+std::string CodePointToUtf8(UInt32 code_point)
+{
+ if (code_point > kMaxCodePoint4) {
+ return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")";
+ }
+
+ char str[5]; // Big enough for the largest valid code point.
+ if (code_point <= kMaxCodePoint1) {
+ str[1] = '\0';
+ str[0] = static_cast<char>(code_point); // 0xxxxxxx
+ } else if (code_point <= kMaxCodePoint2) {
+ str[2] = '\0';
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
+ } else if (code_point <= kMaxCodePoint3) {
+ str[3] = '\0';
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
+ } else { // code_point <= kMaxCodePoint4
+ str[4] = '\0';
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
+ }
+ return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second)
+{
+ return sizeof(wchar_t) == 2 &&
+ (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+ wchar_t second)
+{
+ const UInt32 mask = (1 << 10) - 1;
+ return (sizeof(wchar_t) == 2) ?
+ (((first & mask) << 10) | (second & mask)) + 0x10000 :
+ // This function should not be called when the condition is
+ // false, but we provide a sensible default in case it is.
+ static_cast<UInt32>(first);
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+std::string WideStringToUtf8(const wchar_t* str, int num_chars)
+{
+ if (num_chars == -1)
+ num_chars = static_cast<int>(wcslen(str));
+
+ ::std::stringstream stream;
+ for (int i = 0; i < num_chars; ++i) {
+ UInt32 unicode_code_point;
+
+ if (str[i] == L'\0') {
+ break;
+ } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+ unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+ str[i + 1]);
+ i++;
+ } else {
+ unicode_code_point = static_cast<UInt32>(str[i]);
+ }
+
+ stream << CodePointToUtf8(unicode_code_point);
+ }
+ return StringStreamToString(&stream);
+}
+
+// Converts a wide C string to an std::string using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+std::string String::ShowWideCString(const wchar_t* wide_c_str)
+{
+ if (wide_c_str == NULL) return "(null)";
+
+ return internal::WideStringToUtf8(wide_c_str, -1);
+}
+
+// Compares two wide C strings. Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs)
+{
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual)
+{
+ if (String::WideCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ PrintToString(expected),
+ PrintToString(actual),
+ false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2)
+{
+ if (!String::WideCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ }
+
+ return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: "
+ << PrintToString(s1)
+ << " vs " << PrintToString(s2);
+}
+
+// Compares two C strings, ignoring case. Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s). A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char* lhs, const char* rhs)
+{
+ if (lhs == NULL)
+ return rhs == NULL;
+ if (rhs == NULL)
+ return false;
+ return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+// Compares two wide C strings, ignoring case. Returns true iff they
+// have the same content.
+//
+// Unlike wcscasecmp(), this function can handle NULL argument(s).
+// A NULL C string is considered different to any non-NULL wide C string,
+// including the empty string.
+// NB: The implementations on different platforms slightly differ.
+// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+// environment variable. On GNU platform this method uses wcscasecmp
+// which compares according to LC_CTYPE category of the current locale.
+// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+// current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs)
+{
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+#if GTEST_OS_WINDOWS
+ return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID
+ return wcscasecmp(lhs, rhs) == 0;
+#else
+ // Android, Mac OS X and Cygwin don't define wcscasecmp.
+ // Other unknown OSes may not define it either.
+ wint_t left, right;
+ do {
+ left = towlower(*lhs++);
+ right = towlower(*rhs++);
+ } while (left && left == right);
+ return left == right;
+#endif // OS selector
+}
+
+// Returns true iff str ends with the given suffix, ignoring case.
+// Any string is considered to end with an empty suffix.
+bool String::EndsWithCaseInsensitive(
+ const std::string& str, const std::string& suffix)
+{
+ const size_t str_len = str.length();
+ const size_t suffix_len = suffix.length();
+ return (str_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len,
+ suffix.c_str());
+}
+
+// Formats an int value as "%02d".
+std::string String::FormatIntWidth2(int value)
+{
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(2) << value;
+ return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexInt(int value)
+{
+ std::stringstream ss;
+ ss << std::hex << std::uppercase << value;
+ return ss.str();
+}
+
+// Formats a byte as "%02X".
+std::string String::FormatByte(unsigned char value)
+{
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
+ << static_cast<unsigned int>(value);
+ return ss.str();
+}
+
+// Converts the buffer in a stringstream to an std::string, converting NUL
+// bytes to "\\0" along the way.
+std::string StringStreamToString(::std::stringstream* ss)
+{
+ const ::std::string& str = ss->str();
+ const char* const start = str.c_str();
+ const char* const end = start + str.length();
+
+ std::string result;
+ result.reserve(2 * (end - start));
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ result += "\\0"; // Replaces NUL with "\\0";
+ } else {
+ result += *ch;
+ }
+ }
+
+ return result;
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+std::string AppendUserMessage(const std::string& gtest_msg,
+ const Message& user_msg)
+{
+ // Appends the user message if it's non-empty.
+ const std::string user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+
+ return gtest_msg + "\n" + user_msg_string;
+}
+
+} // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0),
+ elapsed_time_(0)
+{
+}
+
+// D'tor.
+TestResult::~TestResult()
+{
+}
+
+// Returns the i-th test part result among all the results. i can
+// range from 0 to total_part_count() - 1. If i is not in that range,
+// aborts the program.
+const TestPartResult& TestResult::GetTestPartResult(int i) const
+{
+ if (i < 0 || i >= total_part_count())
+ internal::posix::Abort();
+ return test_part_results_.at(i);
+}
+
+// Returns the i-th test property. i can range from 0 to
+// test_property_count() - 1. If i is not in that range, aborts the
+// program.
+const TestProperty& TestResult::GetTestProperty(int i) const
+{
+ if (i < 0 || i >= test_property_count())
+ internal::posix::Abort();
+ return test_properties_.at(i);
+}
+
+// Clears the test part results.
+void TestResult::ClearTestPartResults()
+{
+ test_part_results_.clear();
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result)
+{
+ test_part_results_.push_back(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const std::string& xml_element,
+ const TestProperty& test_property)
+{
+ if (!ValidateTestProperty(xml_element, test_property)) {
+ return;
+ }
+ internal::MutexLock lock(&test_properites_mutex_);
+ const std::vector<TestProperty>::iterator property_with_matching_key =
+ std::find_if(test_properties_.begin(), test_properties_.end(),
+ internal::TestPropertyKeyIs(test_property.key()));
+ if (property_with_matching_key == test_properties_.end()) {
+ test_properties_.push_back(test_property);
+ return;
+ }
+ property_with_matching_key->SetValue(test_property.value());
+}
+
+// The list of reserved attributes used in the <testsuites> element of XML
+// output.
+static const char* const kReservedTestSuitesAttributes[] = {
+ "disabled",
+ "errors",
+ "failures",
+ "name",
+ "random_seed",
+ "tests",
+ "time",
+ "timestamp"
+};
+
+// The list of reserved attributes used in the <testsuite> element of XML
+// output.
+static const char* const kReservedTestSuiteAttributes[] = {
+ "disabled",
+ "errors",
+ "failures",
+ "name",
+ "tests",
+ "time"
+};
+
+// The list of reserved attributes used in the <testcase> element of XML output.
+static const char* const kReservedTestCaseAttributes[] = {
+ "classname",
+ "name",
+ "status",
+ "time",
+ "type_param",
+ "value_param"
+};
+
+template <int kSize>
+std::vector<std::string> ArrayAsVector(const char* const(&array)[kSize])
+{
+ return std::vector<std::string>(array, array + kSize);
+}
+
+static std::vector<std::string> GetReservedAttributesForElement(
+ const std::string& xml_element)
+{
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
+static std::string FormatWordList(const std::vector<std::string>& words)
+{
+ Message word_list;
+ for (size_t i = 0; i < words.size(); ++i) {
+ if (i > 0 && words.size() > 2) {
+ word_list << ", ";
+ }
+ if (i == words.size() - 1) {
+ word_list << "and ";
+ }
+ word_list << "'" << words[i] << "'";
+ }
+ return word_list.GetString();
+}
+
+bool ValidateTestPropertyName(const std::string& property_name,
+ const std::vector<std::string>& reserved_names)
+{
+ if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
+ reserved_names.end()) {
+ ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
+ << " (" << FormatWordList(reserved_names)
+ << " are reserved by " << GTEST_NAME_ << ")";
+ return false;
+ }
+ return true;
+}
+
+// Adds a failure if the key is a reserved attribute of the element named
+// xml_element. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const std::string& xml_element,
+ const TestProperty& test_property)
+{
+ return ValidateTestPropertyName(test_property.key(),
+ GetReservedAttributesForElement(xml_element));
+}
+
+// Clears the object.
+void TestResult::Clear()
+{
+ test_part_results_.clear();
+ test_properties_.clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true iff the test failed.
+bool TestResult::Failed() const
+{
+ for (int i = 0; i < total_part_count(); ++i) {
+ if (GetTestPartResult(i).failed())
+ return true;
+ }
+ return false;
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result)
+{
+ return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const
+{
+ return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true iff the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result)
+{
+ return result.nonfatally_failed();
+}
+
+// Returns true iff the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const
+{
+ return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts. This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const
+{
+ return static_cast<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const
+{
+ return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+ : gtest_flag_saver_(new internal::GTestFlagSaver)
+{
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test()
+{
+ delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp()
+{
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown()
+{
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, const std::string& value)
+{
+ UnitTest::GetInstance()->RecordProperty(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, int value)
+{
+ Message value_message;
+ value_message << value;
+ RecordProperty(key, value_message.GetString().c_str());
+}
+
+namespace internal
+{
+
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const std::string& message)
+{
+ // This function is a friend of UnitTest and as such has access to
+ // AddTestPartResult.
+ UnitTest::GetInstance()->AddTestPartResult(
+ result_type,
+ NULL, // No info about the source file where the exception occurred.
+ -1, // We have no info on which line caused the exception.
+ message,
+ ""); // No stack trace, either.
+}
+
+} // namespace internal
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class. This function checks if the current test has the
+// same fixture class as the first test in the current test case. If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass()
+{
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ const TestCase* const test_case = impl->current_test_case();
+
+ // Info about the first test in the current test case.
+ const TestInfo* const first_test_info = test_case->test_info_list()[0];
+ const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
+ const char* const first_test_name = first_test_info->name();
+
+ // Info about the current test.
+ const TestInfo* const this_test_info = impl->current_test_info();
+ const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
+ const char* const this_test_name = this_test_info->name();
+
+ if (this_fixture_id != first_fixture_id) {
+ // Is the first test defined using TEST?
+ const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+ // Is this test defined using TEST?
+ const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+ if (first_is_TEST || this_is_TEST) {
+ // The user mixed TEST and TEST_F in this test case - we'll tell
+ // him/her how to fix it.
+
+ // Gets the name of the TEST and the name of the TEST_F. Note
+ // that first_is_TEST and this_is_TEST cannot both be true, as
+ // the fixture IDs are different for the two tests.
+ const char* const TEST_name =
+ first_is_TEST ? first_test_name : this_test_name;
+ const char* const TEST_F_name =
+ first_is_TEST ? this_test_name : first_test_name;
+
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test case is\n"
+ << "illegal. In test case " << this_test_info->test_case_name()
+ << ",\n"
+ << "test " << TEST_F_name << " is defined using TEST_F but\n"
+ << "test " << TEST_name << " is defined using TEST. You probably\n"
+ << "want to change the TEST to TEST_F or move it to another test\n"
+ << "case.";
+ } else {
+ // The user defined two fixture classes with the same name in
+ // two namespaces - we'll tell him/her how to fix it.
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case "
+ << this_test_info->test_case_name() << ",\n"
+ << "you defined test " << first_test_name
+ << " and test " << this_test_name << "\n"
+ << "using two different test fixture classes. This can happen if\n"
+ << "the two classes are from different namespaces or translation\n"
+ << "units and have the same name. You should probably rename one\n"
+ << "of the classes to put the tests into different test cases.";
+ }
+ return false;
+ }
+
+ return true;
+}
+
+#if GTEST_HAS_SEH
+
+// Adds an "exception thrown" fatal failure to the current test. This
+// function returns its result via an output parameter pointer because VC++
+// prohibits creation of objects with destructors on stack in functions
+// using __try (see error C2712).
+static std::string* FormatSehExceptionMessage(DWORD exception_code,
+ const char* location)
+{
+ Message message;
+ message << "SEH exception with code 0x" << std::setbase(16) <<
+ exception_code << std::setbase(10) << " thrown in " << location << ".";
+
+ return new std::string(message.GetString());
+}
+
+#endif // GTEST_HAS_SEH
+
+namespace internal
+{
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static std::string FormatCxxExceptionMessage(const char* description,
+ const char* location)
+{
+ Message message;
+ if (description != NULL) {
+ message << "C++ exception with description \"" << description << "\"";
+ } else {
+ message << "Unknown C++ exception";
+ }
+ message << " thrown in " << location << ".";
+
+ return message.GetString();
+}
+
+static std::string PrintTestPartResultToString(
+ const TestPartResult& test_part_result);
+
+GoogleTestFailureException::GoogleTestFailureException(
+ const TestPartResult& failure)
+ : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// We put these helper functions in the internal namespace as IBM's xlC
+// compiler rejects the code if they were declared static.
+
+// Runs the given method and handles SEH exceptions it throws, when
+// SEH is supported; returns the 0-value for type Result in case of an
+// SEH exception. (Microsoft compilers cannot handle SEH and C++
+// exceptions in the same function. Therefore, we provide a separate
+// wrapper function for handling SEH exceptions.)
+template <class T, typename Result>
+Result HandleSehExceptionsInMethodIfSupported(
+ T* object, Result(T::*method)(), const char* location)
+{
+#if GTEST_HAS_SEH
+ __try {
+ return (object->*method)();
+ } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT
+ GetExceptionCode())) {
+ // We create the exception message on the heap because VC++ prohibits
+ // creation of objects with destructors on stack in functions using __try
+ // (see error C2712).
+ std::string* exception_message = FormatSehExceptionMessage(
+ GetExceptionCode(), location);
+ internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+ *exception_message);
+ delete exception_message;
+ return static_cast<Result>(0);
+ }
+#else
+ (void)location;
+ return (object->*method)();
+#endif // GTEST_HAS_SEH
+}
+
+// Runs the given method and catches and reports C++ and/or SEH-style
+// exceptions, if they are supported; returns the 0-value for type
+// Result in case of an SEH exception.
+template <class T, typename Result>
+Result HandleExceptionsInMethodIfSupported(
+ T* object, Result(T::*method)(), const char* location)
+{
+ // NOTE: The user code can affect the way in which Google Test handles
+ // exceptions by setting GTEST_FLAG(catch_exceptions), but only before
+ // RUN_ALL_TESTS() starts. It is technically possible to check the flag
+ // after the exception is caught and either report or re-throw the
+ // exception based on the flag's value:
+ //
+ // try {
+ // // Perform the test method.
+ // } catch (...) {
+ // if (GTEST_FLAG(catch_exceptions))
+ // // Report the exception as failure.
+ // else
+ // throw; // Re-throws the original exception.
+ // }
+ //
+ // However, the purpose of this flag is to allow the program to drop into
+ // the debugger when the exception is thrown. On most platforms, once the
+ // control enters the catch block, the exception origin information is
+ // lost and the debugger will stop the program at the point of the
+ // re-throw in this function -- instead of at the point of the original
+ // throw statement in the code under test. For this reason, we perform
+ // the check early, sacrificing the ability to affect Google Test's
+ // exception handling in the method where the exception is thrown.
+ if (internal::GetUnitTestImpl()->catch_exceptions()) {
+#if GTEST_HAS_EXCEPTIONS
+ try {
+ return HandleSehExceptionsInMethodIfSupported(object, method, location);
+ } catch (const internal::GoogleTestFailureException&) { // NOLINT
+ // This exception type can only be thrown by a failed Google
+ // Test assertion with the intention of letting another testing
+ // framework catch it. Therefore we just re-throw it.
+ throw;
+ } catch (const std::exception& e) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(e.what(), location));
+ } catch (...) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(NULL, location));
+ }
+ return static_cast<Result>(0);
+#else
+ return HandleSehExceptionsInMethodIfSupported(object, method, location);
+#endif // GTEST_HAS_EXCEPTIONS
+ } else {
+ return (object->*method)();
+ }
+}
+
+} // namespace internal
+
+// Runs the test and updates the test result.
+void Test::Run()
+{
+ if (!HasSameFixtureClass()) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
+ // We will run the test only if SetUp() was successful.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &Test::TestBody, "the test body");
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &Test::TearDown, "TearDown()");
+}
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure()
+{
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true iff the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure()
+{
+ return internal::GetUnitTestImpl()->current_test_result()->
+ HasNonfatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object.
+TestInfo::TestInfo(const std::string& a_test_case_name,
+ const std::string& a_name,
+ const char* a_type_param,
+ const char* a_value_param,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory)
+ : test_case_name_(a_test_case_name),
+ name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+ value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+ fixture_class_id_(fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ matches_filter_(false),
+ factory_(factory),
+ result_() {}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() { delete factory_; }
+
+namespace internal
+{
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// type_param: the name of the test's type parameter, or NULL if
+// this is not a typed or a type-parameterized test.
+// value_param: text representation of the test's value parameter,
+// or NULL if this is not a value-parameterized test.
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name,
+ const char* name,
+ const char* type_param,
+ const char* value_param,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory)
+{
+ TestInfo* const test_info =
+ new TestInfo(test_case_name, name, type_param, value_param,
+ fixture_class_id, factory);
+ GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+#if GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line)
+{
+ Message errors;
+ errors
+ << "Attempted redefinition of test case " << test_case_name << ".\n"
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case " << test_case_name << ", you tried\n"
+ << "to define a test using a fixture class different from the one\n"
+ << "used earlier. This can happen if the two fixture classes are\n"
+ << "from different namespaces and have the same name. You should\n"
+ << "probably rename one of the classes to put the tests into different\n"
+ << "test cases.";
+
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors.GetString().c_str());
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+} // namespace internal
+
+namespace
+{
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs
+{
+ public:
+ // Constructor.
+ //
+ // TestNameIs has NO default constructor.
+ explicit TestNameIs(const char* name)
+ : name_(name) {}
+
+ // Returns true iff the test name of test_info matches name_.
+ bool operator()(const TestInfo* test_info) const {
+ return test_info && test_info->name() == name_;
+ }
+
+ private:
+ std::string name_;
+};
+
+} // namespace
+
+namespace internal
+{
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests()
+{
+#if GTEST_HAS_PARAM_TEST
+ if (!parameterized_tests_registered_) {
+ parameterized_test_registry_.RegisterTests();
+ parameterized_tests_registered_ = true;
+ }
+#endif
+}
+
+} // namespace internal
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfo::Run()
+{
+ if (!should_run_) return;
+
+ // Tells UnitTest where to store test result.
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Notifies the unit test event listeners that a test is about to start.
+ repeater->OnTestStart(*this);
+
+ const TimeInMillis start = internal::GetTimeInMillis();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+
+ // Creates the test object.
+ Test* const test = internal::HandleExceptionsInMethodIfSupported(
+ factory_, &internal::TestFactoryBase::CreateTest,
+ "the test fixture's constructor");
+
+ // Runs the test only if the test object was created and its
+ // constructor didn't generate a fatal failure.
+ if ((test != NULL) && !Test::HasFatalFailure()) {
+ // This doesn't throw as all user code that can throw are wrapped into
+ // exception handling code.
+ test->Run();
+ }
+
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ test, &Test::DeleteSelf_, "the test fixture's destructor");
+
+ result_.set_elapsed_time(internal::GetTimeInMillis() - start);
+
+ // Notifies the unit test event listener that a test has just finished.
+ repeater->OnTestEnd(*this);
+
+ // Tells UnitTest to stop associating assertion results to this
+ // test.
+ impl->set_current_test_info(NULL);
+}
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const
+{
+ return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const
+{
+ return CountIf(test_info_list_, TestFailed);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int TestCase::reportable_disabled_test_count() const
+{
+ return CountIf(test_info_list_, TestReportableDisabled);
+}
+
+// Gets the number of disabled tests in this test case.
+int TestCase::disabled_test_count() const
+{
+ return CountIf(test_info_list_, TestDisabled);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int TestCase::reportable_test_count() const
+{
+ return CountIf(test_info_list_, TestReportable);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const
+{
+ return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const
+{
+ return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+// name: name of the test case
+// a_type_param: the name of the test case's type parameter, or NULL if
+// this is not a typed or a type-parameterized test case.
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* a_name, const char* a_type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc)
+ : name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ elapsed_time_(0)
+{
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase()
+{
+ // Deletes every Test in the collection.
+ ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+const TestInfo* TestCase::GetTestInfo(int i) const
+{
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+TestInfo* TestCase::GetMutableTestInfo(int i)
+{
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Adds a test to this test case. Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo* test_info)
+{
+ test_info_list_.push_back(test_info);
+ test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run()
+{
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_case(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ repeater->OnTestCaseStart(*this);
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
+
+ const internal::TimeInMillis start = internal::GetTimeInMillis();
+ for (int i = 0; i < total_test_count(); i++) {
+ GetMutableTestInfo(i)->Run();
+ }
+ elapsed_time_ = internal::GetTimeInMillis() - start;
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
+
+ repeater->OnTestCaseEnd(*this);
+ impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult()
+{
+ ad_hoc_test_result_.Clear();
+ ForEach(test_info_list_, TestInfo::ClearTestResult);
+}
+
+// Shuffles the tests in this test case.
+void TestCase::ShuffleTests(internal::Random* random)
+{
+ Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestCase::UnshuffleTests()
+{
+ for (size_t i = 0; i < test_indices_.size(); i++) {
+ test_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Formats a countable noun. Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static std::string FormatCountableNoun(int count,
+ const char* singular_form,
+ const char* plural_form)
+{
+ return internal::StreamableToString(count) + " " +
+ (count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static std::string FormatTestCount(int test_count)
+{
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static std::string FormatTestCaseCount(int test_case_count)
+{
+ return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResult::Type enum to human-friendly string
+// representation. Both kNonFatalFailure and kFatalFailure are translated
+// to "Failure", as the user usually doesn't care about the difference
+// between the two when viewing the test result.
+static const char* TestPartResultTypeToString(TestPartResult::Type type)
+{
+ switch (type) {
+ case TestPartResult::kSuccess:
+ return "Success";
+
+ case TestPartResult::kNonFatalFailure:
+ case TestPartResult::kFatalFailure:
+#ifdef _MSC_VER
+ return "error: ";
+#else
+ return "Failure\n";
+#endif
+ default:
+ return "Unknown result type";
+ }
+}
+
+namespace internal
+{
+
+// Prints a TestPartResult to an std::string.
+static std::string PrintTestPartResultToString(
+ const TestPartResult& test_part_result)
+{
+ return (Message()
+ << internal::FormatFileLocation(test_part_result.file_name(),
+ test_part_result.line_number())
+ << " " << TestPartResultTypeToString(test_part_result.type())
+ << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(const TestPartResult& test_part_result)
+{
+ const std::string& result =
+ PrintTestPartResultToString(test_part_result);
+ printf("%s\n", result.c_str());
+ fflush(stdout);
+ // If the test program runs in Visual Studio or a debugger, the
+ // following statements add the test part result message to the Output
+ // window such that the user can double-click on it to jump to the
+ // corresponding source code location; otherwise they do nothing.
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ // We don't call OutputDebugString*() on Windows Mobile, as printing
+ // to stdout is done by OutputDebugString() there already - we don't
+ // want the same message printed twice.
+ ::OutputDebugStringA(result.c_str());
+ ::OutputDebugStringA("\n");
+#endif
+}
+
+// class PrettyUnitTestResultPrinter
+
+enum GTestColor {
+ COLOR_DEFAULT,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW
+};
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color)
+{
+ switch (color) {
+ case COLOR_RED: return FOREGROUND_RED;
+ case COLOR_GREEN: return FOREGROUND_GREEN;
+ case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+ default: return 0;
+ }
+}
+
+#else
+
+// Returns the ANSI color code for the given color. COLOR_DEFAULT is
+// an invalid input.
+const char* GetAnsiColorCode(GTestColor color)
+{
+ switch (color) {
+ case COLOR_RED: return "1";
+ case COLOR_GREEN: return "2";
+ case COLOR_YELLOW: return "3";
+ default: return NULL;
+ };
+}
+
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty)
+{
+ const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS
+ // On Windows the TERM variable is usually not set, but the
+ // console there does support colors.
+ return stdout_is_tty;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = posix::GetEnv("TERM");
+ const bool term_supports_color =
+ String::CStringEquals(term, "xterm") ||
+ String::CStringEquals(term, "xterm-color") ||
+ String::CStringEquals(term, "xterm-256color") ||
+ String::CStringEquals(term, "screen") ||
+ String::CStringEquals(term, "screen-256color") ||
+ String::CStringEquals(term, "linux") ||
+ String::CStringEquals(term, "cygwin");
+ return stdout_is_tty && term_supports_color;
+#endif // GTEST_OS_WINDOWS
+ }
+
+ return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+ String::CStringEquals(gtest_color, "1");
+ // We take "yes", "true", "t", and "1" as meaning "yes". If the
+ // value is neither one of these nor "auto", we treat it as "no" to
+ // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS
+ const bool use_color = false;
+#else
+ static const bool in_color_mode =
+ ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+ const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+ // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+
+ // We need to flush the stream buffers into the console before each
+ // SetConsoleTextAttribute call lest it affect the text that is already
+ // printed but has not yet reached the console.
+ fflush(stdout);
+ SetConsoleTextAttribute(stdout_handle,
+ GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ vprintf(fmt, args);
+
+ fflush(stdout);
+ // Restores the text color.
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+ printf("\033[0;3%sm", GetAnsiColorCode(color));
+ vprintf(fmt, args);
+ printf("\033[m"); // Resets the terminal to default.
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ va_end(args);
+}
+
+// Text printed in Google Test's text output and --gunit_list_tests
+// output to label the type parameter and value parameter for a test.
+static const char kTypeParamLabel[] = "TypeParam";
+static const char kValueParamLabel[] = "GetParam()";
+
+void PrintFullTestCommentIfPresent(const TestInfo& test_info)
+{
+ const char* const type_param = test_info.type_param();
+ const char* const value_param = test_info.value_param();
+
+ if (type_param != NULL || value_param != NULL) {
+ printf(", where ");
+ if (type_param != NULL) {
+ printf("%s = %s", kTypeParamLabel, type_param);
+ if (value_param != NULL)
+ printf(" and ");
+ }
+ if (value_param != NULL) {
+ printf("%s = %s", kValueParamLabel, value_param);
+ }
+ }
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener
+{
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char* test_case, const char* test) {
+ printf("%s.%s", test_case, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& test_case);
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+
+ private:
+ static void PrintFailedTests(const UnitTest& unit_test);
+};
+
+// Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+ const UnitTest& unit_test, int iteration)
+{
+ if (GTEST_FLAG(repeat) != 1)
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+ const char* const filter = GTEST_FLAG(filter).c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: %s filter = %s\n", GTEST_NAME_, filter);
+ }
+
+ if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+ const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: This is test shard %d of %s.\n",
+ static_cast<int>(shard_index) + 1,
+ internal::posix::GetEnv(kTestTotalShards));
+ }
+
+ if (GTEST_FLAG(shuffle)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: Randomizing tests' orders with a seed of %d .\n",
+ unit_test.random_seed());
+ }
+
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+ const UnitTest& /*unit_test*/)
+{
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case)
+{
+ const std::string counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_case.name());
+ if (test_case.type_param() == NULL) {
+ printf("\n");
+ } else {
+ printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info)
+{
+ ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
+ PrintTestName(test_info.test_case_name(), test_info.name());
+ printf("\n");
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result)
+{
+ // If the test part succeeded, we don't need to do anything.
+ if (result.type() == TestPartResult::kSuccess)
+ return;
+
+ // Print failure message from the assertion (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info)
+{
+ if (test_info.result()->Passed()) {
+ ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else {
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ }
+ PrintTestName(test_info.test_case_name(), test_info.name());
+ if (test_info.result()->Failed())
+ PrintFullTestCommentIfPresent(test_info);
+
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms)\n", internal::StreamableToString(
+ test_info.result()->elapsed_time()).c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case)
+{
+ if (!GTEST_FLAG(print_time)) return;
+
+ const std::string counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n",
+ counts.c_str(), test_case.name(),
+ internal::StreamableToString(test_case.elapsed_time()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+ const UnitTest& /*unit_test*/)
+{
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment tear-down\n");
+ fflush(stdout);
+}
+
+// Internal helper for printing the list of failed tests.
+void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test)
+{
+ const int failed_test_count = unit_test.failed_test_count();
+ if (failed_test_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase& test_case = *unit_test.GetTestCase(i);
+ if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_case.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_case.GetTestInfo(j);
+ if (!test_info.should_run() || test_info.result()->Passed()) {
+ continue;
+ }
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s.%s", test_case.name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
+ printf("\n");
+ }
+ }
+}
+
+void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/)
+{
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ int num_failures = unit_test.failed_test_count();
+ if (!unit_test.Passed()) {
+ const int failed_test_count = unit_test.failed_test_count();
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+ PrintFailedTests(unit_test);
+ printf("\n%2d FAILED %s\n", num_failures,
+ num_failures == 1 ? "TEST" : "TESTS");
+ }
+
+ int num_disabled = unit_test.reportable_disabled_test_count();
+ if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+ if (!num_failures) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(COLOR_YELLOW,
+ " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled,
+ num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener
+{
+ public:
+ TestEventRepeater() : forwarding_enabled_(true) {}
+ virtual ~TestEventRepeater();
+ void Append(TestEventListener* listener);
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled() const { return forwarding_enabled_; }
+ void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
+
+ virtual void OnTestProgramStart(const UnitTest& unit_test);
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& test_case);
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& unit_test);
+
+ private:
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled_;
+ // The list of listeners that receive events.
+ std::vector<TestEventListener*> listeners_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
+};
+
+TestEventRepeater::~TestEventRepeater()
+{
+ ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener* listener)
+{
+ listeners_.push_back(listener);
+}
+
+// TODO(vladl at google.com): Factor the search functionality into Vector::Find.
+TestEventListener* TestEventRepeater::Release(TestEventListener* listener)
+{
+ for (size_t i = 0; i < listeners_.size(); ++i) {
+ if (listeners_[i] == listener) {
+ listeners_.erase(listeners_.begin() + i);
+ return listener;
+ }
+ }
+
+ return NULL;
+}
+
+// Since most methods are very similar, use macros to reduce boilerplate.
+// This defines a member that forwards the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (size_t i = 0; i < listeners_.size(); i++) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+// This defines a member that forwards the call to all listeners in reverse
+// order.
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
+GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
+
+#undef GTEST_REPEATER_METHOD_
+#undef GTEST_REVERSE_REPEATER_METHOD_
+
+void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
+ int iteration)
+{
+ if (forwarding_enabled_) {
+ for (size_t i = 0; i < listeners_.size(); i++) {
+ listeners_[i]->OnTestIterationStart(unit_test, iteration);
+ }
+ }
+}
+
+void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration)
+{
+ if (forwarding_enabled_) {
+ for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
+ listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+ }
+ }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener
+{
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(char c) {
+ return c == 0x9 || c == 0xA || c == 0xD;
+ }
+
+ // May c appear in a well-formed XML document?
+ static bool IsValidXmlCharacter(char c) {
+ return IsNormalizableWhitespace(c) || c >= 0x20;
+ }
+
+ // Returns an XML-escaped copy of the input string str. If
+ // is_attribute is true, the text is meant to appear as an attribute
+ // value, and normalizable whitespace is preserved by replacing it
+ // with character references.
+ static std::string EscapeXml(const std::string& str, bool is_attribute);
+
+ // Returns the given string with all characters invalid in XML removed.
+ static std::string RemoveInvalidXmlCharacters(const std::string& str);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static std::string EscapeXmlAttribute(const std::string& str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static std::string EscapeXmlText(const char* str) {
+ return EscapeXml(str, false);
+ }
+
+ // Verifies that the given attribute belongs to the given element and
+ // streams the attribute as XML.
+ static void OutputXmlAttribute(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value);
+
+ // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+ static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+ // Streams an XML representation of a TestInfo object.
+ static void OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_case_name,
+ const TestInfo& test_info);
+
+ // Prints an XML representation of a TestCase object
+ static void PrintXmlTestCase(::std::ostream* stream,
+ const TestCase& test_case);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(::std::ostream* stream,
+ const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as space
+ // delimited XML attributes based on the property key="value" pairs.
+ // When the std::string is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
+
+ // The output file.
+ const std::string output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file)
+{
+ if (output_file_.c_str() == NULL || output_file_.empty()) {
+ fprintf(stderr, "XML output file may not be null\n");
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/)
+{
+ FILE* xmlout = NULL;
+ FilePath output_file(output_file_);
+ FilePath output_dir(output_file.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ xmlout = posix::FOpen(output_file_.c_str(), "w");
+ }
+ if (xmlout == NULL) {
+ // TODO(wan): report the reason of the failure.
+ //
+ // We don't do it for now as:
+ //
+ // 1. There is no urgent need for it.
+ // 2. It's a bit involved to make the errno variable thread-safe on
+ // all three operating systems (Linux, Windows, and Mac OS).
+ // 3. To interpret the meaning of errno in a thread-safe way,
+ // we need the strerror_r() function, which is not available on
+ // Windows.
+ fprintf(stderr,
+ "Unable to open file \"%s\"\n",
+ output_file_.c_str());
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ std::stringstream stream;
+ PrintXmlUnitTest(&stream, unit_test);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+ fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str. If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+std::string XmlUnitTestResultPrinter::EscapeXml(
+ const std::string& str, bool is_attribute)
+{
+ Message m;
+
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '<':
+ m << "<";
+ break;
+ case '>':
+ m << ">";
+ break;
+ case '&':
+ m << "&";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "'";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << """;
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(ch)) {
+ if (is_attribute && IsNormalizableWhitespace(ch))
+ m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
+ << ";";
+ else
+ m << ch;
+ }
+ break;
+ }
+ }
+
+ return m.GetString();
+}
+
+// Returns the given string with all characters invalid in XML removed.
+// Currently invalid characters are dropped from the string. An
+// alternative is to replace them with certain characters such as . or ?.
+std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
+ const std::string& str)
+{
+ std::string output;
+ output.reserve(str.size());
+ for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
+ if (IsValidXmlCharacter(*it))
+ output.push_back(*it);
+
+ return output;
+}
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
+// </testcase>
+// </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms)
+{
+ ::std::stringstream ss;
+ ss << ms/1000.0;
+ return ss.str();
+}
+
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms)
+{
+ // Using non-reentrant version as localtime_r is not portable.
+ time_t seconds = static_cast<time_t>(ms / 1000);
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4996) // Temporarily disables warning 4996
+ // (function or variable may be unsafe).
+ const struct tm* const time_struct = localtime(&seconds); // NOLINT
+# pragma warning(pop) // Restores the warning state again.
+#else
+ const struct tm* const time_struct = localtime(&seconds); // NOLINT
+#endif
+ if (time_struct == NULL)
+ return ""; // Invalid ms value
+
+ // YYYY-MM-DDThh:mm:ss
+ return StreamableToString(time_struct->tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct->tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct->tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct->tm_min) + ":" +
+ String::FormatIntWidth2(time_struct->tm_sec);
+}
+
+// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
+ const char* data)
+{
+ const char* segment = data;
+ *stream << "<![CDATA[";
+ for (;;) {
+ const char* const next_segment = strstr(segment, "]]>");
+ if (next_segment != NULL) {
+ stream->write(
+ segment, static_cast<std::streamsize>(next_segment - segment));
+ *stream << "]]>]]><![CDATA[";
+ segment = next_segment + strlen("]]>");
+ } else {
+ *stream << segment;
+ break;
+ }
+ }
+ *stream << "]]>";
+}
+
+void XmlUnitTestResultPrinter::OutputXmlAttribute(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value)
+{
+ const std::vector<std::string>& allowed_names =
+ GetReservedAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Attribute " << name << " is not allowed for element <" << element_name
+ << ">.";
+
+ *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
+}
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_case_name,
+ const TestInfo& test_info)
+{
+ const TestResult& result = *test_info.result();
+ const std::string kTestcase = "testcase";
+
+ *stream << " <testcase";
+ OutputXmlAttribute(stream, kTestcase, "name", test_info.name());
+
+ if (test_info.value_param() != NULL) {
+ OutputXmlAttribute(stream, kTestcase, "value_param",
+ test_info.value_param());
+ }
+ if (test_info.type_param() != NULL) {
+ OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
+ }
+
+ OutputXmlAttribute(stream, kTestcase, "status",
+ test_info.should_run() ? "run" : "notrun");
+ OutputXmlAttribute(stream, kTestcase, "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(stream, kTestcase, "classname", test_case_name);
+ *stream << TestPropertiesAsXmlAttributes(result);
+
+ int failures = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ if (++failures == 1) {
+ *stream << ">\n";
+ }
+ const string location = internal::FormatCompilerIndependentFileLocation(
+ part.file_name(), part.line_number());
+ const string summary = location + "\n" + part.summary();
+ *stream << " <failure message=\""
+ << EscapeXmlAttribute(summary.c_str())
+ << "\" type=\"\">";
+ const string detail = location + "\n" + part.message();
+ OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+ *stream << "</failure>\n";
+ }
+ }
+
+ if (failures == 0)
+ *stream << " />\n";
+ else
+ *stream << " </testcase>\n";
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
+ const TestCase& test_case)
+{
+ const std::string kTestsuite = "testsuite";
+ *stream << " <" << kTestsuite;
+ OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
+ OutputXmlAttribute(stream, kTestsuite, "tests",
+ StreamableToString(test_case.reportable_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "failures",
+ StreamableToString(test_case.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "disabled",
+ StreamableToString(test_case.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
+ *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
+ << ">\n";
+
+ for (int i = 0; i < test_case.total_test_count(); ++i) {
+ if (test_case.GetTestInfo(i)->is_reportable())
+ OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
+ }
+ *stream << " </" << kTestsuite << ">\n";
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
+ const UnitTest& unit_test)
+{
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(unit_test.reportable_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "failures",
+ StreamableToString(unit_test.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuites, "disabled",
+ StreamableToString(unit_test.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+ OutputXmlAttribute(
+ stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
+ OutputXmlAttribute(stream, kTestsuites, "time",
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
+
+ if (GTEST_FLAG(shuffle)) {
+ OutputXmlAttribute(stream, kTestsuites, "random_seed",
+ StreamableToString(unit_test.random_seed()));
+ }
+
+ *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
+
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ if (unit_test.GetTestCase(i)->reportable_test_count() > 0)
+ PrintXmlTestCase(stream, *unit_test.GetTestCase(i));
+ }
+ *stream << "</" << kTestsuites << ">\n";
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+ const TestResult& result)
+{
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << " " << property.key() << "="
+ << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
+// replaces them by "%xx" where xx is their hexadecimal value. For
+// example, replaces "=" with "%3D". This algorithm is O(strlen(str))
+// in both time and space -- important as the input str may contain an
+// arbitrarily long test failure message and stack trace.
+string StreamingListener::UrlEncode(const char* str)
+{
+ string result;
+ result.reserve(strlen(str) + 1);
+ for (char ch = *str; ch != '\0'; ch = *++str) {
+ switch (ch) {
+ case '%':
+ case '=':
+ case '&':
+ case '\n':
+ result.append("%" + String::FormatByte(static_cast<unsigned char>(ch)));
+ break;
+ default:
+ result.push_back(ch);
+ break;
+ }
+ }
+ return result;
+}
+
+void StreamingListener::SocketWriter::MakeConnection()
+{
+ GTEST_CHECK_(sockfd_ == -1)
+ << "MakeConnection() can't be called when there is already a connection.";
+
+ addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses.
+ hints.ai_socktype = SOCK_STREAM;
+ addrinfo* servinfo = NULL;
+
+ // Use the getaddrinfo() to get a linked list of IP addresses for
+ // the given host name.
+ const int error_num = getaddrinfo(
+ host_name_.c_str(), port_num_.c_str(), &hints, &servinfo);
+ if (error_num != 0) {
+ GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
+ << gai_strerror(error_num);
+ }
+
+ // Loop through all the results and connect to the first we can.
+ for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL;
+ cur_addr = cur_addr->ai_next) {
+ sockfd_ = socket(
+ cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
+ if (sockfd_ != -1) {
+ // Connect the client socket to the server socket.
+ if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) {
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+ }
+ }
+
+ freeaddrinfo(servinfo); // all done with this structure
+
+ if (sockfd_ == -1) {
+ GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "
+ << host_name_ << ":" << port_num_;
+ }
+}
+
+// End of class Streaming Listener
+#endif // GTEST_CAN_STREAM_RESULTS__
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message)
+GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_)
+{
+ TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message = message.GetString();
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+ScopedTrace::~ScopedTrace()
+GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_)
+{
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as an std::string. Parameters:
+//
+// max_depth - the maximum number of stack frames to be included
+// in the trace.
+// skip_count - the number of top frames to be skipped; doesn't count
+// against max_depth.
+//
+string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
+ int /* skip_count */)
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ return "";
+}
+
+void OsStackTraceGetter::UponLeavingGTest()
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
+
+} // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+ : repeater_(new internal::TestEventRepeater()),
+ default_result_printer_(NULL),
+ default_xml_generator_(NULL)
+{
+}
+
+TestEventListeners::~TestEventListeners() { delete repeater_; }
+
+// Returns the standard listener responsible for the default console
+// output. Can be removed from the listeners list to shut down default
+// console output. Note that removing this object from the listener list
+// with Release transfers its ownership to the user.
+void TestEventListeners::Append(TestEventListener* listener)
+{
+ repeater_->Append(listener);
+}
+
+// Removes the given event listener from the list and returns it. It then
+// becomes the caller's responsibility to delete the listener. Returns
+// NULL if the listener is not found in the list.
+TestEventListener* TestEventListeners::Release(TestEventListener* listener)
+{
+ if (listener == default_result_printer_)
+ default_result_printer_ = NULL;
+ else if (listener == default_xml_generator_)
+ default_xml_generator_ = NULL;
+ return repeater_->Release(listener);
+}
+
+// Returns repeater that broadcasts the TestEventListener events to all
+// subscribers.
+TestEventListener* TestEventListeners::repeater() { return repeater_; }
+
+// Sets the default_result_printer attribute to the provided listener.
+// The listener is also added to the listener list and previous
+// default_result_printer is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener)
+{
+ if (default_result_printer_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_result_printer_);
+ default_result_printer_ = listener;
+ if (listener != NULL)
+ Append(listener);
+ }
+}
+
+// Sets the default_xml_generator attribute to the provided listener. The
+// listener is also added to the listener list and previous
+// default_xml_generator is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener)
+{
+ if (default_xml_generator_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_xml_generator_);
+ default_xml_generator_ = listener;
+ if (listener != NULL)
+ Append(listener);
+ }
+}
+
+// Controls whether events will be forwarded by the repeater to the
+// listeners in the list.
+bool TestEventListeners::EventForwardingEnabled() const
+{
+ return repeater_->forwarding_enabled();
+}
+
+void TestEventListeners::SuppressEventForwarding()
+{
+ repeater_->set_forwarding_enabled(false);
+}
+
+// class UnitTest
+
+// Gets the singleton UnitTest object. The first time this method is
+// called, a UnitTest object is constructed and returned. Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest* UnitTest::GetInstance()
+{
+ // When compiled with MSVC 7.1 in optimized mode, destroying the
+ // UnitTest object upon exiting the program messes up the exit code,
+ // causing successful tests to appear failed. We have to use a
+ // different implementation in this case to bypass the compiler bug.
+ // This implementation makes the compiler happy, at the cost of
+ // leaking the UnitTest object.
+
+ // CodeGear C++Builder insists on a public destructor for the
+ // default implementation. Use this implementation to keep good OO
+ // design with private destructor.
+
+#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+}
+
+// Gets the number of successful test cases.
+int UnitTest::successful_test_case_count() const
+{
+ return impl()->successful_test_case_count();
+}
+
+// Gets the number of failed test cases.
+int UnitTest::failed_test_case_count() const
+{
+ return impl()->failed_test_case_count();
+}
+
+// Gets the number of all test cases.
+int UnitTest::total_test_case_count() const
+{
+ return impl()->total_test_case_count();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTest::test_case_to_run_count() const
+{
+ return impl()->test_case_to_run_count();
+}
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const
+{
+ return impl()->successful_test_count();
+}
+
+// Gets the number of failed tests.
+int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTest::reportable_disabled_test_count() const
+{
+ return impl()->reportable_disabled_test_count();
+}
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const
+{
+ return impl()->disabled_test_count();
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTest::reportable_test_count() const
+{
+ return impl()->reportable_test_count();
+}
+
+// Gets the number of all tests.
+int UnitTest::total_test_count() const { return impl()->total_test_count(); }
+
+// Gets the number of tests that should run.
+int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
+
+// Gets the time of the test program start, in ms from the start of the
+// UNIX epoch.
+internal::TimeInMillis UnitTest::start_timestamp() const
+{
+ return impl()->start_timestamp();
+}
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const
+{
+ return impl()->elapsed_time();
+}
+
+// Returns true iff the unit test passed (i.e. all test cases passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true iff the unit test failed (i.e. some test case failed
+// or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+const TestCase* UnitTest::GetTestCase(int i) const
+{
+ return impl()->GetTestCase(i);
+}
+
+// Returns the TestResult containing information on test failures and
+// properties logged outside of individual test cases.
+const TestResult& UnitTest::ad_hoc_test_result() const
+{
+ return *impl()->ad_hoc_test_result();
+}
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+TestCase* UnitTest::GetMutableTestCase(int i)
+{
+ return impl()->GetMutableTestCase(i);
+}
+
+// Returns the list of event listeners that can be used to track events
+// inside Google Test.
+TestEventListeners& UnitTest::listeners()
+{
+ return *impl()->listeners();
+}
+
+// Registers and returns a global test environment. When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered. After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env)
+{
+ if (env == NULL) {
+ return NULL;
+ }
+
+ impl_->environments().push_back(env);
+ return env;
+}
+
+// Adds a TestPartResult to the current TestResult object. All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results. The user code should use the
+// assertion macros instead of calling this directly.
+void UnitTest::AddTestPartResult(
+ TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const std::string& message,
+ const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack().size() > 0) {
+ msg << "\n" << GTEST_NAME_ << " trace:";
+
+ for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
+ i > 0; --i) {
+ const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
+ msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
+ << " " << trace.message;
+ }
+ }
+
+ if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+ msg << internal::kStackTraceMarker << os_stack_trace;
+ }
+
+ const TestPartResult result =
+ TestPartResult(result_type, file_name, line_number,
+ msg.GetString().c_str());
+ impl_->GetTestPartResultReporterForCurrentThread()->
+ ReportTestPartResult(result);
+
+ if (result_type != TestPartResult::kSuccess) {
+ // gtest_break_on_failure takes precedence over
+ // gtest_throw_on_failure. This allows a user to set the latter
+ // in the code (perhaps in order to use Google Test assertions
+ // with another testing framework) and specify the former on the
+ // command line for debugging.
+ if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS
+ // Using DebugBreak on Windows allows gtest to still break into a debugger
+ // when a failure happens and both the --gtest_break_on_failure and
+ // the --gtest_catch_exceptions flags are specified.
+ DebugBreak();
+#else
+ // Dereference NULL through a volatile pointer to prevent the compiler
+ // from removing. We use this rather than abort() or __builtin_trap() for
+ // portability: Symbian doesn't implement abort() well, and some debuggers
+ // don't correctly trap abort().
+ *static_cast<volatile int*>(NULL) = 1;
+#endif // GTEST_OS_WINDOWS
+ } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+ throw internal::GoogleTestFailureException(result);
+#else
+ // We cannot call abort() as it generates a pop-up in debug mode
+ // that cannot be suppressed in VC 7.1 or below.
+ exit(1);
+#endif
+ }
+ }
+}
+
+// Adds a TestProperty to the current TestResult object when invoked from
+// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+// from SetUpTestCase or TearDownTestCase, or to the global property set
+// when invoked elsewhere. If the result already contains a property with
+// the same key, the value will be updated.
+void UnitTest::RecordProperty(const std::string& key,
+ const std::string& value)
+{
+ impl_->RecordProperty(TestProperty(key, value));
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run()
+{
+ // Captures the value of GTEST_FLAG(catch_exceptions). This value will be
+ // used for the duration of the program.
+ impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
+
+#if GTEST_HAS_SEH
+ const bool in_death_test_child_process =
+ internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+ // Either the user wants Google Test to catch exceptions thrown by the
+ // tests or this is executing in the context of death test child
+ // process. In either case the user does not want to see pop-up dialogs
+ // about crashes - they are expected.
+ if (impl()->catch_exceptions() || in_death_test_child_process) {
+# if !GTEST_OS_WINDOWS_MOBILE
+ // SetErrorMode doesn't exist on CE.
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+# endif // !GTEST_OS_WINDOWS_MOBILE
+
+# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
+ // Death test children can be terminated with _abort(). On Windows,
+ // _abort() can show a dialog with a warning message. This forces the
+ // abort message to go to stderr instead.
+ _set_error_mode(_OUT_TO_STDERR);
+# endif
+
+# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+ // In the debug version, Visual Studio pops up a separate dialog
+ // offering a choice to debug the aborted program. We need to suppress
+ // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+ // executed. Google Test will notify the user of any unexpected
+ // failure via stderr.
+ //
+ // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
+ // Users of prior VC versions shall suffer the agony and pain of
+ // clicking through the countless debug dialogs.
+ // TODO(vladl at google.com): find a way to suppress the abort dialog() in the
+ // debug mode when compiled with VC 7.1 or lower.
+ if (!GTEST_FLAG(break_on_failure))
+ _set_abort_behavior(
+ 0x0, // Clear the following flags:
+ _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
+# endif
+ }
+#endif // GTEST_HAS_SEH
+
+ return internal::HandleExceptionsInMethodIfSupported(
+ impl(),
+ &internal::UnitTestImpl::RunAllTests,
+ "auxiliary test code (environments or event listeners)") ? 0 : 1;
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const
+{
+ return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+const TestCase* UnitTest::current_test_case() const
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+const TestInfo* UnitTest::current_test_info() const
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_info();
+}
+
+// Returns the random seed used at the start of the current test run.
+int UnitTest::random_seed() const { return impl_->random_seed(); }
+
+#if GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+internal::ParameterizedTestCaseRegistry&
+UnitTest::parameterized_test_registry()
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ return impl_->parameterized_test_registry();
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest()
+{
+ impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest()
+{
+ delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+void UnitTest::PopGTestTrace()
+GTEST_LOCK_EXCLUDED_(mutex_)
+{
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal
+{
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+#ifdef _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4355) // Temporarily disables warning 4355
+ // (using this in initializer).
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+# pragma warning(pop) // Restores the warning state again.
+#else
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+#endif // _MSC_VER
+ global_test_part_result_repoter_(
+ &default_global_test_part_result_reporter_),
+ per_thread_test_part_result_reporter_(
+ &default_per_thread_test_part_result_reporter_),
+#if GTEST_HAS_PARAM_TEST
+ parameterized_test_registry_(),
+ parameterized_tests_registered_(false),
+#endif // GTEST_HAS_PARAM_TEST
+ last_death_test_case_(-1),
+ current_test_case_(NULL),
+ current_test_info_(NULL),
+ ad_hoc_test_result_(),
+ os_stack_trace_getter_(NULL),
+ post_flag_parse_init_performed_(false),
+ random_seed_(0), // Will be overridden by the flag before first use.
+ random_(0), // Will be reseeded before first use.
+ start_timestamp_(0),
+ elapsed_time_(0),
+#if GTEST_HAS_DEATH_TEST
+ death_test_factory_(new DefaultDeathTestFactory),
+#endif
+ // Will be overridden by the flag before first use.
+ catch_exceptions_(false)
+{
+ listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
+}
+
+UnitTestImpl::~UnitTestImpl()
+{
+ // Deletes every TestCase.
+ ForEach(test_cases_, internal::Delete<TestCase>);
+
+ // Deletes every Environment.
+ ForEach(environments_, internal::Delete<Environment>);
+
+ delete os_stack_trace_getter_;
+}
+
+// Adds a TestProperty to the current TestResult object when invoked in a
+// context of a test, to current test case's ad_hoc_test_result when invoke
+// from SetUpTestCase/TearDownTestCase, or to the global property set
+// otherwise. If the result already contains a property with the same key,
+// the value will be updated.
+void UnitTestImpl::RecordProperty(const TestProperty& test_property)
+{
+ std::string xml_element;
+ TestResult* test_result; // TestResult appropriate for property recording.
+
+ if (current_test_info_ != NULL) {
+ xml_element = "testcase";
+ test_result = &(current_test_info_->result_);
+ } else if (current_test_case_ != NULL) {
+ xml_element = "testsuite";
+ test_result = &(current_test_case_->ad_hoc_test_result_);
+ } else {
+ xml_element = "testsuites";
+ test_result = &ad_hoc_test_result_;
+ }
+ test_result->RecordProperty(xml_element, test_property);
+}
+
+#if GTEST_HAS_DEATH_TEST
+// Disables event forwarding if the control is currently in a death test
+// subprocess. Must not be called before InitGoogleTest.
+void UnitTestImpl::SuppressTestEventsIfInSubprocess()
+{
+ if (internal_run_death_test_flag_.get() != NULL)
+ listeners()->SuppressEventForwarding();
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// Initializes event listeners performing XML output as specified by
+// UnitTestOptions. Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureXmlOutput()
+{
+ const std::string& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format != "") {
+ printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+ output_format.c_str());
+ fflush(stdout);
+ }
+}
+
+#if GTEST_CAN_STREAM_RESULTS_
+// Initializes event listeners for streaming test results in string form.
+// Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureStreamingOutput()
+{
+ const std::string& target = GTEST_FLAG(stream_result_to);
+ if (!target.empty()) {
+ const size_t pos = target.find(':');
+ if (pos != std::string::npos) {
+ listeners()->Append(new StreamingListener(target.substr(0, pos),
+ target.substr(pos+1)));
+ } else {
+ printf("WARNING: unrecognized streaming target \"%s\" ignored.\n",
+ target.c_str());
+ fflush(stdout);
+ }
+ }
+}
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+// Performs initialization dependent upon flag values obtained in
+// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+// this function is also called from RunAllTests. Since this function can be
+// called more than once, it has to be idempotent.
+void UnitTestImpl::PostFlagParsingInit()
+{
+ // Ensures that this function does not execute more than once.
+ if (!post_flag_parse_init_performed_) {
+ post_flag_parse_init_performed_ = true;
+
+#if GTEST_HAS_DEATH_TEST
+ InitDeathTestSubprocessControlInfo();
+ SuppressTestEventsIfInSubprocess();
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Registers parameterized tests. This makes parameterized tests
+ // available to the UnitTest reflection API without running
+ // RUN_ALL_TESTS.
+ RegisterParameterizedTests();
+
+ // Configures listeners for XML output. This makes it possible for users
+ // to shut down the default XML output before invoking RUN_ALL_TESTS.
+ ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Configures listeners for streaming test results to the specified server.
+ ConfigureStreamingOutput();
+#endif // GTEST_CAN_STREAM_RESULTS_
+ }
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs
+{
+ public:
+ // Constructor.
+ explicit TestCaseNameIs(const std::string& name)
+ : name_(name) {}
+
+ // Returns true iff the name of test_case matches name_.
+ bool operator()(const TestCase* test_case) const {
+ return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ std::string name_;
+};
+
+// Finds and returns a TestCase with the given name. If one doesn't
+// exist, creates one and returns it. It's the CALLER'S
+// RESPONSIBILITY to ensure that this function is only called WHEN THE
+// TESTS ARE NOT SHUFFLED.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// type_param: the name of the test case's type parameter, or NULL if
+// this is not a typed or a type-parameterized test case.
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+ const char* type_param,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc)
+{
+ // Can we find a TestCase with the given name?
+ const std::vector<TestCase*>::const_iterator test_case =
+ std::find_if(test_cases_.begin(), test_cases_.end(),
+ TestCaseNameIs(test_case_name));
+
+ if (test_case != test_cases_.end())
+ return *test_case;
+
+ // No. Let's create one.
+ TestCase* const new_test_case =
+ new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);
+
+ // Is this a death test case?
+ if (internal::UnitTestOptions::MatchesFilter(test_case_name,
+ kDeathTestCaseFilter)) {
+ // Yes. Inserts the test case after the last death test case
+ // defined so far. This only works when the test cases haven't
+ // been shuffled. Otherwise we may end up running a death test
+ // after a non-death test.
+ ++last_death_test_case_;
+ test_cases_.insert(test_cases_.begin() + last_death_test_case_,
+ new_test_case);
+ } else {
+ // No. Appends to the end of the list.
+ test_cases_.push_back(new_test_case);
+ }
+
+ test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
+ return new_test_case;
+}
+
+// Helpers for setting up / tearing down the given environment. They
+// are for use in the ForEach() function.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns true if all tests are successful. If any exception is
+// thrown during a test, the test is considered to be failed, but the
+// rest of the tests will still be run.
+//
+// When parameterized tests are enabled, it expands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+bool UnitTestImpl::RunAllTests()
+{
+ // Makes sure InitGoogleTest() was called.
+ if (!GTestIsInitialized()) {
+ printf("%s",
+ "\nThis test program did NOT call ::testing::InitGoogleTest "
+ "before calling RUN_ALL_TESTS(). Please fix it.\n");
+ return false;
+ }
+
+ // Do not run any test if the --help flag was specified.
+ if (g_help_flag)
+ return true;
+
+ // Repeats the call to the post-flag parsing initialization in case the
+ // user didn't call InitGoogleTest.
+ PostFlagParsingInit();
+
+ // Even if sharding is not on, test runners may want to use the
+ // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+ // protocol.
+ internal::WriteToShardStatusFileIfNeeded();
+
+ // True iff we are in a subprocess for running a thread-safe-style
+ // death test.
+ bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+ in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif // GTEST_HAS_DEATH_TEST
+
+ const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+ in_subprocess_for_death_test);
+
+ // Compares the full test names with the filter to decide which
+ // tests to run.
+ const bool has_tests_to_run = FilterTests(should_shard
+ ? HONOR_SHARDING_PROTOCOL
+ : IGNORE_SHARDING_PROTOCOL) > 0;
+
+ // Lists the tests and exits if the --gtest_list_tests flag was specified.
+ if (GTEST_FLAG(list_tests)) {
+ // This must be called *after* FilterTests() has been called.
+ ListTestsMatchingFilter();
+ return true;
+ }
+
+ random_seed_ = GTEST_FLAG(shuffle) ?
+ GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
+
+ // True iff at least one test has failed.
+ bool failed = false;
+
+ TestEventListener* repeater = listeners()->repeater();
+
+ start_timestamp_ = GetTimeInMillis();
+ repeater->OnTestProgramStart(*parent_);
+
+ // How many times to repeat the tests? We don't want to repeat them
+ // when we are inside the subprocess of a death test.
+ const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+ // Repeats forever if the repeat count is negative.
+ const bool forever = repeat < 0;
+ for (int i = 0; forever || i != repeat; i++) {
+ // We want to preserve failures generated by ad-hoc test
+ // assertions executed before RUN_ALL_TESTS().
+ ClearNonAdHocTestResult();
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ // Shuffles test cases and tests if requested.
+ if (has_tests_to_run && GTEST_FLAG(shuffle)) {
+ random()->Reseed(random_seed_);
+ // This should be done before calling OnTestIterationStart(),
+ // such that a test event listener can see the actual test order
+ // in the event.
+ ShuffleTests();
+ }
+
+ // Tells the unit test event listeners that the tests are about to start.
+ repeater->OnTestIterationStart(*parent_, i);
+
+ // Runs each test case if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand.
+ repeater->OnEnvironmentsSetUpStart(*parent_);
+ ForEach(environments_, SetUpEnvironment);
+ repeater->OnEnvironmentsSetUpEnd(*parent_);
+
+ // Runs the tests only if there was no fatal failure during global
+ // set-up.
+ if (!Test::HasFatalFailure()) {
+ for (int test_index = 0; test_index < total_test_case_count();
+ test_index++) {
+ GetMutableTestCase(test_index)->Run();
+ }
+ }
+
+ // Tears down all environments in reverse order afterwards.
+ repeater->OnEnvironmentsTearDownStart(*parent_);
+ std::for_each(environments_.rbegin(), environments_.rend(),
+ TearDownEnvironment);
+ repeater->OnEnvironmentsTearDownEnd(*parent_);
+ }
+
+ elapsed_time_ = GetTimeInMillis() - start;
+
+ // Tells the unit test event listener that the tests have just finished.
+ repeater->OnTestIterationEnd(*parent_, i);
+
+ // Gets the result and clears it.
+ if (!Passed()) {
+ failed = true;
+ }
+
+ // Restores the original test order after the iteration. This
+ // allows the user to quickly repro a failure that happens in the
+ // N-th iteration without repeating the first (N - 1) iterations.
+ // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
+ // case the user somehow changes the value of the flag somewhere
+ // (it's always safe to unshuffle the tests).
+ UnshuffleTests();
+
+ if (GTEST_FLAG(shuffle)) {
+ // Picks a new random seed for each iteration.
+ random_seed_ = GetNextRandomSeed(random_seed_);
+ }
+ }
+
+ repeater->OnTestProgramEnd(*parent_);
+
+ return !failed;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded()
+{
+ const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+ if (test_shard_file != NULL) {
+ FILE* const file = posix::FOpen(test_shard_file, "w");
+ if (file == NULL) {
+ ColoredPrintf(COLOR_RED,
+ "Could not write to the test shard status file \"%s\" "
+ "specified by the %s environment variable.\n",
+ test_shard_file, kTestShardStatusFile);
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+ fclose(file);
+ }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+ const char* shard_index_env,
+ bool in_subprocess_for_death_test)
+{
+ if (in_subprocess_for_death_test) {
+ return false;
+ }
+
+ const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+ const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+ if (total_shards == -1 && shard_index == -1) {
+ return false;
+ } else if (total_shards == -1 && shard_index != -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestShardIndex << " = " << shard_index
+ << ", but have left " << kTestTotalShards << " unset.\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (total_shards != -1 && shard_index == -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestTotalShards << " = " << total_shards
+ << ", but have left " << kTestShardIndex << " unset.\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (shard_index < 0 || shard_index >= total_shards) {
+ const Message msg = Message()
+ << "Invalid environment variables: we require 0 <= "
+ << kTestShardIndex << " < " << kTestTotalShards
+ << ", but you have " << kTestShardIndex << "=" << shard_index
+ << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+
+ return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* var, Int32 default_val)
+{
+ const char* str_val = posix::GetEnv(var);
+ if (str_val == NULL) {
+ return default_val;
+ }
+
+ Int32 result;
+ if (!ParseInt32(Message() << "The value of environment variable " << var,
+ str_val, &result)) {
+ exit(EXIT_FAILURE);
+ }
+ return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id)
+{
+ return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests)
+{
+ const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+ const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+ // num_runnable_tests are the number of tests that will
+ // run across all shards (i.e., match filter and are not disabled).
+ // num_selected_tests are the number of tests to be run on
+ // this shard.
+ int num_runnable_tests = 0;
+ int num_selected_tests = 0;
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ TestCase* const test_case = test_cases_[i];
+ const std::string& test_case_name = test_case->name();
+ test_case->set_should_run(false);
+
+ for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+ TestInfo* const test_info = test_case->test_info_list()[j];
+ const std::string test_name(test_info->name());
+ // A test is disabled if test case name or test name matches
+ // kDisableTestFilter.
+ const bool is_disabled =
+ internal::UnitTestOptions::MatchesFilter(test_case_name,
+ kDisableTestFilter) ||
+ internal::UnitTestOptions::MatchesFilter(test_name,
+ kDisableTestFilter);
+ test_info->is_disabled_ = is_disabled;
+
+ const bool matches_filter =
+ internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+ test_name);
+ test_info->matches_filter_ = matches_filter;
+
+ const bool is_runnable =
+ (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+ matches_filter;
+
+ const bool is_selected = is_runnable &&
+ (shard_tests == IGNORE_SHARDING_PROTOCOL ||
+ ShouldRunTestOnShard(total_shards, shard_index,
+ num_runnable_tests));
+
+ num_runnable_tests += is_runnable;
+ num_selected_tests += is_selected;
+
+ test_info->should_run_ = is_selected;
+ test_case->set_should_run(test_case->should_run() || is_selected);
+ }
+ }
+ return num_selected_tests;
+}
+
+// Prints the given C-string on a single line by replacing all '\n'
+// characters with string "\\n". If the output takes more than
+// max_length characters, only prints the first max_length characters
+// and "...".
+static void PrintOnOneLine(const char* str, int max_length)
+{
+ if (str != NULL) {
+ for (int i = 0; *str != '\0'; ++str) {
+ if (i >= max_length) {
+ printf("...");
+ break;
+ }
+ if (*str == '\n') {
+ printf("\\n");
+ i += 2;
+ } else {
+ printf("%c", *str);
+ ++i;
+ }
+ }
+ }
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter()
+{
+ // Print at most this many characters for each type/value parameter.
+ const int kMaxParamLength = 250;
+
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ const TestCase* const test_case = test_cases_[i];
+ bool printed_test_case_name = false;
+
+ for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+ const TestInfo* const test_info =
+ test_case->test_info_list()[j];
+ if (test_info->matches_filter_) {
+ if (!printed_test_case_name) {
+ printed_test_case_name = true;
+ printf("%s.", test_case->name());
+ if (test_case->type_param() != NULL) {
+ printf(" # %s = ", kTypeParamLabel);
+ // We print the type parameter on a single line to make
+ // the output easy to parse by a program.
+ PrintOnOneLine(test_case->type_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ printf(" %s", test_info->name());
+ if (test_info->value_param() != NULL) {
+ printf(" # %s = ", kValueParamLabel);
+ // We print the value parameter on a single line to make the
+ // output easy to parse by a program.
+ PrintOnOneLine(test_info->value_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ }
+ }
+ fflush(stdout);
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+ OsStackTraceGetterInterface* getter)
+{
+ if (os_stack_trace_getter_ != getter) {
+ delete os_stack_trace_getter_;
+ os_stack_trace_getter_ = getter;
+ }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter()
+{
+ if (os_stack_trace_getter_ == NULL) {
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+TestResult* UnitTestImpl::current_test_result()
+{
+ return current_test_info_ ?
+ &(current_test_info_->result_) : &ad_hoc_test_result_;
+}
+
+// Shuffles all test cases, and the tests within each test case,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests()
+{
+ // Shuffles the death test cases.
+ ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
+
+ // Shuffles the non-death test cases.
+ ShuffleRange(random(), last_death_test_case_ + 1,
+ static_cast<int>(test_cases_.size()), &test_case_indices_);
+
+ // Shuffles the tests inside each test case.
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ test_cases_[i]->ShuffleTests(random());
+ }
+}
+
+// Restores the test cases and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests()
+{
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ // Unshuffles the tests in each test case.
+ test_cases_[i]->UnshuffleTests();
+ // Resets the index of each test case.
+ test_case_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
+ int skip_count)
+{
+ // We pass skip_count + 1 to skip this wrapper function in addition
+ // to what the user really wants to skip.
+ return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
+// suppress unreachable code warnings.
+namespace
+{
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool IsTrue(bool condition) { return condition; }
+
+bool AlwaysTrue()
+{
+#if GTEST_HAS_EXCEPTIONS
+ // This condition is always false so AlwaysTrue() never actually throws,
+ // but it makes the compiler think that it may throw.
+ if (IsTrue(false))
+ throw ClassUniqueToAlwaysTrue();
+#endif // GTEST_HAS_EXCEPTIONS
+ return true;
+}
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr)
+{
+ const size_t prefix_len = strlen(prefix);
+ if (strncmp(*pstr, prefix, prefix_len) == 0) {
+ *pstr += prefix_len;
+ return true;
+ }
+ return false;
+}
+
+// Parses a string as a command line flag. The string should have
+// the format "--flag=value". When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+ const char* flag,
+ bool def_optional)
+{
+ // str and flag must not be NULL.
+ if (str == NULL || flag == NULL) return NULL;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+ const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag;
+ const size_t flag_len = flag_str.length();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return NULL;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value)
+{
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value)
+{
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, std::string* value)
+{
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// Determines whether a string has a prefix that Google Test uses for its
+// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
+// If Google Test detects that a command line flag has its prefix but is not
+// recognized, it will print its help message. Flags starting with
+// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
+// internal flags and do not trigger the help message.
+static bool HasGoogleTestFlagPrefix(const char* str)
+{
+ return (SkipPrefix("--", &str) ||
+ SkipPrefix("-", &str) ||
+ SkipPrefix("/", &str)) &&
+ !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
+ (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
+ SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
+}
+
+// Prints a string containing code-encoded text. The following escape
+// sequences can be used in the string to control the text color:
+//
+// @@ prints a single '@' character.
+// @R changes the color to red.
+// @G changes the color to green.
+// @Y changes the color to yellow.
+// @D changes to the default terminal text color.
+//
+// TODO(wan at google.com): Write tests for this once we add stdout
+// capturing to Google Test.
+static void PrintColorEncoded(const char* str)
+{
+ GTestColor color = COLOR_DEFAULT; // The current color.
+
+ // Conceptually, we split the string into segments divided by escape
+ // sequences. Then we print one segment at a time. At the end of
+ // each iteration, the str pointer advances to the beginning of the
+ // next segment.
+ for (;;) {
+ const char* p = strchr(str, '@');
+ if (p == NULL) {
+ ColoredPrintf(color, "%s", str);
+ return;
+ }
+
+ ColoredPrintf(color, "%s", std::string(str, p).c_str());
+
+ const char ch = p[1];
+ str = p + 2;
+ if (ch == '@') {
+ ColoredPrintf(color, "@");
+ } else if (ch == 'D') {
+ color = COLOR_DEFAULT;
+ } else if (ch == 'R') {
+ color = COLOR_RED;
+ } else if (ch == 'G') {
+ color = COLOR_GREEN;
+ } else if (ch == 'Y') {
+ color = COLOR_YELLOW;
+ } else {
+ --str;
+ }
+ }
+}
+
+static const char kColorEncodedHelpMessage[] =
+ "This program contains tests written using " GTEST_NAME_ ". You can use the\n"
+ "following command line flags to control its behavior:\n"
+ "\n"
+ "Test Selection:\n"
+ " @G--" GTEST_FLAG_PREFIX_ "list_tests at D\n"
+ " List the names of all tests instead of running them. The name of\n"
+ " TEST(Foo, Bar) is \"Foo.Bar\".\n"
+ " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+ "[@G- at YNEGATIVE_PATTERNS]@D\n"
+ " Run only the tests whose name matches one of the positive patterns but\n"
+ " none of the negative patterns. '?' matches any single character; '*'\n"
+ " matches any substring; ':' separates two patterns.\n"
+ " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests at D\n"
+ " Run all disabled tests too.\n"
+ "\n"
+ "Test Execution:\n"
+ " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
+ " Run the tests repeatedly; use a negative count to repeat forever.\n"
+ " @G--" GTEST_FLAG_PREFIX_ "shuffle at D\n"
+ " Randomize tests' orders on every iteration.\n"
+ " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
+ " Random number seed to use for shuffling test orders (between 1 and\n"
+ " 99999, or 0 to use a seed based on the current time).\n"
+ "\n"
+ "Test Output:\n"
+ " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes at Y|@Gno at Y|@Gauto at Y)@D\n"
+ " Enable/disable colored output. The default is @Gauto at D.\n"
+ " - at G-" GTEST_FLAG_PREFIX_ "print_time=0 at D\n"
+ " Don't print the elapsed time of each test.\n"
+ " @G--" GTEST_FLAG_PREFIX_ "output=xml at Y[@G:@YDIRECTORY_PATH at G"
+ GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
+ " Generate an XML report in the given directory or with the given file\n"
+ " name. @YFILE_PATH at D defaults to @Gtest_details.xml at D.\n"
+#if GTEST_CAN_STREAM_RESULTS_
+ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST at G:@YPORT at D\n"
+ " Stream test results to the given server.\n"
+#endif // GTEST_CAN_STREAM_RESULTS_
+ "\n"
+ "Assertion Behavior:\n"
+#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+ " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast at Y|@Gthreadsafe at Y)@D\n"
+ " Set the default death test style.\n"
+#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+ " @G--" GTEST_FLAG_PREFIX_ "break_on_failure at D\n"
+ " Turn assertion failures into debugger break-points.\n"
+ " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure at D\n"
+ " Turn assertion failures into C++ exceptions.\n"
+ " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0 at D\n"
+ " Do not report exceptions as test failures. Instead, allow them\n"
+ " to crash the program or throw a pop-up (on Windows).\n"
+ "\n"
+ "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests at D, you can alternatively set "
+ "the corresponding\n"
+ "environment variable of a flag (all letters in upper-case). For example, to\n"
+ "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+ "color=no at D or set\n"
+ "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR at D environment variable to @Gno at D.\n"
+ "\n"
+ "For more information, please read the " GTEST_NAME_ " documentation at\n"
+ "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
+ "(not one in your own code or tests), please report it to\n"
+ "@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test. The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv)
+{
+ for (int i = 1; i < *argc; i++) {
+ const std::string arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseBoolFlag;
+ using internal::ParseInt32Flag;
+ using internal::ParseStringFlag;
+
+ // Do we see a Google Test flag?
+ if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+ >EST_FLAG(also_run_disabled_tests)) ||
+ ParseBoolFlag(arg, kBreakOnFailureFlag,
+ >EST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ >EST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ >EST_FLAG(death_test_style)) ||
+ ParseBoolFlag(arg, kDeathTestUseFork,
+ >EST_FLAG(death_test_use_fork)) ||
+ ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ >EST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) ||
+ ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) ||
+ ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) ||
+ ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) ||
+ ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) ||
+ ParseInt32Flag(arg, kStackTraceDepthFlag,
+ >EST_FLAG(stack_trace_depth)) ||
+ ParseStringFlag(arg, kStreamResultToFlag,
+ >EST_FLAG(stream_result_to)) ||
+ ParseBoolFlag(arg, kThrowOnFailureFlag,
+ >EST_FLAG(throw_on_failure))
+ ) {
+ // Yes. Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ } else if (arg_string == "--help" || arg_string == "-h" ||
+ arg_string == "-?" || arg_string == "/?" ||
+ HasGoogleTestFlagPrefix(arg)) {
+ // Both help flag and unrecognized Google Test flags (excluding
+ // internal ones) trigger help display.
+ g_help_flag = true;
+ }
+ }
+
+ if (g_help_flag) {
+ // We print the help here instead of in RUN_ALL_TESTS(), as the
+ // latter may not be called at all if the user is using Google
+ // Test with another testing framework.
+ PrintColorEncoded(kColorEncodedHelpMessage);
+ }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv)
+{
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv)
+{
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv)
+{
+ g_init_gtest_count++;
+
+ // We don't want to run the initialization code twice.
+ if (g_init_gtest_count != 1) return;
+
+ if (*argc <= 0) return;
+
+ internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#if GTEST_HAS_DEATH_TEST
+
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+
+#endif // GTEST_HAS_DEATH_TEST
+
+ ParseGoogleTestFlagsOnly(argc, argv);
+ GetUnitTestImpl()->PostFlagParsingInit();
+}
+
+} // namespace internal
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv)
+{
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv)
+{
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+} // namespace testing
diff --git a/external/gtest-1.6.0/src/gtest_main.cc b/external/gtest-1.6.0/src/gtest_main.cc
new file mode 100644
index 0000000..78095c0
--- /dev/null
+++ b/external/gtest-1.6.0/src/gtest_main.cc
@@ -0,0 +1,39 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+
+GTEST_API_ int main(int argc, char** argv)
+{
+ printf("Running main() from gtest_main.cc\n");
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest-death-test_ex_test.cc b/external/gtest-1.6.0/test/gtest-death-test_ex_test.cc
new file mode 100644
index 0000000..a0d21f7
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-death-test_ex_test.cc
@@ -0,0 +1,98 @@
+// Copyright 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+//
+// Tests that verify interaction of exceptions and death tests.
+
+#include "gtest/gtest-death-test.h"
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_HAS_SEH
+# include <windows.h> // For RaiseException().
+# endif
+
+# include "gtest/gtest-spi.h"
+
+# if GTEST_HAS_EXCEPTIONS
+
+# include <exception> // For std::exception.
+
+// Tests that death tests report thrown exceptions as failures and that the
+// exceptions do not escape death test macros.
+TEST(CxxExceptionDeathTest, ExceptionIsFailure)
+{
+ try {
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception");
+ } catch (...) { // NOLINT
+ FAIL() << "An exception escaped a death test macro invocation "
+ << "with catch_exceptions "
+ << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled");
+ }
+}
+
+class TestException : public std::exception
+{
+ public:
+ virtual const char* what() const throw() { return "exceptional message"; }
+};
+
+TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions)
+{
+ // Verifies that the exception message is quoted in the failure text.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""),
+ "exceptional message");
+ // Verifies that the location is mentioned in the failure text.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""),
+ "gtest-death-test_ex_test.cc");
+}
+# endif // GTEST_HAS_EXCEPTIONS
+
+# if GTEST_HAS_SEH
+// Tests that enabling interception of SEH exceptions with the
+// catch_exceptions flag does not interfere with SEH exceptions being
+// treated as death by death tests.
+TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere)
+{
+ EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "")
+ << "with catch_exceptions "
+ << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled");
+}
+# endif
+
+#endif // GTEST_HAS_DEATH_TEST
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0;
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest-death-test_test.cc b/external/gtest-1.6.0/test/gtest-death-test_test.cc
new file mode 100644
index 0000000..8aa926b
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-death-test_test.cc
@@ -0,0 +1,1467 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Tests for death tests.
+
+#include "gtest/gtest-death-test.h"
+#include "gtest/gtest.h"
+#include "gtest/internal/gtest-filepath.h"
+
+using testing::internal::AlwaysFalse;
+using testing::internal::AlwaysTrue;
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_OS_WINDOWS
+# include <direct.h> // For chdir().
+# else
+# include <unistd.h>
+# include <sys/wait.h> // For waitpid.
+# include <limits> // For std::numeric_limits.
+# endif // GTEST_OS_WINDOWS
+
+# include <limits.h>
+# include <signal.h>
+# include <stdio.h>
+
+# if GTEST_OS_LINUX
+# include <sys/time.h>
+# endif // GTEST_OS_LINUX
+
+# include "gtest/gtest-spi.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+# define GTEST_IMPLEMENTATION_ 1
+# include "src/gtest-internal-inl.h"
+# undef GTEST_IMPLEMENTATION_
+
+namespace posix = ::testing::internal::posix;
+
+using testing::Message;
+using testing::internal::DeathTest;
+using testing::internal::DeathTestFactory;
+using testing::internal::FilePath;
+using testing::internal::GetLastErrnoDescription;
+using testing::internal::GetUnitTestImpl;
+using testing::internal::InDeathTestChild;
+using testing::internal::ParseNaturalNumber;
+
+namespace testing
+{
+namespace internal
+{
+
+// A helper class whose objects replace the death test factory for a
+// single UnitTest object during their lifetimes.
+class ReplaceDeathTestFactory
+{
+ public:
+ explicit ReplaceDeathTestFactory(DeathTestFactory* new_factory)
+ : unit_test_impl_(GetUnitTestImpl()) {
+ old_factory_ = unit_test_impl_->death_test_factory_.release();
+ unit_test_impl_->death_test_factory_.reset(new_factory);
+ }
+
+ ~ReplaceDeathTestFactory() {
+ unit_test_impl_->death_test_factory_.release();
+ unit_test_impl_->death_test_factory_.reset(old_factory_);
+ }
+ private:
+ // Prevents copying ReplaceDeathTestFactory objects.
+ ReplaceDeathTestFactory(const ReplaceDeathTestFactory&);
+ void operator=(const ReplaceDeathTestFactory&);
+
+ UnitTestImpl* unit_test_impl_;
+ DeathTestFactory* old_factory_;
+};
+
+} // namespace internal
+} // namespace testing
+
+void DieWithMessage(const ::std::string& message)
+{
+ fprintf(stderr, "%s", message.c_str());
+ fflush(stderr); // Make sure the text is printed before the process exits.
+
+ // We call _exit() instead of exit(), as the former is a direct
+ // system call and thus safer in the presence of threads. exit()
+ // will invoke user-defined exit-hooks, which may do dangerous
+ // things that conflict with death tests.
+ //
+ // Some compilers can recognize that _exit() never returns and issue the
+ // 'unreachable code' warning for code following this function, unless
+ // fooled by a fake condition.
+ if (AlwaysTrue())
+ _exit(1);
+}
+
+void DieInside(const ::std::string& function)
+{
+ DieWithMessage("death inside " + function + "().");
+}
+
+// Tests that death tests work.
+
+class TestForDeathTest : public testing::Test
+{
+ protected:
+ TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {}
+
+ virtual ~TestForDeathTest() {
+ posix::ChDir(original_dir_.c_str());
+ }
+
+ // A static member function that's expected to die.
+ static void StaticMemberFunction() { DieInside("StaticMemberFunction"); }
+
+ // A method of the test fixture that may die.
+ void MemberFunction() {
+ if (should_die_)
+ DieInside("MemberFunction");
+ }
+
+ // True iff MemberFunction() should die.
+ bool should_die_;
+ const FilePath original_dir_;
+};
+
+// A class with a member function that may die.
+class MayDie
+{
+ public:
+ explicit MayDie(bool should_die) : should_die_(should_die) {}
+
+ // A member function that may die.
+ void MemberFunction() const {
+ if (should_die_)
+ DieInside("MayDie::MemberFunction");
+ }
+
+ private:
+ // True iff MemberFunction() should die.
+ bool should_die_;
+};
+
+// A global function that's expected to die.
+void GlobalFunction() { DieInside("GlobalFunction"); }
+
+// A non-void function that's expected to die.
+int NonVoidFunction()
+{
+ DieInside("NonVoidFunction");
+ return 1;
+}
+
+// A unary function that may die.
+void DieIf(bool should_die)
+{
+ if (should_die)
+ DieInside("DieIf");
+}
+
+// A binary function that may die.
+bool DieIfLessThan(int x, int y)
+{
+ if (x < y) {
+ DieInside("DieIfLessThan");
+ }
+ return true;
+}
+
+// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture.
+void DeathTestSubroutine()
+{
+ EXPECT_DEATH(GlobalFunction(), "death.*GlobalFunction");
+ ASSERT_DEATH(GlobalFunction(), "death.*GlobalFunction");
+}
+
+// Death in dbg, not opt.
+int DieInDebugElse12(int* sideeffect)
+{
+ if (sideeffect) *sideeffect = 12;
+
+# ifndef NDEBUG
+
+ DieInside("DieInDebugElse12");
+
+# endif // NDEBUG
+
+ return 12;
+}
+
+# if GTEST_OS_WINDOWS
+
+// Tests the ExitedWithCode predicate.
+TEST(ExitStatusPredicateTest, ExitedWithCode)
+{
+ // On Windows, the process's exit code is the same as its exit status,
+ // so the predicate just compares the its input with its parameter.
+ EXPECT_TRUE(testing::ExitedWithCode(0)(0));
+ EXPECT_TRUE(testing::ExitedWithCode(1)(1));
+ EXPECT_TRUE(testing::ExitedWithCode(42)(42));
+ EXPECT_FALSE(testing::ExitedWithCode(0)(1));
+ EXPECT_FALSE(testing::ExitedWithCode(1)(0));
+}
+
+# else
+
+// Returns the exit status of a process that calls _exit(2) with a
+// given exit code. This is a helper function for the
+// ExitStatusPredicateTest test suite.
+static int NormalExitStatus(int exit_code)
+{
+ pid_t child_pid = fork();
+ if (child_pid == 0) {
+ _exit(exit_code);
+ }
+ int status;
+ waitpid(child_pid, &status, 0);
+ return status;
+}
+
+// Returns the exit status of a process that raises a given signal.
+// If the signal does not cause the process to die, then it returns
+// instead the exit status of a process that exits normally with exit
+// code 1. This is a helper function for the ExitStatusPredicateTest
+// test suite.
+static int KilledExitStatus(int signum)
+{
+ pid_t child_pid = fork();
+ if (child_pid == 0) {
+ raise(signum);
+ _exit(1);
+ }
+ int status;
+ waitpid(child_pid, &status, 0);
+ return status;
+}
+
+// Tests the ExitedWithCode predicate.
+TEST(ExitStatusPredicateTest, ExitedWithCode)
+{
+ const int status0 = NormalExitStatus(0);
+ const int status1 = NormalExitStatus(1);
+ const int status42 = NormalExitStatus(42);
+ const testing::ExitedWithCode pred0(0);
+ const testing::ExitedWithCode pred1(1);
+ const testing::ExitedWithCode pred42(42);
+ EXPECT_PRED1(pred0, status0);
+ EXPECT_PRED1(pred1, status1);
+ EXPECT_PRED1(pred42, status42);
+ EXPECT_FALSE(pred0(status1));
+ EXPECT_FALSE(pred42(status0));
+ EXPECT_FALSE(pred1(status42));
+}
+
+// Tests the KilledBySignal predicate.
+TEST(ExitStatusPredicateTest, KilledBySignal)
+{
+ const int status_segv = KilledExitStatus(SIGSEGV);
+ const int status_kill = KilledExitStatus(SIGKILL);
+ const testing::KilledBySignal pred_segv(SIGSEGV);
+ const testing::KilledBySignal pred_kill(SIGKILL);
+ EXPECT_PRED1(pred_segv, status_segv);
+ EXPECT_PRED1(pred_kill, status_kill);
+ EXPECT_FALSE(pred_segv(status_kill));
+ EXPECT_FALSE(pred_kill(status_segv));
+}
+
+# endif // GTEST_OS_WINDOWS
+
+// Tests that the death test macros expand to code which may or may not
+// be followed by operator<<, and that in either case the complete text
+// comprises only a single C++ statement.
+TEST_F(TestForDeathTest, SingleStatement)
+{
+ if (AlwaysFalse())
+ // This would fail if executed; this is a compilation test only
+ ASSERT_DEATH(return, "");
+
+ if (AlwaysTrue())
+ EXPECT_DEATH(_exit(1), "");
+ else
+ // This empty "else" branch is meant to ensure that EXPECT_DEATH
+ // doesn't expand into an "if" statement without an "else"
+ ;
+
+ if (AlwaysFalse())
+ ASSERT_DEATH(return, "") << "did not die";
+
+ if (AlwaysFalse())
+ ;
+ else
+ EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3;
+}
+
+void DieWithEmbeddedNul()
+{
+ fprintf(stderr, "Hello%cmy null world.\n", '\0');
+ fflush(stderr);
+ _exit(1);
+}
+
+# if GTEST_USES_PCRE
+// Tests that EXPECT_DEATH and ASSERT_DEATH work when the error
+// message has a NUL character in it.
+TEST_F(TestForDeathTest, EmbeddedNulInMessage)
+{
+ // TODO(wan at google.com): <regex.h> doesn't support matching strings
+ // with embedded NUL characters - find a way to workaround it.
+ EXPECT_DEATH(DieWithEmbeddedNul(), "my null world");
+ ASSERT_DEATH(DieWithEmbeddedNul(), "my null world");
+}
+# endif // GTEST_USES_PCRE
+
+// Tests that death test macros expand to code which interacts well with switch
+// statements.
+TEST_F(TestForDeathTest, SwitchStatement)
+{
+// Microsoft compiler usually complains about switch statements without
+// case labels. We suppress that warning for this test.
+# ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4065)
+# endif // _MSC_VER
+
+ switch (0)
+ default:
+ ASSERT_DEATH(_exit(1), "") << "exit in default switch handler";
+
+ switch (0)
+ case 0:
+ EXPECT_DEATH(_exit(1), "") << "exit in switch case";
+
+# ifdef _MSC_VER
+# pragma warning(pop)
+# endif // _MSC_VER
+}
+
+// Tests that a static member function can be used in a "fast" style
+// death test.
+TEST_F(TestForDeathTest, StaticMemberFunctionFastStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember");
+}
+
+// Tests that a method of the test fixture can be used in a "fast"
+// style death test.
+TEST_F(TestForDeathTest, MemberFunctionFastStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ should_die_ = true;
+ EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction");
+}
+
+void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); }
+
+// Tests that death tests work even if the current directory has been
+// changed.
+TEST_F(TestForDeathTest, FastDeathTestInChangedDir)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+
+ ChangeToRootDir();
+ EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), "");
+
+ ChangeToRootDir();
+ ASSERT_DEATH(_exit(1), "");
+}
+
+# if GTEST_OS_LINUX
+void SigprofAction(int, siginfo_t*, void*) { /* no op */ }
+
+// Sets SIGPROF action and ITIMER_PROF timer (interval: 1ms).
+void SetSigprofActionAndTimer()
+{
+ struct itimerval timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 1;
+ timer.it_value = timer.it_interval;
+ ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL));
+ struct sigaction signal_action;
+ memset(&signal_action, 0, sizeof(signal_action));
+ sigemptyset(&signal_action.sa_mask);
+ signal_action.sa_sigaction = SigprofAction;
+ signal_action.sa_flags = SA_RESTART | SA_SIGINFO;
+ ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, NULL));
+}
+
+// Disables ITIMER_PROF timer and ignores SIGPROF signal.
+void DisableSigprofActionAndTimer(struct sigaction* old_signal_action)
+{
+ struct itimerval timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 0;
+ timer.it_value = timer.it_interval;
+ ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL));
+ struct sigaction signal_action;
+ memset(&signal_action, 0, sizeof(signal_action));
+ sigemptyset(&signal_action.sa_mask);
+ signal_action.sa_handler = SIG_IGN;
+ ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, old_signal_action));
+}
+
+// Tests that death tests work when SIGPROF handler and timer are set.
+TEST_F(TestForDeathTest, FastSigprofActionSet)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ SetSigprofActionAndTimer();
+ EXPECT_DEATH(_exit(1), "");
+ struct sigaction old_signal_action;
+ DisableSigprofActionAndTimer(&old_signal_action);
+ EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction);
+}
+
+TEST_F(TestForDeathTest, ThreadSafeSigprofActionSet)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ SetSigprofActionAndTimer();
+ EXPECT_DEATH(_exit(1), "");
+ struct sigaction old_signal_action;
+ DisableSigprofActionAndTimer(&old_signal_action);
+ EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction);
+}
+# endif // GTEST_OS_LINUX
+
+// Repeats a representative sample of death tests in the "threadsafe" style:
+
+TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember");
+}
+
+TEST_F(TestForDeathTest, MemberFunctionThreadsafeStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ should_die_ = true;
+ EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction");
+}
+
+TEST_F(TestForDeathTest, ThreadsafeDeathTestInLoop)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+
+ for (int i = 0; i < 3; ++i)
+ EXPECT_EXIT(_exit(i), testing::ExitedWithCode(i), "") << ": i = " << i;
+}
+
+TEST_F(TestForDeathTest, ThreadsafeDeathTestInChangedDir)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+
+ ChangeToRootDir();
+ EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), "");
+
+ ChangeToRootDir();
+ ASSERT_DEATH(_exit(1), "");
+}
+
+TEST_F(TestForDeathTest, MixedStyles)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ EXPECT_DEATH(_exit(1), "");
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_DEATH(_exit(1), "");
+}
+
+# if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD
+
+namespace
+{
+
+bool pthread_flag;
+
+void SetPthreadFlag()
+{
+ pthread_flag = true;
+}
+
+} // namespace
+
+TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks)
+{
+ if (!testing::GTEST_FLAG(death_test_use_fork)) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ pthread_flag = false;
+ ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL));
+ ASSERT_DEATH(_exit(1), "");
+ ASSERT_FALSE(pthread_flag);
+ }
+}
+
+# endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD
+
+// Tests that a method of another class can be used in a death test.
+TEST_F(TestForDeathTest, MethodOfAnotherClass)
+{
+ const MayDie x(true);
+ ASSERT_DEATH(x.MemberFunction(), "MayDie\\:\\:MemberFunction");
+}
+
+// Tests that a global function can be used in a death test.
+TEST_F(TestForDeathTest, GlobalFunction)
+{
+ EXPECT_DEATH(GlobalFunction(), "GlobalFunction");
+}
+
+// Tests that any value convertible to an RE works as a second
+// argument to EXPECT_DEATH.
+TEST_F(TestForDeathTest, AcceptsAnythingConvertibleToRE)
+{
+ static const char regex_c_str[] = "GlobalFunction";
+ EXPECT_DEATH(GlobalFunction(), regex_c_str);
+
+ const testing::internal::RE regex(regex_c_str);
+ EXPECT_DEATH(GlobalFunction(), regex);
+
+# if GTEST_HAS_GLOBAL_STRING
+
+ const string regex_str(regex_c_str);
+ EXPECT_DEATH(GlobalFunction(), regex_str);
+
+# endif // GTEST_HAS_GLOBAL_STRING
+
+ const ::std::string regex_std_str(regex_c_str);
+ EXPECT_DEATH(GlobalFunction(), regex_std_str);
+}
+
+// Tests that a non-void function can be used in a death test.
+TEST_F(TestForDeathTest, NonVoidFunction)
+{
+ ASSERT_DEATH(NonVoidFunction(), "NonVoidFunction");
+}
+
+// Tests that functions that take parameter(s) can be used in a death test.
+TEST_F(TestForDeathTest, FunctionWithParameter)
+{
+ EXPECT_DEATH(DieIf(true), "DieIf\\(\\)");
+ EXPECT_DEATH(DieIfLessThan(2, 3), "DieIfLessThan");
+}
+
+// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture.
+TEST_F(TestForDeathTest, OutsideFixture)
+{
+ DeathTestSubroutine();
+}
+
+// Tests that death tests can be done inside a loop.
+TEST_F(TestForDeathTest, InsideLoop)
+{
+ for (int i = 0; i < 5; i++) {
+ EXPECT_DEATH(DieIfLessThan(-1, i), "DieIfLessThan") << "where i == " << i;
+ }
+}
+
+// Tests that a compound statement can be used in a death test.
+TEST_F(TestForDeathTest, CompoundStatement)
+{
+ EXPECT_DEATH({ // NOLINT
+ const int x = 2;
+ const int y = x + 1;
+ DieIfLessThan(x, y);
+ },
+ "DieIfLessThan");
+}
+
+// Tests that code that doesn't die causes a death test to fail.
+TEST_F(TestForDeathTest, DoesNotDie)
+{
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieIf(false), "DieIf"),
+ "failed to die");
+}
+
+// Tests that a death test fails when the error message isn't expected.
+TEST_F(TestForDeathTest, ErrorMessageMismatch)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_DEATH(DieIf(true), "DieIfLessThan") << "End of death test message.";
+ }, "died but not with expected error");
+}
+
+// On exit, *aborted will be true iff the EXPECT_DEATH() statement
+// aborted the function.
+void ExpectDeathTestHelper(bool* aborted)
+{
+ *aborted = true;
+ EXPECT_DEATH(DieIf(false), "DieIf"); // This assertion should fail.
+ *aborted = false;
+}
+
+// Tests that EXPECT_DEATH doesn't abort the test on failure.
+TEST_F(TestForDeathTest, EXPECT_DEATH)
+{
+ bool aborted = true;
+ EXPECT_NONFATAL_FAILURE(ExpectDeathTestHelper(&aborted),
+ "failed to die");
+ EXPECT_FALSE(aborted);
+}
+
+// Tests that ASSERT_DEATH does abort the test on failure.
+TEST_F(TestForDeathTest, ASSERT_DEATH)
+{
+ static bool aborted;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ aborted = true;
+ ASSERT_DEATH(DieIf(false), "DieIf"); // This assertion should fail.
+ aborted = false;
+ }, "failed to die");
+ EXPECT_TRUE(aborted);
+}
+
+// Tests that EXPECT_DEATH evaluates the arguments exactly once.
+TEST_F(TestForDeathTest, SingleEvaluation)
+{
+ int x = 3;
+ EXPECT_DEATH(DieIf((++x) == 4), "DieIf");
+
+ const char* regex = "DieIf";
+ const char* regex_save = regex;
+ EXPECT_DEATH(DieIfLessThan(3, 4), regex++);
+ EXPECT_EQ(regex_save + 1, regex);
+}
+
+// Tests that run-away death tests are reported as failures.
+TEST_F(TestForDeathTest, RunawayIsFailure)
+{
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast<void>(0), "Foo"),
+ "failed to die.");
+}
+
+// Tests that death tests report executing 'return' in the statement as
+// failure.
+TEST_F(TestForDeathTest, ReturnIsFailure)
+{
+ EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"),
+ "illegal return in test statement.");
+}
+
+// Tests that EXPECT_DEBUG_DEATH works as expected, that is, you can stream a
+// message to it, and in debug mode it:
+// 1. Asserts on death.
+// 2. Has no side effect.
+//
+// And in opt mode, it:
+// 1. Has side effects but does not assert.
+TEST_F(TestForDeathTest, TestExpectDebugDeath)
+{
+ int sideeffect = 0;
+
+ EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12")
+ << "Must accept a streamed message";
+
+# ifdef NDEBUG
+
+ // Checks that the assignment occurs in opt mode (sideeffect).
+ EXPECT_EQ(12, sideeffect);
+
+# else
+
+ // Checks that the assignment does not occur in dbg mode (no sideeffect).
+ EXPECT_EQ(0, sideeffect);
+
+# endif
+}
+
+// Tests that ASSERT_DEBUG_DEATH works as expected, that is, you can stream a
+// message to it, and in debug mode it:
+// 1. Asserts on death.
+// 2. Has no side effect.
+//
+// And in opt mode, it:
+// 1. Has side effects but does not assert.
+TEST_F(TestForDeathTest, TestAssertDebugDeath)
+{
+ int sideeffect = 0;
+
+ ASSERT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12")
+ << "Must accept a streamed message";
+
+# ifdef NDEBUG
+
+ // Checks that the assignment occurs in opt mode (sideeffect).
+ EXPECT_EQ(12, sideeffect);
+
+# else
+
+ // Checks that the assignment does not occur in dbg mode (no sideeffect).
+ EXPECT_EQ(0, sideeffect);
+
+# endif
+}
+
+# ifndef NDEBUG
+
+void ExpectDebugDeathHelper(bool* aborted)
+{
+ *aborted = true;
+ EXPECT_DEBUG_DEATH(return, "") << "This is expected to fail.";
+ *aborted = false;
+}
+
+# if GTEST_OS_WINDOWS
+TEST(PopUpDeathTest, DoesNotShowPopUpOnAbort)
+{
+ printf("This test should be considered failing if it shows "
+ "any pop-up dialogs.\n");
+ fflush(stdout);
+
+ EXPECT_DEATH({
+ testing::GTEST_FLAG(catch_exceptions) = false;
+ abort();
+ }, "");
+}
+# endif // GTEST_OS_WINDOWS
+
+// Tests that EXPECT_DEBUG_DEATH in debug mode does not abort
+// the function.
+TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort)
+{
+ bool aborted = true;
+ EXPECT_NONFATAL_FAILURE(ExpectDebugDeathHelper(&aborted), "");
+ EXPECT_FALSE(aborted);
+}
+
+void AssertDebugDeathHelper(bool* aborted)
+{
+ *aborted = true;
+ ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail.";
+ *aborted = false;
+}
+
+// Tests that ASSERT_DEBUG_DEATH in debug mode aborts the function on
+// failure.
+TEST_F(TestForDeathTest, AssertDebugDeathAborts)
+{
+ static bool aborted;
+ aborted = false;
+ EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
+ EXPECT_TRUE(aborted);
+}
+
+# endif // _NDEBUG
+
+// Tests the *_EXIT family of macros, using a variety of predicates.
+static void TestExitMacros()
+{
+ EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), "");
+ ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), "");
+
+# if GTEST_OS_WINDOWS
+
+ // Of all signals effects on the process exit code, only those of SIGABRT
+ // are documented on Windows.
+ // See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx.
+ EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), "") << "b_ar";
+
+# else
+
+ EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo";
+ ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar";
+
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EXIT(_exit(0), testing::KilledBySignal(SIGSEGV), "")
+ << "This failure is expected, too.";
+ }, "This failure is expected, too.");
+
+# endif // GTEST_OS_WINDOWS
+
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_EXIT(raise(SIGSEGV), testing::ExitedWithCode(0), "")
+ << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+TEST_F(TestForDeathTest, ExitMacros)
+{
+ TestExitMacros();
+}
+
+TEST_F(TestForDeathTest, ExitMacrosUsingFork)
+{
+ testing::GTEST_FLAG(death_test_use_fork) = true;
+ TestExitMacros();
+}
+
+TEST_F(TestForDeathTest, InvalidStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "rococo";
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_DEATH(_exit(0), "") << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+TEST_F(TestForDeathTest, DeathTestFailedOutput)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_DEATH(DieWithMessage("death\n"),
+ "expected message"),
+ "Actual msg:\n"
+ "[ DEATH ] death\n");
+}
+
+TEST_F(TestForDeathTest, DeathTestUnexpectedReturnOutput)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_DEATH({
+ fprintf(stderr, "returning\n");
+ fflush(stderr);
+ return;
+ }, ""),
+ " Result: illegal return in test statement.\n"
+ " Error msg:\n"
+ "[ DEATH ] returning\n");
+}
+
+TEST_F(TestForDeathTest, DeathTestBadExitCodeOutput)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EXIT(DieWithMessage("exiting with rc 1\n"),
+ testing::ExitedWithCode(3),
+ "expected message"),
+ " Result: died but not with expected exit code:\n"
+ " Exited with exit status 1\n"
+ "Actual msg:\n"
+ "[ DEATH ] exiting with rc 1\n");
+}
+
+TEST_F(TestForDeathTest, DeathTestMultiLineMatchFail)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"),
+ "line 1\nxyz\nline 3\n"),
+ "Actual msg:\n"
+ "[ DEATH ] line 1\n"
+ "[ DEATH ] line 2\n"
+ "[ DEATH ] line 3\n");
+}
+
+TEST_F(TestForDeathTest, DeathTestMultiLineMatchPass)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"),
+ "line 1\nline 2\nline 3\n");
+}
+
+// A DeathTestFactory that returns MockDeathTests.
+class MockDeathTestFactory : public DeathTestFactory
+{
+ public:
+ MockDeathTestFactory();
+ virtual bool Create(const char* statement,
+ const ::testing::internal::RE* regex,
+ const char* file, int line, DeathTest** test);
+
+ // Sets the parameters for subsequent calls to Create.
+ void SetParameters(bool create, DeathTest::TestRole role,
+ int status, bool passed);
+
+ // Accessors.
+ int AssumeRoleCalls() const { return assume_role_calls_; }
+ int WaitCalls() const { return wait_calls_; }
+ int PassedCalls() const { return passed_args_.size(); }
+ bool PassedArgument(int n) const { return passed_args_[n]; }
+ int AbortCalls() const { return abort_args_.size(); }
+ DeathTest::AbortReason AbortArgument(int n) const {
+ return abort_args_[n];
+ }
+ bool TestDeleted() const { return test_deleted_; }
+
+ private:
+ friend class MockDeathTest;
+ // If true, Create will return a MockDeathTest; otherwise it returns
+ // NULL.
+ bool create_;
+ // The value a MockDeathTest will return from its AssumeRole method.
+ DeathTest::TestRole role_;
+ // The value a MockDeathTest will return from its Wait method.
+ int status_;
+ // The value a MockDeathTest will return from its Passed method.
+ bool passed_;
+
+ // Number of times AssumeRole was called.
+ int assume_role_calls_;
+ // Number of times Wait was called.
+ int wait_calls_;
+ // The arguments to the calls to Passed since the last call to
+ // SetParameters.
+ std::vector<bool> passed_args_;
+ // The arguments to the calls to Abort since the last call to
+ // SetParameters.
+ std::vector<DeathTest::AbortReason> abort_args_;
+ // True if the last MockDeathTest returned by Create has been
+ // deleted.
+ bool test_deleted_;
+};
+
+
+// A DeathTest implementation useful in testing. It returns values set
+// at its creation from its various inherited DeathTest methods, and
+// reports calls to those methods to its parent MockDeathTestFactory
+// object.
+class MockDeathTest : public DeathTest
+{
+ public:
+ MockDeathTest(MockDeathTestFactory* parent,
+ TestRole role, int status, bool passed) :
+ parent_(parent), role_(role), status_(status), passed_(passed) {
+ }
+ virtual ~MockDeathTest() {
+ parent_->test_deleted_ = true;
+ }
+ virtual TestRole AssumeRole() {
+ ++parent_->assume_role_calls_;
+ return role_;
+ }
+ virtual int Wait() {
+ ++parent_->wait_calls_;
+ return status_;
+ }
+ virtual bool Passed(bool exit_status_ok) {
+ parent_->passed_args_.push_back(exit_status_ok);
+ return passed_;
+ }
+ virtual void Abort(AbortReason reason) {
+ parent_->abort_args_.push_back(reason);
+ }
+
+ private:
+ MockDeathTestFactory* const parent_;
+ const TestRole role_;
+ const int status_;
+ const bool passed_;
+};
+
+
+// MockDeathTestFactory constructor.
+MockDeathTestFactory::MockDeathTestFactory()
+ : create_(true),
+ role_(DeathTest::OVERSEE_TEST),
+ status_(0),
+ passed_(true),
+ assume_role_calls_(0),
+ wait_calls_(0),
+ passed_args_(),
+ abort_args_()
+{
+}
+
+
+// Sets the parameters for subsequent calls to Create.
+void MockDeathTestFactory::SetParameters(bool create,
+ DeathTest::TestRole role,
+ int status, bool passed)
+{
+ create_ = create;
+ role_ = role;
+ status_ = status;
+ passed_ = passed;
+
+ assume_role_calls_ = 0;
+ wait_calls_ = 0;
+ passed_args_.clear();
+ abort_args_.clear();
+}
+
+
+// Sets test to NULL (if create_ is false) or to the address of a new
+// MockDeathTest object with parameters taken from the last call
+// to SetParameters (if create_ is true). Always returns true.
+bool MockDeathTestFactory::Create(const char* /*statement*/,
+ const ::testing::internal::RE* /*regex*/,
+ const char* /*file*/,
+ int /*line*/,
+ DeathTest** test)
+{
+ test_deleted_ = false;
+ if (create_) {
+ *test = new MockDeathTest(this, role_, status_, passed_);
+ } else {
+ *test = NULL;
+ }
+ return true;
+}
+
+// A test fixture for testing the logic of the GTEST_DEATH_TEST_ macro.
+// It installs a MockDeathTestFactory that is used for the duration
+// of the test case.
+class MacroLogicDeathTest : public testing::Test
+{
+ protected:
+ static testing::internal::ReplaceDeathTestFactory* replacer_;
+ static MockDeathTestFactory* factory_;
+
+ static void SetUpTestCase() {
+ factory_ = new MockDeathTestFactory;
+ replacer_ = new testing::internal::ReplaceDeathTestFactory(factory_);
+ }
+
+ static void TearDownTestCase() {
+ delete replacer_;
+ replacer_ = NULL;
+ delete factory_;
+ factory_ = NULL;
+ }
+
+ // Runs a death test that breaks the rules by returning. Such a death
+ // test cannot be run directly from a test routine that uses a
+ // MockDeathTest, or the remainder of the routine will not be executed.
+ static void RunReturningDeathTest(bool* flag) {
+ ASSERT_DEATH({ // NOLINT
+ *flag = true;
+ return;
+ }, "");
+ }
+};
+
+testing::internal::ReplaceDeathTestFactory* MacroLogicDeathTest::replacer_
+ = NULL;
+MockDeathTestFactory* MacroLogicDeathTest::factory_ = NULL;
+
+
+// Test that nothing happens when the factory doesn't return a DeathTest:
+TEST_F(MacroLogicDeathTest, NothingHappens)
+{
+ bool flag = false;
+ factory_->SetParameters(false, DeathTest::OVERSEE_TEST, 0, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_FALSE(flag);
+ EXPECT_EQ(0, factory_->AssumeRoleCalls());
+ EXPECT_EQ(0, factory_->WaitCalls());
+ EXPECT_EQ(0, factory_->PassedCalls());
+ EXPECT_EQ(0, factory_->AbortCalls());
+ EXPECT_FALSE(factory_->TestDeleted());
+}
+
+// Test that the parent process doesn't run the death test code,
+// and that the Passed method returns false when the (simulated)
+// child process exits with status 0:
+TEST_F(MacroLogicDeathTest, ChildExitsSuccessfully)
+{
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 0, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_FALSE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(1, factory_->WaitCalls());
+ ASSERT_EQ(1, factory_->PassedCalls());
+ EXPECT_FALSE(factory_->PassedArgument(0));
+ EXPECT_EQ(0, factory_->AbortCalls());
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that the Passed method was given the argument "true" when
+// the (simulated) child process exits with status 1:
+TEST_F(MacroLogicDeathTest, ChildExitsUnsuccessfully)
+{
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 1, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_FALSE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(1, factory_->WaitCalls());
+ ASSERT_EQ(1, factory_->PassedCalls());
+ EXPECT_TRUE(factory_->PassedArgument(0));
+ EXPECT_EQ(0, factory_->AbortCalls());
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that the (simulated) child process executes the death test
+// code, and is aborted with the correct AbortReason if it
+// executes a return statement.
+TEST_F(MacroLogicDeathTest, ChildPerformsReturn)
+{
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true);
+ RunReturningDeathTest(&flag);
+ EXPECT_TRUE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(0, factory_->WaitCalls());
+ EXPECT_EQ(0, factory_->PassedCalls());
+ EXPECT_EQ(1, factory_->AbortCalls());
+ EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT,
+ factory_->AbortArgument(0));
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that the (simulated) child process is aborted with the
+// correct AbortReason if it does not die.
+TEST_F(MacroLogicDeathTest, ChildDoesNotDie)
+{
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_TRUE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(0, factory_->WaitCalls());
+ EXPECT_EQ(0, factory_->PassedCalls());
+ // This time there are two calls to Abort: one since the test didn't
+ // die, and another from the ReturnSentinel when it's destroyed. The
+ // sentinel normally isn't destroyed if a test doesn't die, since
+ // _exit(2) is called in that case by ForkingDeathTest, but not by
+ // our MockDeathTest.
+ ASSERT_EQ(2, factory_->AbortCalls());
+ EXPECT_EQ(DeathTest::TEST_DID_NOT_DIE,
+ factory_->AbortArgument(0));
+ EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT,
+ factory_->AbortArgument(1));
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that a successful death test does not register a successful
+// test part.
+TEST(SuccessRegistrationDeathTest, NoSuccessPart)
+{
+ EXPECT_DEATH(_exit(1), "");
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+TEST(StreamingAssertionsDeathTest, DeathTest)
+{
+ EXPECT_DEATH(_exit(1), "") << "unexpected failure";
+ ASSERT_DEATH(_exit(1), "") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_DEATH(_exit(0), "") << "expected failure";
+ }, "expected failure");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_DEATH(_exit(0), "") << "expected failure";
+ }, "expected failure");
+}
+
+// Tests that GetLastErrnoDescription returns an empty string when the
+// last error is 0 and non-empty string when it is non-zero.
+TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks)
+{
+ errno = ENOENT;
+ EXPECT_STRNE("", GetLastErrnoDescription().c_str());
+ errno = 0;
+ EXPECT_STREQ("", GetLastErrnoDescription().c_str());
+}
+
+# if GTEST_OS_WINDOWS
+TEST(AutoHandleTest, AutoHandleWorks)
+{
+ HANDLE handle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ ASSERT_NE(INVALID_HANDLE_VALUE, handle);
+
+ // Tests that the AutoHandle is correctly initialized with a handle.
+ testing::internal::AutoHandle auto_handle(handle);
+ EXPECT_EQ(handle, auto_handle.Get());
+
+ // Tests that Reset assigns INVALID_HANDLE_VALUE.
+ // Note that this cannot verify whether the original handle is closed.
+ auto_handle.Reset();
+ EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle.Get());
+
+ // Tests that Reset assigns the new handle.
+ // Note that this cannot verify whether the original handle is closed.
+ handle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ ASSERT_NE(INVALID_HANDLE_VALUE, handle);
+ auto_handle.Reset(handle);
+ EXPECT_EQ(handle, auto_handle.Get());
+
+ // Tests that AutoHandle contains INVALID_HANDLE_VALUE by default.
+ testing::internal::AutoHandle auto_handle2;
+ EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle2.Get());
+}
+# endif // GTEST_OS_WINDOWS
+
+# if GTEST_OS_WINDOWS
+typedef unsigned __int64 BiggestParsable;
+typedef signed __int64 BiggestSignedParsable;
+const BiggestParsable kBiggestParsableMax = ULLONG_MAX;
+const BiggestSignedParsable kBiggestSignedParsableMax = LLONG_MAX;
+# else
+typedef unsigned long long BiggestParsable;
+typedef signed long long BiggestSignedParsable;
+const BiggestParsable kBiggestParsableMax =
+ ::std::numeric_limits<BiggestParsable>::max();
+const BiggestSignedParsable kBiggestSignedParsableMax =
+ ::std::numeric_limits<BiggestSignedParsable>::max();
+# endif // GTEST_OS_WINDOWS
+
+TEST(ParseNaturalNumberTest, RejectsInvalidFormat)
+{
+ BiggestParsable result = 0;
+
+ // Rejects non-numbers.
+ EXPECT_FALSE(ParseNaturalNumber("non-number string", &result));
+
+ // Rejects numbers with whitespace prefix.
+ EXPECT_FALSE(ParseNaturalNumber(" 123", &result));
+
+ // Rejects negative numbers.
+ EXPECT_FALSE(ParseNaturalNumber("-123", &result));
+
+ // Rejects numbers starting with a plus sign.
+ EXPECT_FALSE(ParseNaturalNumber("+123", &result));
+ errno = 0;
+}
+
+TEST(ParseNaturalNumberTest, RejectsOverflownNumbers)
+{
+ BiggestParsable result = 0;
+
+ EXPECT_FALSE(ParseNaturalNumber("99999999999999999999999", &result));
+
+ signed char char_result = 0;
+ EXPECT_FALSE(ParseNaturalNumber("200", &char_result));
+ errno = 0;
+}
+
+TEST(ParseNaturalNumberTest, AcceptsValidNumbers)
+{
+ BiggestParsable result = 0;
+
+ result = 0;
+ ASSERT_TRUE(ParseNaturalNumber("123", &result));
+ EXPECT_EQ(123U, result);
+
+ // Check 0 as an edge case.
+ result = 1;
+ ASSERT_TRUE(ParseNaturalNumber("0", &result));
+ EXPECT_EQ(0U, result);
+
+ result = 1;
+ ASSERT_TRUE(ParseNaturalNumber("00000", &result));
+ EXPECT_EQ(0U, result);
+}
+
+TEST(ParseNaturalNumberTest, AcceptsTypeLimits)
+{
+ Message msg;
+ msg << kBiggestParsableMax;
+
+ BiggestParsable result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg.GetString(), &result));
+ EXPECT_EQ(kBiggestParsableMax, result);
+
+ Message msg2;
+ msg2 << kBiggestSignedParsableMax;
+
+ BiggestSignedParsable signed_result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg2.GetString(), &signed_result));
+ EXPECT_EQ(kBiggestSignedParsableMax, signed_result);
+
+ Message msg3;
+ msg3 << INT_MAX;
+
+ int int_result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg3.GetString(), &int_result));
+ EXPECT_EQ(INT_MAX, int_result);
+
+ Message msg4;
+ msg4 << UINT_MAX;
+
+ unsigned int uint_result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg4.GetString(), &uint_result));
+ EXPECT_EQ(UINT_MAX, uint_result);
+}
+
+TEST(ParseNaturalNumberTest, WorksForShorterIntegers)
+{
+ short short_result = 0;
+ ASSERT_TRUE(ParseNaturalNumber("123", &short_result));
+ EXPECT_EQ(123, short_result);
+
+ signed char char_result = 0;
+ ASSERT_TRUE(ParseNaturalNumber("123", &char_result));
+ EXPECT_EQ(123, char_result);
+}
+
+# if GTEST_OS_WINDOWS
+TEST(EnvironmentTest, HandleFitsIntoSizeT)
+{
+ // TODO(vladl at google.com): Remove this test after this condition is verified
+ // in a static assertion in gtest-death-test.cc in the function
+ // GetStatusFileDescriptor.
+ ASSERT_TRUE(sizeof(HANDLE) <= sizeof(size_t));
+}
+# endif // GTEST_OS_WINDOWS
+
+// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED trigger
+// failures when death tests are available on the system.
+TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable)
+{
+ EXPECT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestExpectMacro"),
+ "death inside CondDeathTestExpectMacro");
+ ASSERT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestAssertMacro"),
+ "death inside CondDeathTestAssertMacro");
+
+ // Empty statement will not crash, which must trigger a failure.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH_IF_SUPPORTED(; , ""), "");
+ EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(; , ""), "");
+}
+
+#else
+
+using testing::internal::CaptureStderr;
+using testing::internal::GetCapturedStderr;
+
+// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still
+// defined but do not trigger failures when death tests are not available on
+// the system.
+TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable)
+{
+ // Empty statement will not crash, but that should not trigger a failure
+ // when death tests are not supported.
+ CaptureStderr();
+ EXPECT_DEATH_IF_SUPPORTED(; , "");
+ std::string output = GetCapturedStderr();
+ ASSERT_TRUE(NULL != strstr(output.c_str(),
+ "Death tests are not supported on this platform"));
+ ASSERT_TRUE(NULL != strstr(output.c_str(), ";"));
+
+ // The streamed message should not be printed as there is no test failure.
+ CaptureStderr();
+ EXPECT_DEATH_IF_SUPPORTED(; , "") << "streamed message";
+ output = GetCapturedStderr();
+ ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message"));
+
+ CaptureStderr();
+ ASSERT_DEATH_IF_SUPPORTED(; , ""); // NOLINT
+ output = GetCapturedStderr();
+ ASSERT_TRUE(NULL != strstr(output.c_str(),
+ "Death tests are not supported on this platform"));
+ ASSERT_TRUE(NULL != strstr(output.c_str(), ";"));
+
+ CaptureStderr();
+ ASSERT_DEATH_IF_SUPPORTED(; , "") << "streamed message"; // NOLINT
+ output = GetCapturedStderr();
+ ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message"));
+}
+
+void FuncWithAssert(int* n)
+{
+ ASSERT_DEATH_IF_SUPPORTED(return; , "");
+ (*n)++;
+}
+
+// Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current
+// function (as ASSERT_DEATH does) if death tests are not supported.
+TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported)
+{
+ int n = 0;
+ FuncWithAssert(&n);
+ EXPECT_EQ(1, n);
+}
+
+TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInFastStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_FALSE(InDeathTestChild());
+ EXPECT_DEATH({
+ fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside");
+ fflush(stderr);
+ _exit(1);
+ }, "Inside");
+}
+
+TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle)
+{
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ EXPECT_FALSE(InDeathTestChild());
+ EXPECT_DEATH({
+ fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside");
+ fflush(stderr);
+ _exit(1);
+ }, "Inside");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Tests that the death test macros expand to code which may or may not
+// be followed by operator<<, and that in either case the complete text
+// comprises only a single C++ statement.
+//
+// The syntax should work whether death tests are available or not.
+TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement)
+{
+ if (AlwaysFalse())
+ // This would fail if executed; this is a compilation test only
+ ASSERT_DEATH_IF_SUPPORTED(return, "");
+
+ if (AlwaysTrue())
+ EXPECT_DEATH_IF_SUPPORTED(_exit(1), "");
+ else
+ // This empty "else" branch is meant to ensure that EXPECT_DEATH
+ // doesn't expand into an "if" statement without an "else"
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die";
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3;
+}
+
+// Tests that conditional death test macros expand to code which interacts
+// well with switch statements.
+TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement)
+{
+// Microsoft compiler usually complains about switch statements without
+// case labels. We suppress that warning for this test.
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4065)
+#endif // _MSC_VER
+
+ switch (0)
+ default:
+ ASSERT_DEATH_IF_SUPPORTED(_exit(1), "")
+ << "exit in default switch handler";
+
+ switch (0)
+ case 0:
+ EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case";
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif // _MSC_VER
+}
+
+// Tests that a test case whose name ends with "DeathTest" works fine
+// on Windows.
+TEST(NotADeathTest, Test)
+{
+ SUCCEED();
+}
diff --git a/external/gtest-1.6.0/test/gtest-filepath_test.cc b/external/gtest-1.6.0/test/gtest-filepath_test.cc
new file mode 100644
index 0000000..aa52597
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-filepath_test.cc
@@ -0,0 +1,753 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray at gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This file tests classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included from gtest_unittest.cc, to avoid changing
+// build or make-files for some existing Google Test clients. Do not
+// #include this file anywhere else!
+
+#include "gtest/internal/gtest-filepath.h"
+#include "gtest/gtest.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h> // NOLINT
+#elif GTEST_OS_WINDOWS
+# include <direct.h> // NOLINT
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+namespace testing
+{
+namespace internal
+{
+namespace
+{
+
+#if GTEST_OS_WINDOWS_MOBILE
+// TODO(wan at google.com): Move these to the POSIX adapter section in
+// gtest-port.h.
+
+// Windows CE doesn't have the remove C function.
+int remove(const char* path)
+{
+ LPCWSTR wpath = String::AnsiToUtf16(path);
+ int ret = DeleteFile(wpath) ? 0 : -1;
+ delete [] wpath;
+ return ret;
+}
+// Windows CE doesn't have the _rmdir C function.
+int _rmdir(const char* path)
+{
+ FilePath filepath(path);
+ LPCWSTR wpath = String::AnsiToUtf16(
+ filepath.RemoveTrailingPathSeparator().c_str());
+ int ret = RemoveDirectory(wpath) ? 0 : -1;
+ delete [] wpath;
+ return ret;
+}
+
+#else
+
+TEST(GetCurrentDirTest, ReturnsCurrentDir)
+{
+ const FilePath original_dir = FilePath::GetCurrentDir();
+ EXPECT_FALSE(original_dir.IsEmpty());
+
+ posix::ChDir(GTEST_PATH_SEP_);
+ const FilePath cwd = FilePath::GetCurrentDir();
+ posix::ChDir(original_dir.c_str());
+
+# if GTEST_OS_WINDOWS
+
+ // Skips the ":".
+ const char* const cwd_without_drive = strchr(cwd.c_str(), ':');
+ ASSERT_TRUE(cwd_without_drive != NULL);
+ EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1);
+
+# else
+
+ EXPECT_EQ(GTEST_PATH_SEP_, cwd.string());
+
+# endif
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+TEST(IsEmptyTest, ReturnsTrueForEmptyPath)
+{
+ EXPECT_TRUE(FilePath("").IsEmpty());
+}
+
+TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath)
+{
+ EXPECT_FALSE(FilePath("a").IsEmpty());
+ EXPECT_FALSE(FilePath(".").IsEmpty());
+ EXPECT_FALSE(FilePath("a/b").IsEmpty());
+ EXPECT_FALSE(FilePath("a\\b\\").IsEmpty());
+}
+
+// RemoveDirectoryName "" -> ""
+TEST(RemoveDirectoryNameTest, WhenEmptyName)
+{
+ EXPECT_EQ("", FilePath("").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName "afile" -> "afile"
+TEST(RemoveDirectoryNameTest, ButNoDirectory)
+{
+ EXPECT_EQ("afile",
+ FilePath("afile").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName "/afile" -> "afile"
+TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName)
+{
+ EXPECT_EQ("afile",
+ FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName "adir/" -> ""
+TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName)
+{
+ EXPECT_EQ("",
+ FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName "adir/afile" -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldGiveFileName)
+{
+ EXPECT_EQ("afile",
+ FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName "adir/subdir/afile" -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName)
+{
+ EXPECT_EQ("afile",
+ FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile")
+ .RemoveDirectoryName().string());
+}
+
+#if GTEST_HAS_ALT_PATH_SEP_
+
+// Tests that RemoveDirectoryName() works with the alternate separator
+// on Windows.
+
+// RemoveDirectoryName("/afile") -> "afile"
+TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator)
+{
+ EXPECT_EQ("afile", FilePath("/afile").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName("adir/") -> ""
+TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator)
+{
+ EXPECT_EQ("", FilePath("adir/").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName("adir/afile") -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator)
+{
+ EXPECT_EQ("afile", FilePath("adir/afile").RemoveDirectoryName().string());
+}
+
+// RemoveDirectoryName("adir/subdir/afile") -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator)
+{
+ EXPECT_EQ("afile",
+ FilePath("adir/subdir/afile").RemoveDirectoryName().string());
+}
+
+#endif
+
+// RemoveFileName "" -> "./"
+TEST(RemoveFileNameTest, EmptyName)
+{
+#if GTEST_OS_WINDOWS_MOBILE
+ // On Windows CE, we use the root as the current directory.
+ EXPECT_EQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().string());
+#else
+ EXPECT_EQ("." GTEST_PATH_SEP_, FilePath("").RemoveFileName().string());
+#endif
+}
+
+// RemoveFileName "adir/" -> "adir/"
+TEST(RemoveFileNameTest, ButNoFile)
+{
+ EXPECT_EQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().string());
+}
+
+// RemoveFileName "adir/afile" -> "adir/"
+TEST(RemoveFileNameTest, GivesDirName)
+{
+ EXPECT_EQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveFileName().string());
+}
+
+// RemoveFileName "adir/subdir/afile" -> "adir/subdir/"
+TEST(RemoveFileNameTest, GivesDirAndSubDirName)
+{
+ EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_,
+ FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile")
+ .RemoveFileName().string());
+}
+
+// RemoveFileName "/afile" -> "/"
+TEST(RemoveFileNameTest, GivesRootDir)
+{
+ EXPECT_EQ(GTEST_PATH_SEP_,
+ FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().string());
+}
+
+#if GTEST_HAS_ALT_PATH_SEP_
+
+// Tests that RemoveFileName() works with the alternate separator on
+// Windows.
+
+// RemoveFileName("adir/") -> "adir/"
+TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator)
+{
+ EXPECT_EQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir/").RemoveFileName().string());
+}
+
+// RemoveFileName("adir/afile") -> "adir/"
+TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator)
+{
+ EXPECT_EQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir/afile").RemoveFileName().string());
+}
+
+// RemoveFileName("adir/subdir/afile") -> "adir/subdir/"
+TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator)
+{
+ EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_,
+ FilePath("adir/subdir/afile").RemoveFileName().string());
+}
+
+// RemoveFileName("/afile") -> "\"
+TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator)
+{
+ EXPECT_EQ(GTEST_PATH_SEP_, FilePath("/afile").RemoveFileName().string());
+}
+
+#endif
+
+TEST(MakeFileNameTest, GenerateWhenNumberIsZero)
+{
+ FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"),
+ 0, "xml");
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
+}
+
+TEST(MakeFileNameTest, GenerateFileNameNumberGtZero)
+{
+ FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"),
+ 12, "xml");
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string());
+}
+
+TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero)
+{
+ FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar"), 0, "xml");
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
+}
+
+TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero)
+{
+ FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar"), 12, "xml");
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string());
+}
+
+TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty)
+{
+ FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"),
+ 0, "xml");
+ EXPECT_EQ("bar.xml", actual.string());
+}
+
+TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty)
+{
+ FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"),
+ 14, "xml");
+ EXPECT_EQ("bar_14.xml", actual.string());
+}
+
+TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
+ FilePath("bar.xml"));
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
+}
+
+TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar.xml"));
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string());
+}
+
+TEST(ConcatPathsTest, Path1BeingEmpty)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath(""),
+ FilePath("bar.xml"));
+ EXPECT_EQ("bar.xml", actual.string());
+}
+
+TEST(ConcatPathsTest, Path2BeingEmpty)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath(""));
+ EXPECT_EQ("foo" GTEST_PATH_SEP_, actual.string());
+}
+
+TEST(ConcatPathsTest, BothPathBeingEmpty)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath(""),
+ FilePath(""));
+ EXPECT_EQ("", actual.string());
+}
+
+TEST(ConcatPathsTest, Path1ContainsPathSep)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"),
+ FilePath("foobar.xml"));
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml",
+ actual.string());
+}
+
+TEST(ConcatPathsTest, Path2ContainsPathSep)
+{
+ FilePath actual = FilePath::ConcatPaths(
+ FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar" GTEST_PATH_SEP_ "bar.xml"));
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml",
+ actual.string());
+}
+
+TEST(ConcatPathsTest, Path2EndsWithPathSep)
+{
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
+ FilePath("bar" GTEST_PATH_SEP_));
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.string());
+}
+
+// RemoveTrailingPathSeparator "" -> ""
+TEST(RemoveTrailingPathSeparatorTest, EmptyString)
+{
+ EXPECT_EQ("", FilePath("").RemoveTrailingPathSeparator().string());
+}
+
+// RemoveTrailingPathSeparator "foo" -> "foo"
+TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString)
+{
+ EXPECT_EQ("foo", FilePath("foo").RemoveTrailingPathSeparator().string());
+}
+
+// RemoveTrailingPathSeparator "foo/" -> "foo"
+TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator)
+{
+ EXPECT_EQ("foo",
+ FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().string());
+#if GTEST_HAS_ALT_PATH_SEP_
+ EXPECT_EQ("foo", FilePath("foo/").RemoveTrailingPathSeparator().string());
+#endif
+}
+
+// RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/"
+TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator)
+{
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_)
+ .RemoveTrailingPathSeparator().string());
+}
+
+// RemoveTrailingPathSeparator "foo/bar" -> "foo/bar"
+TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified)
+{
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ "bar")
+ .RemoveTrailingPathSeparator().string());
+}
+
+TEST(DirectoryTest, RootDirectoryExists)
+{
+#if GTEST_OS_WINDOWS // We are on Windows.
+ char current_drive[_MAX_PATH]; // NOLINT
+ current_drive[0] = static_cast<char>(_getdrive() + 'A' - 1);
+ current_drive[1] = ':';
+ current_drive[2] = '\\';
+ current_drive[3] = '\0';
+ EXPECT_TRUE(FilePath(current_drive).DirectoryExists());
+#else
+ EXPECT_TRUE(FilePath("/").DirectoryExists());
+#endif // GTEST_OS_WINDOWS
+}
+
+#if GTEST_OS_WINDOWS
+TEST(DirectoryTest, RootOfWrongDriveDoesNotExists)
+{
+ const int saved_drive_ = _getdrive();
+ // Find a drive that doesn't exist. Start with 'Z' to avoid common ones.
+ for (char drive = 'Z'; drive >= 'A'; drive--)
+ if (_chdrive(drive - 'A' + 1) == -1) {
+ char non_drive[_MAX_PATH]; // NOLINT
+ non_drive[0] = drive;
+ non_drive[1] = ':';
+ non_drive[2] = '\\';
+ non_drive[3] = '\0';
+ EXPECT_FALSE(FilePath(non_drive).DirectoryExists());
+ break;
+ }
+ _chdrive(saved_drive_);
+}
+#endif // GTEST_OS_WINDOWS
+
+#if !GTEST_OS_WINDOWS_MOBILE
+// Windows CE _does_ consider an empty directory to exist.
+TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist)
+{
+ EXPECT_FALSE(FilePath("").DirectoryExists());
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+TEST(DirectoryTest, CurrentDirectoryExists)
+{
+#if GTEST_OS_WINDOWS // We are on Windows.
+# ifndef _WIN32_CE // Windows CE doesn't have a current directory.
+
+ EXPECT_TRUE(FilePath(".").DirectoryExists());
+ EXPECT_TRUE(FilePath(".\\").DirectoryExists());
+
+# endif // _WIN32_CE
+#else
+ EXPECT_TRUE(FilePath(".").DirectoryExists());
+ EXPECT_TRUE(FilePath("./").DirectoryExists());
+#endif // GTEST_OS_WINDOWS
+}
+
+// "foo/bar" == foo//bar" == "foo///bar"
+TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring)
+{
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ "bar").string());
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string());
+ EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_
+ GTEST_PATH_SEP_ "bar").string());
+}
+
+// "/bar" == //bar" == "///bar"
+TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart)
+{
+ EXPECT_EQ(GTEST_PATH_SEP_ "bar",
+ FilePath(GTEST_PATH_SEP_ "bar").string());
+ EXPECT_EQ(GTEST_PATH_SEP_ "bar",
+ FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string());
+ EXPECT_EQ(GTEST_PATH_SEP_ "bar",
+ FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string());
+}
+
+// "foo/" == foo//" == "foo///"
+TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd)
+{
+ EXPECT_EQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_).string());
+ EXPECT_EQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).string());
+ EXPECT_EQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).string());
+}
+
+#if GTEST_HAS_ALT_PATH_SEP_
+
+// Tests that separators at the end of the string are normalized
+// regardless of their combination (e.g. "foo\" =="foo/\" ==
+// "foo\\/").
+TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd)
+{
+ EXPECT_EQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo/").string());
+ EXPECT_EQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_ "/").string());
+ EXPECT_EQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo//" GTEST_PATH_SEP_).string());
+}
+
+#endif
+
+TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault)
+{
+ FilePath default_path;
+ FilePath non_default_path("path");
+ non_default_path = default_path;
+ EXPECT_EQ("", non_default_path.string());
+ EXPECT_EQ("", default_path.string()); // RHS var is unchanged.
+}
+
+TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault)
+{
+ FilePath non_default_path("path");
+ FilePath default_path;
+ default_path = non_default_path;
+ EXPECT_EQ("path", default_path.string());
+ EXPECT_EQ("path", non_default_path.string()); // RHS var is unchanged.
+}
+
+TEST(AssignmentOperatorTest, ConstAssignedToNonConst)
+{
+ const FilePath const_default_path("const_path");
+ FilePath non_default_path("path");
+ non_default_path = const_default_path;
+ EXPECT_EQ("const_path", non_default_path.string());
+}
+
+class DirectoryCreationTest : public Test
+{
+ protected:
+ virtual void SetUp() {
+ testdata_path_.Set(FilePath(
+ TempDir() + GetCurrentExecutableName().string() +
+ "_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_));
+ testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator());
+
+ unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"),
+ 0, "txt"));
+ unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"),
+ 1, "txt"));
+
+ remove(testdata_file_.c_str());
+ remove(unique_file0_.c_str());
+ remove(unique_file1_.c_str());
+ posix::RmDir(testdata_path_.c_str());
+ }
+
+ virtual void TearDown() {
+ remove(testdata_file_.c_str());
+ remove(unique_file0_.c_str());
+ remove(unique_file1_.c_str());
+ posix::RmDir(testdata_path_.c_str());
+ }
+
+ std::string TempDir() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ return "\\temp\\";
+#elif GTEST_OS_WINDOWS
+ const char* temp_dir = posix::GetEnv("TEMP");
+ if (temp_dir == NULL || temp_dir[0] == '\0')
+ return "\\temp\\";
+ else if (temp_dir[strlen(temp_dir) - 1] == '\\')
+ return temp_dir;
+ else
+ return std::string(temp_dir) + "\\";
+#elif GTEST_OS_LINUX_ANDROID
+ return "/sdcard/";
+#else
+ return "/tmp/";
+#endif // GTEST_OS_WINDOWS_MOBILE
+ }
+
+ void CreateTextFile(const char* filename) {
+ FILE* f = posix::FOpen(filename, "w");
+ fprintf(f, "text\n");
+ fclose(f);
+ }
+
+ // Strings representing a directory and a file, with identical paths
+ // except for the trailing separator character that distinquishes
+ // a directory named 'test' from a file named 'test'. Example names:
+ FilePath testdata_path_; // "/tmp/directory_creation/test/"
+ FilePath testdata_file_; // "/tmp/directory_creation/test"
+ FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt"
+ FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt"
+};
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively)
+{
+ EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string();
+ EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
+ EXPECT_TRUE(testdata_path_.DirectoryExists());
+}
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath)
+{
+ EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string();
+ EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
+ // Call 'create' again... should still succeed.
+ EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
+}
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename)
+{
+ FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_,
+ FilePath("unique"), "txt"));
+ EXPECT_EQ(unique_file0_.string(), file_path.string());
+ EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there
+
+ testdata_path_.CreateDirectoriesRecursively();
+ EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there
+ CreateTextFile(file_path.c_str());
+ EXPECT_TRUE(file_path.FileOrDirectoryExists());
+
+ FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_,
+ FilePath("unique"), "txt"));
+ EXPECT_EQ(unique_file1_.string(), file_path2.string());
+ EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there
+ CreateTextFile(file_path2.c_str());
+ EXPECT_TRUE(file_path2.FileOrDirectoryExists());
+}
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesFail)
+{
+ // force a failure by putting a file where we will try to create a directory.
+ CreateTextFile(testdata_file_.c_str());
+ EXPECT_TRUE(testdata_file_.FileOrDirectoryExists());
+ EXPECT_FALSE(testdata_file_.DirectoryExists());
+ EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively());
+}
+
+TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile)
+{
+ const FilePath test_detail_xml("test_detail.xml");
+ EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively());
+}
+
+TEST(FilePathTest, DefaultConstructor)
+{
+ FilePath fp;
+ EXPECT_EQ("", fp.string());
+}
+
+TEST(FilePathTest, CharAndCopyConstructors)
+{
+ const FilePath fp("spicy");
+ EXPECT_EQ("spicy", fp.string());
+
+ const FilePath fp_copy(fp);
+ EXPECT_EQ("spicy", fp_copy.string());
+}
+
+TEST(FilePathTest, StringConstructor)
+{
+ const FilePath fp(std::string("cider"));
+ EXPECT_EQ("cider", fp.string());
+}
+
+TEST(FilePathTest, Set)
+{
+ const FilePath apple("apple");
+ FilePath mac("mac");
+ mac.Set(apple); // Implement Set() since overloading operator= is forbidden.
+ EXPECT_EQ("apple", mac.string());
+ EXPECT_EQ("apple", apple.string());
+}
+
+TEST(FilePathTest, ToString)
+{
+ const FilePath file("drink");
+ EXPECT_EQ("drink", file.string());
+}
+
+TEST(FilePathTest, RemoveExtension)
+{
+ EXPECT_EQ("app", FilePath("app.cc").RemoveExtension("cc").string());
+ EXPECT_EQ("app", FilePath("app.exe").RemoveExtension("exe").string());
+ EXPECT_EQ("APP", FilePath("APP.EXE").RemoveExtension("exe").string());
+}
+
+TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension)
+{
+ EXPECT_EQ("app", FilePath("app").RemoveExtension("exe").string());
+}
+
+TEST(FilePathTest, IsDirectory)
+{
+ EXPECT_FALSE(FilePath("cola").IsDirectory());
+ EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory());
+#if GTEST_HAS_ALT_PATH_SEP_
+ EXPECT_TRUE(FilePath("koala/").IsDirectory());
+#endif
+}
+
+TEST(FilePathTest, IsAbsolutePath)
+{
+ EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath());
+ EXPECT_FALSE(FilePath("").IsAbsolutePath());
+#if GTEST_OS_WINDOWS
+ EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not"
+ GTEST_PATH_SEP_ "relative").IsAbsolutePath());
+ EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath());
+ EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not"
+ GTEST_PATH_SEP_ "relative").IsAbsolutePath());
+#else
+ EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative")
+ .IsAbsolutePath());
+#endif // GTEST_OS_WINDOWS
+}
+
+TEST(FilePathTest, IsRootDirectory)
+{
+#if GTEST_OS_WINDOWS
+ EXPECT_TRUE(FilePath("a:\\").IsRootDirectory());
+ EXPECT_TRUE(FilePath("Z:/").IsRootDirectory());
+ EXPECT_TRUE(FilePath("e://").IsRootDirectory());
+ EXPECT_FALSE(FilePath("").IsRootDirectory());
+ EXPECT_FALSE(FilePath("b:").IsRootDirectory());
+ EXPECT_FALSE(FilePath("b:a").IsRootDirectory());
+ EXPECT_FALSE(FilePath("8:/").IsRootDirectory());
+ EXPECT_FALSE(FilePath("c|/").IsRootDirectory());
+#else
+ EXPECT_TRUE(FilePath("/").IsRootDirectory());
+ EXPECT_TRUE(FilePath("//").IsRootDirectory());
+ EXPECT_FALSE(FilePath("").IsRootDirectory());
+ EXPECT_FALSE(FilePath("\\").IsRootDirectory());
+ EXPECT_FALSE(FilePath("/x").IsRootDirectory());
+#endif
+}
+
+} // namespace
+} // namespace internal
+} // namespace testing
diff --git a/external/gtest-1.6.0/test/gtest-linked_ptr_test.cc b/external/gtest-1.6.0/test/gtest-linked_ptr_test.cc
new file mode 100644
index 0000000..0d2b80a
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-linked_ptr_test.cc
@@ -0,0 +1,159 @@
+// Copyright 2003, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor at google.com)
+// Ported to Windows: Vadim Berman (vadimb at google.com)
+
+#include "gtest/internal/gtest-linked_ptr.h"
+
+#include <stdlib.h>
+#include "gtest/gtest.h"
+
+namespace
+{
+
+using testing::Message;
+using testing::internal::linked_ptr;
+
+int num;
+Message* history = NULL;
+
+// Class which tracks allocation/deallocation
+class A
+{
+ public:
+ A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; }
+ virtual ~A() { *history << "A" << mynum << " dtor\n"; }
+ virtual void Use() { *history << "A" << mynum << " use\n"; }
+ protected:
+ int mynum;
+};
+
+// Subclass
+class B : public A
+{
+ public:
+ B() { *history << "B" << mynum << " ctor\n"; }
+ ~B() { *history << "B" << mynum << " dtor\n"; }
+ virtual void Use() { *history << "B" << mynum << " use\n"; }
+};
+
+class LinkedPtrTest : public testing::Test
+{
+ public:
+ LinkedPtrTest() {
+ num = 0;
+ history = new Message;
+ }
+
+ virtual ~LinkedPtrTest() {
+ delete history;
+ history = NULL;
+ }
+};
+
+TEST_F(LinkedPtrTest, GeneralTest)
+{
+ {
+ linked_ptr<A> a0, a1, a2;
+ // Use explicit function call notation here to suppress self-assign warning.
+ a0.operator=(a0);
+ a1 = a2;
+ ASSERT_EQ(a0.get(), static_cast<A*>(NULL));
+ ASSERT_EQ(a1.get(), static_cast<A*>(NULL));
+ ASSERT_EQ(a2.get(), static_cast<A*>(NULL));
+ ASSERT_TRUE(a0 == NULL);
+ ASSERT_TRUE(a1 == NULL);
+ ASSERT_TRUE(a2 == NULL);
+
+ {
+ linked_ptr<A> a3(new A);
+ a0 = a3;
+ ASSERT_TRUE(a0 == a3);
+ ASSERT_TRUE(a0 != NULL);
+ ASSERT_TRUE(a0.get() == a3);
+ ASSERT_TRUE(a0 == a3.get());
+ linked_ptr<A> a4(a0);
+ a1 = a4;
+ linked_ptr<A> a5(new A);
+ ASSERT_TRUE(a5.get() != a3);
+ ASSERT_TRUE(a5 != a3.get());
+ a2 = a5;
+ linked_ptr<B> b0(new B);
+ linked_ptr<A> a6(b0);
+ ASSERT_TRUE(b0 == a6);
+ ASSERT_TRUE(a6 == b0);
+ ASSERT_TRUE(b0 != NULL);
+ a5 = b0;
+ a5 = b0;
+ a3->Use();
+ a4->Use();
+ a5->Use();
+ a6->Use();
+ b0->Use();
+ (*b0).Use();
+ b0.get()->Use();
+ }
+
+ a0->Use();
+ a1->Use();
+ a2->Use();
+
+ a1 = a2;
+ a2.reset(new A);
+ a0.reset();
+
+ linked_ptr<A> a7;
+ }
+
+ ASSERT_STREQ(
+ "A0 ctor\n"
+ "A1 ctor\n"
+ "A2 ctor\n"
+ "B2 ctor\n"
+ "A0 use\n"
+ "A0 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 dtor\n"
+ "A2 dtor\n"
+ "A0 use\n"
+ "A0 use\n"
+ "A1 use\n"
+ "A3 ctor\n"
+ "A0 dtor\n"
+ "A3 dtor\n"
+ "A1 dtor\n",
+ history->GetString().c_str());
+}
+
+} // Unnamed namespace
diff --git a/external/gtest-1.6.0/test/gtest-listener_test.cc b/external/gtest-1.6.0/test/gtest-listener_test.cc
new file mode 100644
index 0000000..9812d54
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-listener_test.cc
@@ -0,0 +1,319 @@
+// Copyright 2009 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This file verifies Google Test event listeners receive events at the
+// right times.
+
+#include "gtest/gtest.h"
+#include <vector>
+
+using ::testing::AddGlobalTestEnvironment;
+using ::testing::Environment;
+using ::testing::InitGoogleTest;
+using ::testing::Test;
+using ::testing::TestCase;
+using ::testing::TestEventListener;
+using ::testing::TestInfo;
+using ::testing::TestPartResult;
+using ::testing::UnitTest;
+
+// Used by tests to register their events.
+std::vector<std::string>* g_events = NULL;
+
+namespace testing
+{
+namespace internal
+{
+
+class EventRecordingListener : public TestEventListener
+{
+ public:
+ explicit EventRecordingListener(const char* name) : name_(name) {}
+
+ protected:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnTestProgramStart"));
+ }
+
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int iteration) {
+ Message message;
+ message << GetFullMethodName("OnTestIterationStart")
+ << "(" << iteration << ")";
+ g_events->push_back(message.GetString());
+ }
+
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart"));
+ }
+
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd"));
+ }
+
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {
+ g_events->push_back(GetFullMethodName("OnTestCaseStart"));
+ }
+
+ virtual void OnTestStart(const TestInfo& /*test_info*/) {
+ g_events->push_back(GetFullMethodName("OnTestStart"));
+ }
+
+ virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {
+ g_events->push_back(GetFullMethodName("OnTestPartResult"));
+ }
+
+ virtual void OnTestEnd(const TestInfo& /*test_info*/) {
+ g_events->push_back(GetFullMethodName("OnTestEnd"));
+ }
+
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {
+ g_events->push_back(GetFullMethodName("OnTestCaseEnd"));
+ }
+
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart"));
+ }
+
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd"));
+ }
+
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int iteration) {
+ Message message;
+ message << GetFullMethodName("OnTestIterationEnd")
+ << "(" << iteration << ")";
+ g_events->push_back(message.GetString());
+ }
+
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnTestProgramEnd"));
+ }
+
+ private:
+ std::string GetFullMethodName(const char* name) {
+ return name_ + "." + name;
+ }
+
+ std::string name_;
+};
+
+class EnvironmentInvocationCatcher : public Environment
+{
+ protected:
+ virtual void SetUp() {
+ g_events->push_back("Environment::SetUp");
+ }
+
+ virtual void TearDown() {
+ g_events->push_back("Environment::TearDown");
+ }
+};
+
+class ListenerTest : public Test
+{
+ protected:
+ static void SetUpTestCase() {
+ g_events->push_back("ListenerTest::SetUpTestCase");
+ }
+
+ static void TearDownTestCase() {
+ g_events->push_back("ListenerTest::TearDownTestCase");
+ }
+
+ virtual void SetUp() {
+ g_events->push_back("ListenerTest::SetUp");
+ }
+
+ virtual void TearDown() {
+ g_events->push_back("ListenerTest::TearDown");
+ }
+};
+
+TEST_F(ListenerTest, DoesFoo)
+{
+ // Test execution order within a test case is not guaranteed so we are not
+ // recording the test name.
+ g_events->push_back("ListenerTest::* Test Body");
+ SUCCEED(); // Triggers OnTestPartResult.
+}
+
+TEST_F(ListenerTest, DoesBar)
+{
+ g_events->push_back("ListenerTest::* Test Body");
+ SUCCEED(); // Triggers OnTestPartResult.
+}
+
+} // namespace internal
+
+} // namespace testing
+
+using ::testing::internal::EnvironmentInvocationCatcher;
+using ::testing::internal::EventRecordingListener;
+
+void VerifyResults(const std::vector<std::string>& data,
+ const char* const* expected_data,
+ int expected_data_size)
+{
+ const int actual_size = data.size();
+ // If the following assertion fails, a new entry will be appended to
+ // data. Hence we save data.size() first.
+ EXPECT_EQ(expected_data_size, actual_size);
+
+ // Compares the common prefix.
+ const int shorter_size = expected_data_size <= actual_size ?
+ expected_data_size : actual_size;
+ int i = 0;
+ for (; i < shorter_size; ++i) {
+ ASSERT_STREQ(expected_data[i], data[i].c_str())
+ << "at position " << i;
+ }
+
+ // Prints extra elements in the actual data.
+ for (; i < actual_size; ++i) {
+ printf(" Actual event #%d: %s\n", i, data[i].c_str());
+ }
+}
+
+int main(int argc, char** argv)
+{
+ std::vector<std::string> events;
+ g_events = &events;
+ InitGoogleTest(&argc, argv);
+
+ UnitTest::GetInstance()->listeners().Append(
+ new EventRecordingListener("1st"));
+ UnitTest::GetInstance()->listeners().Append(
+ new EventRecordingListener("2nd"));
+
+ AddGlobalTestEnvironment(new EnvironmentInvocationCatcher);
+
+ GTEST_CHECK_(events.size() == 0)
+ << "AddGlobalTestEnvironment should not generate any events itself.";
+
+ ::testing::GTEST_FLAG(repeat) = 2;
+ int ret_val = RUN_ALL_TESTS();
+
+ const char* const expected_events[] = {
+ "1st.OnTestProgramStart",
+ "2nd.OnTestProgramStart",
+ "1st.OnTestIterationStart(0)",
+ "2nd.OnTestIterationStart(0)",
+ "1st.OnEnvironmentsSetUpStart",
+ "2nd.OnEnvironmentsSetUpStart",
+ "Environment::SetUp",
+ "2nd.OnEnvironmentsSetUpEnd",
+ "1st.OnEnvironmentsSetUpEnd",
+ "1st.OnTestCaseStart",
+ "2nd.OnTestCaseStart",
+ "ListenerTest::SetUpTestCase",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "ListenerTest::TearDownTestCase",
+ "2nd.OnTestCaseEnd",
+ "1st.OnTestCaseEnd",
+ "1st.OnEnvironmentsTearDownStart",
+ "2nd.OnEnvironmentsTearDownStart",
+ "Environment::TearDown",
+ "2nd.OnEnvironmentsTearDownEnd",
+ "1st.OnEnvironmentsTearDownEnd",
+ "2nd.OnTestIterationEnd(0)",
+ "1st.OnTestIterationEnd(0)",
+ "1st.OnTestIterationStart(1)",
+ "2nd.OnTestIterationStart(1)",
+ "1st.OnEnvironmentsSetUpStart",
+ "2nd.OnEnvironmentsSetUpStart",
+ "Environment::SetUp",
+ "2nd.OnEnvironmentsSetUpEnd",
+ "1st.OnEnvironmentsSetUpEnd",
+ "1st.OnTestCaseStart",
+ "2nd.OnTestCaseStart",
+ "ListenerTest::SetUpTestCase",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "ListenerTest::TearDownTestCase",
+ "2nd.OnTestCaseEnd",
+ "1st.OnTestCaseEnd",
+ "1st.OnEnvironmentsTearDownStart",
+ "2nd.OnEnvironmentsTearDownStart",
+ "Environment::TearDown",
+ "2nd.OnEnvironmentsTearDownEnd",
+ "1st.OnEnvironmentsTearDownEnd",
+ "2nd.OnTestIterationEnd(1)",
+ "1st.OnTestIterationEnd(1)",
+ "2nd.OnTestProgramEnd",
+ "1st.OnTestProgramEnd"
+ };
+ VerifyResults(events,
+ expected_events,
+ sizeof(expected_events)/sizeof(expected_events[0]));
+
+ // We need to check manually for ad hoc test failures that happen after
+ // RUN_ALL_TESTS finishes.
+ if (UnitTest::GetInstance()->Failed())
+ ret_val = 1;
+
+ return ret_val;
+}
diff --git a/external/gtest-1.6.0/test/gtest-message_test.cc b/external/gtest-1.6.0/test/gtest-message_test.cc
new file mode 100644
index 0000000..c35e532
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-message_test.cc
@@ -0,0 +1,177 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Tests for the Message class.
+
+#include "gtest/gtest-message.h"
+
+#include "gtest/gtest.h"
+
+namespace
+{
+
+using ::testing::Message;
+
+// Tests the testing::Message class
+
+// Tests the default constructor.
+TEST(MessageTest, DefaultConstructor)
+{
+ const Message msg;
+ EXPECT_EQ("", msg.GetString());
+}
+
+// Tests the copy constructor.
+TEST(MessageTest, CopyConstructor)
+{
+ const Message msg1("Hello");
+ const Message msg2(msg1);
+ EXPECT_EQ("Hello", msg2.GetString());
+}
+
+// Tests constructing a Message from a C-string.
+TEST(MessageTest, ConstructsFromCString)
+{
+ Message msg("Hello");
+ EXPECT_EQ("Hello", msg.GetString());
+}
+
+// Tests streaming a float.
+TEST(MessageTest, StreamsFloat)
+{
+ const std::string s = (Message() << 1.23456F << " " << 2.34567F).GetString();
+ // Both numbers should be printed with enough precision.
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s.c_str());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s.c_str());
+}
+
+// Tests streaming a double.
+TEST(MessageTest, StreamsDouble)
+{
+ const std::string s = (Message() << 1260570880.4555497 << " "
+ << 1260572265.1954534).GetString();
+ // Both numbers should be printed with enough precision.
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s.c_str());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s.c_str());
+}
+
+// Tests streaming a non-char pointer.
+TEST(MessageTest, StreamsPointer)
+{
+ int n = 0;
+ int* p = &n;
+ EXPECT_NE("(null)", (Message() << p).GetString());
+}
+
+// Tests streaming a NULL non-char pointer.
+TEST(MessageTest, StreamsNullPointer)
+{
+ int* p = NULL;
+ EXPECT_EQ("(null)", (Message() << p).GetString());
+}
+
+// Tests streaming a C string.
+TEST(MessageTest, StreamsCString)
+{
+ EXPECT_EQ("Foo", (Message() << "Foo").GetString());
+}
+
+// Tests streaming a NULL C string.
+TEST(MessageTest, StreamsNullCString)
+{
+ char* p = NULL;
+ EXPECT_EQ("(null)", (Message() << p).GetString());
+}
+
+// Tests streaming std::string.
+TEST(MessageTest, StreamsString)
+{
+ const ::std::string str("Hello");
+ EXPECT_EQ("Hello", (Message() << str).GetString());
+}
+
+// Tests that we can output strings containing embedded NULs.
+TEST(MessageTest, StreamsStringWithEmbeddedNUL)
+{
+ const char char_array_with_nul[] =
+ "Here's a NUL\0 and some more string";
+ const ::std::string string_with_nul(char_array_with_nul,
+ sizeof(char_array_with_nul) - 1);
+ EXPECT_EQ("Here's a NUL\\0 and some more string",
+ (Message() << string_with_nul).GetString());
+}
+
+// Tests streaming a NUL char.
+TEST(MessageTest, StreamsNULChar)
+{
+ EXPECT_EQ("\\0", (Message() << '\0').GetString());
+}
+
+// Tests streaming int.
+TEST(MessageTest, StreamsInt)
+{
+ EXPECT_EQ("123", (Message() << 123).GetString());
+}
+
+// Tests that basic IO manipulators (endl, ends, and flush) can be
+// streamed to Message.
+TEST(MessageTest, StreamsBasicIoManip)
+{
+ EXPECT_EQ("Line 1.\nA NUL char \\0 in line 2.",
+ (Message() << "Line 1." << std::endl
+ << "A NUL char " << std::ends << std::flush
+ << " in line 2.").GetString());
+}
+
+// Tests Message::GetString()
+TEST(MessageTest, GetString)
+{
+ Message msg;
+ msg << 1 << " lamb";
+ EXPECT_EQ("1 lamb", msg.GetString());
+}
+
+// Tests streaming a Message object to an ostream.
+TEST(MessageTest, StreamsToOStream)
+{
+ Message msg("Hello");
+ ::std::stringstream ss;
+ ss << msg;
+ EXPECT_EQ("Hello", testing::internal::StringStreamToString(&ss));
+}
+
+// Tests that a Message object doesn't take up too much stack space.
+TEST(MessageTest, DoesNotTakeUpMuchStackSpace)
+{
+ EXPECT_LE(sizeof(Message), 16U);
+}
+
+} // namespace
diff --git a/external/gtest-1.6.0/test/gtest-options_test.cc b/external/gtest-1.6.0/test/gtest-options_test.cc
new file mode 100644
index 0000000..1da2286
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-options_test.cc
@@ -0,0 +1,232 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray at gmail.com (Keith Ray)
+//
+// Google Test UnitTestOptions tests
+//
+// This file tests classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included from gtest.cc, to avoid changing build or
+// make-files on Windows and other platforms. Do not #include this file
+// anywhere else!
+
+#include "gtest/gtest.h"
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>
+#elif GTEST_OS_WINDOWS
+# include <direct.h>
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+namespace internal
+{
+namespace
+{
+
+// Turns the given relative path into an absolute path.
+FilePath GetAbsolutePathOf(const FilePath& relative_path)
+{
+ return FilePath::ConcatPaths(FilePath::GetCurrentDir(), relative_path);
+}
+
+// Testing UnitTestOptions::GetOutputFormat/GetOutputFile.
+
+TEST(XmlOutputTest, GetOutputFormatDefault)
+{
+ GTEST_FLAG(output) = "";
+ EXPECT_STREQ("", UnitTestOptions::GetOutputFormat().c_str());
+}
+
+TEST(XmlOutputTest, GetOutputFormat)
+{
+ GTEST_FLAG(output) = "xml:filename";
+ EXPECT_STREQ("xml", UnitTestOptions::GetOutputFormat().c_str());
+}
+
+TEST(XmlOutputTest, GetOutputFileDefault)
+{
+ GTEST_FLAG(output) = "";
+ EXPECT_EQ(GetAbsolutePathOf(FilePath("test_detail.xml")).string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+}
+
+TEST(XmlOutputTest, GetOutputFileSingleFile)
+{
+ GTEST_FLAG(output) = "xml:filename.abc";
+ EXPECT_EQ(GetAbsolutePathOf(FilePath("filename.abc")).string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+}
+
+TEST(XmlOutputTest, GetOutputFileFromDirectoryPath)
+{
+ GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_;
+ const std::string expected_output_file =
+ GetAbsolutePathOf(
+ FilePath(std::string("path") + GTEST_PATH_SEP_ +
+ GetCurrentExecutableName().string() + ".xml")).string();
+ const std::string& output_file =
+ UnitTestOptions::GetAbsolutePathToOutputFile();
+#if GTEST_OS_WINDOWS
+ EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str());
+#else
+ EXPECT_EQ(expected_output_file, output_file.c_str());
+#endif
+}
+
+TEST(OutputFileHelpersTest, GetCurrentExecutableName)
+{
+ const std::string exe_str = GetCurrentExecutableName().string();
+#if GTEST_OS_WINDOWS
+ const bool success =
+ _strcmpi("gtest-options_test", exe_str.c_str()) == 0 ||
+ _strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 ||
+ _strcmpi("gtest_all_test", exe_str.c_str()) == 0 ||
+ _strcmpi("gtest_dll_test", exe_str.c_str()) == 0;
+#else
+ // TODO(wan at google.com): remove the hard-coded "lt-" prefix when
+ // Chandler Carruth's libtool replacement is ready.
+ const bool success =
+ exe_str == "gtest-options_test" ||
+ exe_str == "gtest_all_test" ||
+ exe_str == "lt-gtest_all_test" ||
+ exe_str == "gtest_dll_test";
+#endif // GTEST_OS_WINDOWS
+ if (!success)
+ FAIL() << "GetCurrentExecutableName() returns " << exe_str;
+}
+
+class XmlOutputChangeDirTest : public Test
+{
+ protected:
+ virtual void SetUp() {
+ original_working_dir_ = FilePath::GetCurrentDir();
+ posix::ChDir("..");
+ // This will make the test fail if run from the root directory.
+ EXPECT_NE(original_working_dir_.string(),
+ FilePath::GetCurrentDir().string());
+ }
+
+ virtual void TearDown() {
+ posix::ChDir(original_working_dir_.string().c_str());
+ }
+
+ FilePath original_working_dir_;
+};
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault)
+{
+ GTEST_FLAG(output) = "";
+ EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_,
+ FilePath("test_detail.xml")).string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML)
+{
+ GTEST_FLAG(output) = "xml";
+ EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_,
+ FilePath("test_detail.xml")).string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile)
+{
+ GTEST_FLAG(output) = "xml:filename.abc";
+ EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_,
+ FilePath("filename.abc")).string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath)
+{
+ GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_;
+ const std::string expected_output_file =
+ FilePath::ConcatPaths(
+ original_working_dir_,
+ FilePath(std::string("path") + GTEST_PATH_SEP_ +
+ GetCurrentExecutableName().string() + ".xml")).string();
+ const std::string& output_file =
+ UnitTestOptions::GetAbsolutePathToOutputFile();
+#if GTEST_OS_WINDOWS
+ EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str());
+#else
+ EXPECT_EQ(expected_output_file, output_file.c_str());
+#endif
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsoluteFile)
+{
+#if GTEST_OS_WINDOWS
+ GTEST_FLAG(output) = "xml:c:\\tmp\\filename.abc";
+ EXPECT_EQ(FilePath("c:\\tmp\\filename.abc").string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+#else
+ GTEST_FLAG(output) ="xml:/tmp/filename.abc";
+ EXPECT_EQ(FilePath("/tmp/filename.abc").string(),
+ UnitTestOptions::GetAbsolutePathToOutputFile());
+#endif
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath)
+{
+#if GTEST_OS_WINDOWS
+ const std::string path = "c:\\tmp\\";
+#else
+ const std::string path = "/tmp/";
+#endif
+
+ GTEST_FLAG(output) = "xml:" + path;
+ const std::string expected_output_file =
+ path + GetCurrentExecutableName().string() + ".xml";
+ const std::string& output_file =
+ UnitTestOptions::GetAbsolutePathToOutputFile();
+
+#if GTEST_OS_WINDOWS
+ EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str());
+#else
+ EXPECT_EQ(expected_output_file, output_file.c_str());
+#endif
+}
+
+} // namespace
+} // namespace internal
+} // namespace testing
diff --git a/external/gtest-1.6.0/test/gtest-param-test2_test.cc b/external/gtest-1.6.0/test/gtest-param-test2_test.cc
new file mode 100644
index 0000000..4a782fe
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-param-test2_test.cc
@@ -0,0 +1,65 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+//
+// Tests for Google Test itself. This verifies that the basic constructs of
+// Google Test work.
+
+#include "gtest/gtest.h"
+
+#include "test/gtest-param-test_test.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+using ::testing::Values;
+using ::testing::internal::ParamGenerator;
+
+// Tests that generators defined in a different translation unit
+// are functional. The test using extern_gen is defined
+// in gtest-param-test_test.cc.
+ParamGenerator<int> extern_gen = Values(33);
+
+// Tests that a parameterized test case can be defined in one translation unit
+// and instantiated in another. The test is defined in gtest-param-test_test.cc
+// and ExternalInstantiationTest fixture class is defined in
+// gtest-param-test_test.h.
+INSTANTIATE_TEST_CASE_P(MultiplesOf33,
+ ExternalInstantiationTest,
+ Values(33, 66));
+
+// Tests that a parameterized test case can be instantiated
+// in multiple translation units. Another instantiation is defined
+// in gtest-param-test_test.cc and InstantiationInMultipleTranslaionUnitsTest
+// fixture is defined in gtest-param-test_test.h
+INSTANTIATE_TEST_CASE_P(Sequence2,
+ InstantiationInMultipleTranslaionUnitsTest,
+ Values(42*3, 42*4, 42*5));
+
+#endif // GTEST_HAS_PARAM_TEST
diff --git a/external/gtest-1.6.0/test/gtest-param-test_test.cc b/external/gtest-1.6.0/test/gtest-param-test_test.cc
new file mode 100644
index 0000000..c0b2071
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-param-test_test.cc
@@ -0,0 +1,965 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+//
+// Tests for Google Test itself. This file verifies that the parameter
+// generators objects produce correct parameter sequences and that
+// Google Test runtime instantiates correct tests from those sequences.
+
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+# include <algorithm>
+# include <iostream>
+# include <list>
+# include <sstream>
+# include <string>
+# include <vector>
+
+// To include gtest-internal-inl.h.
+# define GTEST_IMPLEMENTATION_ 1
+# include "src/gtest-internal-inl.h" // for UnitTestOptions
+# undef GTEST_IMPLEMENTATION_
+
+# include "test/gtest-param-test_test.h"
+
+using ::std::vector;
+using ::std::sort;
+
+using ::testing::AddGlobalTestEnvironment;
+using ::testing::Bool;
+using ::testing::Message;
+using ::testing::Range;
+using ::testing::TestWithParam;
+using ::testing::Values;
+using ::testing::ValuesIn;
+
+# if GTEST_HAS_COMBINE
+using ::testing::Combine;
+using ::std::tr1::get;
+using ::std::tr1::make_tuple;
+using ::std::tr1::tuple;
+# endif // GTEST_HAS_COMBINE
+
+using ::testing::internal::ParamGenerator;
+using ::testing::internal::UnitTestOptions;
+
+// Prints a value to a string.
+//
+// TODO(wan at google.com): remove PrintValue() when we move matchers and
+// EXPECT_THAT() from Google Mock to Google Test. At that time, we
+// can write EXPECT_THAT(x, Eq(y)) to compare two tuples x and y, as
+// EXPECT_THAT() and the matchers know how to print tuples.
+template <typename T>
+::std::string PrintValue(const T& value)
+{
+ ::std::stringstream stream;
+ stream << value;
+ return stream.str();
+}
+
+# if GTEST_HAS_COMBINE
+
+// These overloads allow printing tuples in our tests. We cannot
+// define an operator<< for tuples, as that definition needs to be in
+// the std namespace in order to be picked up by Google Test via
+// Argument-Dependent Lookup, yet defining anything in the std
+// namespace in non-STL code is undefined behavior.
+
+template <typename T1, typename T2>
+::std::string PrintValue(const tuple<T1, T2>& value)
+{
+ ::std::stringstream stream;
+ stream << "(" << get<0>(value) << ", " << get<1>(value) << ")";
+ return stream.str();
+}
+
+template <typename T1, typename T2, typename T3>
+::std::string PrintValue(const tuple<T1, T2, T3>& value)
+{
+ ::std::stringstream stream;
+ stream << "(" << get<0>(value) << ", " << get<1>(value)
+ << ", "<< get<2>(value) << ")";
+ return stream.str();
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+::std::string PrintValue(
+ const tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& value)
+{
+ ::std::stringstream stream;
+ stream << "(" << get<0>(value) << ", " << get<1>(value)
+ << ", "<< get<2>(value) << ", " << get<3>(value)
+ << ", "<< get<4>(value) << ", " << get<5>(value)
+ << ", "<< get<6>(value) << ", " << get<7>(value)
+ << ", "<< get<8>(value) << ", " << get<9>(value) << ")";
+ return stream.str();
+}
+
+# endif // GTEST_HAS_COMBINE
+
+// Verifies that a sequence generated by the generator and accessed
+// via the iterator object matches the expected one using Google Test
+// assertions.
+template <typename T, size_t N>
+void VerifyGenerator(const ParamGenerator<T>& generator,
+ const T(&expected_values)[N])
+{
+ typename ParamGenerator<T>::iterator it = generator.begin();
+ for (size_t i = 0; i < N; ++i) {
+ ASSERT_FALSE(it == generator.end())
+ << "At element " << i << " when accessing via an iterator "
+ << "created with the copy constructor.\n";
+ // We cannot use EXPECT_EQ() here as the values may be tuples,
+ // which don't support <<.
+ EXPECT_TRUE(expected_values[i] == *it)
+ << "where i is " << i
+ << ", expected_values[i] is " << PrintValue(expected_values[i])
+ << ", *it is " << PrintValue(*it)
+ << ", and 'it' is an iterator created with the copy constructor.\n";
+ it++;
+ }
+ EXPECT_TRUE(it == generator.end())
+ << "At the presumed end of sequence when accessing via an iterator "
+ << "created with the copy constructor.\n";
+
+ // Test the iterator assignment. The following lines verify that
+ // the sequence accessed via an iterator initialized via the
+ // assignment operator (as opposed to a copy constructor) matches
+ // just the same.
+ it = generator.begin();
+ for (size_t i = 0; i < N; ++i) {
+ ASSERT_FALSE(it == generator.end())
+ << "At element " << i << " when accessing via an iterator "
+ << "created with the assignment operator.\n";
+ EXPECT_TRUE(expected_values[i] == *it)
+ << "where i is " << i
+ << ", expected_values[i] is " << PrintValue(expected_values[i])
+ << ", *it is " << PrintValue(*it)
+ << ", and 'it' is an iterator created with the copy constructor.\n";
+ it++;
+ }
+ EXPECT_TRUE(it == generator.end())
+ << "At the presumed end of sequence when accessing via an iterator "
+ << "created with the assignment operator.\n";
+}
+
+template <typename T>
+void VerifyGeneratorIsEmpty(const ParamGenerator<T>& generator)
+{
+ typename ParamGenerator<T>::iterator it = generator.begin();
+ EXPECT_TRUE(it == generator.end());
+
+ it = generator.begin();
+ EXPECT_TRUE(it == generator.end());
+}
+
+// Generator tests. They test that each of the provided generator functions
+// generates an expected sequence of values. The general test pattern
+// instantiates a generator using one of the generator functions,
+// checks the sequence produced by the generator using its iterator API,
+// and then resets the iterator back to the beginning of the sequence
+// and checks the sequence again.
+
+// Tests that iterators produced by generator functions conform to the
+// ForwardIterator concept.
+TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept)
+{
+ const ParamGenerator<int> gen = Range(0, 10);
+ ParamGenerator<int>::iterator it = gen.begin();
+
+ // Verifies that iterator initialization works as expected.
+ ParamGenerator<int>::iterator it2 = it;
+ EXPECT_TRUE(*it == *it2) << "Initialized iterators must point to the "
+ << "element same as its source points to";
+
+ // Verifies that iterator assignment works as expected.
+ it++;
+ EXPECT_FALSE(*it == *it2);
+ it2 = it;
+ EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the "
+ << "element same as its source points to";
+
+ // Verifies that prefix operator++() returns *this.
+ EXPECT_EQ(&it, &(++it)) << "Result of the prefix operator++ must be "
+ << "refer to the original object";
+
+ // Verifies that the result of the postfix operator++ points to the value
+ // pointed to by the original iterator.
+ int original_value = *it; // Have to compute it outside of macro call to be
+ // unaffected by the parameter evaluation order.
+ EXPECT_EQ(original_value, *(it++));
+
+ // Verifies that prefix and postfix operator++() advance an iterator
+ // all the same.
+ it2 = it;
+ it++;
+ ++it2;
+ EXPECT_TRUE(*it == *it2);
+}
+
+// Tests that Range() generates the expected sequence.
+TEST(RangeTest, IntRangeWithDefaultStep)
+{
+ const ParamGenerator<int> gen = Range(0, 3);
+ const int expected_values[] = {0, 1, 2};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that Range() generates the single element sequence
+// as expected when provided with range limits that are equal.
+TEST(RangeTest, IntRangeSingleValue)
+{
+ const ParamGenerator<int> gen = Range(0, 1);
+ const int expected_values[] = {0};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that Range() with generates empty sequence when
+// supplied with an empty range.
+TEST(RangeTest, IntRangeEmpty)
+{
+ const ParamGenerator<int> gen = Range(0, 0);
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Tests that Range() with custom step (greater then one) generates
+// the expected sequence.
+TEST(RangeTest, IntRangeWithCustomStep)
+{
+ const ParamGenerator<int> gen = Range(0, 9, 3);
+ const int expected_values[] = {0, 3, 6};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Range() with custom step (greater then one) generates
+// the expected sequence when the last element does not fall on the
+// upper range limit. Sequences generated by Range() must not have
+// elements beyond the range limits.
+TEST(RangeTest, IntRangeWithCustomStepOverUpperBound)
+{
+ const ParamGenerator<int> gen = Range(0, 4, 3);
+ const int expected_values[] = {0, 3};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Verifies that Range works with user-defined types that define
+// copy constructor, operator=(), operator+(), and operator<().
+class DogAdder
+{
+ public:
+ explicit DogAdder(const char* a_value) : value_(a_value) {}
+ DogAdder(const DogAdder& other) : value_(other.value_.c_str()) {}
+
+ DogAdder operator=(const DogAdder& other) {
+ if (this != &other)
+ value_ = other.value_;
+ return *this;
+ }
+ DogAdder operator+(const DogAdder& other) const {
+ Message msg;
+ msg << value_.c_str() << other.value_.c_str();
+ return DogAdder(msg.GetString().c_str());
+ }
+ bool operator<(const DogAdder& other) const {
+ return value_ < other.value_;
+ }
+ const std::string& value() const { return value_; }
+
+ private:
+ std::string value_;
+};
+
+TEST(RangeTest, WorksWithACustomType)
+{
+ const ParamGenerator<DogAdder> gen =
+ Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog"));
+ ParamGenerator<DogAdder>::iterator it = gen.begin();
+
+ ASSERT_FALSE(it == gen.end());
+ EXPECT_STREQ("cat", it->value().c_str());
+
+ ASSERT_FALSE(++it == gen.end());
+ EXPECT_STREQ("catdog", it->value().c_str());
+
+ EXPECT_TRUE(++it == gen.end());
+}
+
+class IntWrapper
+{
+ public:
+ explicit IntWrapper(int a_value) : value_(a_value) {}
+ IntWrapper(const IntWrapper& other) : value_(other.value_) {}
+
+ IntWrapper operator=(const IntWrapper& other) {
+ value_ = other.value_;
+ return *this;
+ }
+ // operator+() adds a different type.
+ IntWrapper operator+(int other) const { return IntWrapper(value_ + other); }
+ bool operator<(const IntWrapper& other) const {
+ return value_ < other.value_;
+ }
+ int value() const { return value_; }
+
+ private:
+ int value_;
+};
+
+TEST(RangeTest, WorksWithACustomTypeWithDifferentIncrementType)
+{
+ const ParamGenerator<IntWrapper> gen = Range(IntWrapper(0), IntWrapper(2));
+ ParamGenerator<IntWrapper>::iterator it = gen.begin();
+
+ ASSERT_FALSE(it == gen.end());
+ EXPECT_EQ(0, it->value());
+
+ ASSERT_FALSE(++it == gen.end());
+ EXPECT_EQ(1, it->value());
+
+ EXPECT_TRUE(++it == gen.end());
+}
+
+// Tests that ValuesIn() with an array parameter generates
+// the expected sequence.
+TEST(ValuesInTest, ValuesInArray)
+{
+ int array[] = {3, 5, 8};
+ const ParamGenerator<int> gen = ValuesIn(array);
+ VerifyGenerator(gen, array);
+}
+
+// Tests that ValuesIn() with a const array parameter generates
+// the expected sequence.
+TEST(ValuesInTest, ValuesInConstArray)
+{
+ const int array[] = {3, 5, 8};
+ const ParamGenerator<int> gen = ValuesIn(array);
+ VerifyGenerator(gen, array);
+}
+
+// Edge case. Tests that ValuesIn() with an array parameter containing a
+// single element generates the single element sequence.
+TEST(ValuesInTest, ValuesInSingleElementArray)
+{
+ int array[] = {42};
+ const ParamGenerator<int> gen = ValuesIn(array);
+ VerifyGenerator(gen, array);
+}
+
+// Tests that ValuesIn() generates the expected sequence for an STL
+// container (vector).
+TEST(ValuesInTest, ValuesInVector)
+{
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ values.push_back(3);
+ values.push_back(5);
+ values.push_back(8);
+ const ParamGenerator<int> gen = ValuesIn(values);
+
+ const int expected_values[] = {3, 5, 8};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that ValuesIn() generates the expected sequence.
+TEST(ValuesInTest, ValuesInIteratorRange)
+{
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ values.push_back(3);
+ values.push_back(5);
+ values.push_back(8);
+ const ParamGenerator<int> gen = ValuesIn(values.begin(), values.end());
+
+ const int expected_values[] = {3, 5, 8};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that ValuesIn() provided with an iterator range specifying a
+// single value generates a single-element sequence.
+TEST(ValuesInTest, ValuesInSingleElementIteratorRange)
+{
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ values.push_back(42);
+ const ParamGenerator<int> gen = ValuesIn(values.begin(), values.end());
+
+ const int expected_values[] = {42};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that ValuesIn() provided with an empty iterator range
+// generates an empty sequence.
+TEST(ValuesInTest, ValuesInEmptyIteratorRange)
+{
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ const ParamGenerator<int> gen = ValuesIn(values.begin(), values.end());
+
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Tests that the Values() generates the expected sequence.
+TEST(ValuesTest, ValuesWorks)
+{
+ const ParamGenerator<int> gen = Values(3, 5, 8);
+
+ const int expected_values[] = {3, 5, 8};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Values() generates the expected sequences from elements of
+// different types convertible to ParamGenerator's parameter type.
+TEST(ValuesTest, ValuesWorksForValuesOfCompatibleTypes)
+{
+ const ParamGenerator<double> gen = Values(3, 5.0f, 8.0);
+
+ const double expected_values[] = {3.0, 5.0, 8.0};
+ VerifyGenerator(gen, expected_values);
+}
+
+TEST(ValuesTest, ValuesWorksForMaxLengthList)
+{
+ const ParamGenerator<int> gen = Values(
+ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
+ 110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
+ 210, 220, 230, 240, 250, 260, 270, 280, 290, 300,
+ 310, 320, 330, 340, 350, 360, 370, 380, 390, 400,
+ 410, 420, 430, 440, 450, 460, 470, 480, 490, 500);
+
+ const int expected_values[] = {
+ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
+ 110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
+ 210, 220, 230, 240, 250, 260, 270, 280, 290, 300,
+ 310, 320, 330, 340, 350, 360, 370, 380, 390, 400,
+ 410, 420, 430, 440, 450, 460, 470, 480, 490, 500
+ };
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case test. Tests that single-parameter Values() generates the sequence
+// with the single value.
+TEST(ValuesTest, ValuesWithSingleParameter)
+{
+ const ParamGenerator<int> gen = Values(42);
+
+ const int expected_values[] = {42};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Bool() generates sequence (false, true).
+TEST(BoolTest, BoolWorks)
+{
+ const ParamGenerator<bool> gen = Bool();
+
+ const bool expected_values[] = {false, true};
+ VerifyGenerator(gen, expected_values);
+}
+
+# if GTEST_HAS_COMBINE
+
+// Tests that Combine() with two parameters generates the expected sequence.
+TEST(CombineTest, CombineWithTwoParameters)
+{
+ const char* foo = "foo";
+ const char* bar = "bar";
+ const ParamGenerator<tuple<const char*, int> > gen =
+ Combine(Values(foo, bar), Values(3, 4));
+
+ tuple<const char*, int> expected_values[] = {
+ make_tuple(foo, 3), make_tuple(foo, 4),
+ make_tuple(bar, 3), make_tuple(bar, 4)
+ };
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Combine() with three parameters generates the expected sequence.
+TEST(CombineTest, CombineWithThreeParameters)
+{
+ const ParamGenerator<tuple<int, int, int> > gen = Combine(Values(0, 1),
+ Values(3, 4),
+ Values(5, 6));
+ tuple<int, int, int> expected_values[] = {
+ make_tuple(0, 3, 5), make_tuple(0, 3, 6),
+ make_tuple(0, 4, 5), make_tuple(0, 4, 6),
+ make_tuple(1, 3, 5), make_tuple(1, 3, 6),
+ make_tuple(1, 4, 5), make_tuple(1, 4, 6)
+ };
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that the Combine() with the first parameter generating a single value
+// sequence generates a sequence with the number of elements equal to the
+// number of elements in the sequence generated by the second parameter.
+TEST(CombineTest, CombineWithFirstParameterSingleValue)
+{
+ const ParamGenerator<tuple<int, int> > gen = Combine(Values(42),
+ Values(0, 1));
+
+ tuple<int, int> expected_values[] = {make_tuple(42, 0), make_tuple(42, 1)};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that the Combine() with the second parameter generating a single value
+// sequence generates a sequence with the number of elements equal to the
+// number of elements in the sequence generated by the first parameter.
+TEST(CombineTest, CombineWithSecondParameterSingleValue)
+{
+ const ParamGenerator<tuple<int, int> > gen = Combine(Values(0, 1),
+ Values(42));
+
+ tuple<int, int> expected_values[] = {make_tuple(0, 42), make_tuple(1, 42)};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that when the first parameter produces an empty sequence,
+// Combine() produces an empty sequence, too.
+TEST(CombineTest, CombineWithFirstParameterEmptyRange)
+{
+ const ParamGenerator<tuple<int, int> > gen = Combine(Range(0, 0),
+ Values(0, 1));
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Tests that when the second parameter produces an empty sequence,
+// Combine() produces an empty sequence, too.
+TEST(CombineTest, CombineWithSecondParameterEmptyRange)
+{
+ const ParamGenerator<tuple<int, int> > gen = Combine(Values(0, 1),
+ Range(1, 1));
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Edge case. Tests that combine works with the maximum number
+// of parameters supported by Google Test (currently 10).
+TEST(CombineTest, CombineWithMaxNumberOfParameters)
+{
+ const char* foo = "foo";
+ const char* bar = "bar";
+ const ParamGenerator<tuple<const char*, int, int, int, int, int, int, int,
+ int, int> > gen = Combine(Values(foo, bar),
+ Values(1), Values(2),
+ Values(3), Values(4),
+ Values(5), Values(6),
+ Values(7), Values(8),
+ Values(9));
+
+ tuple<const char*, int, int, int, int, int, int, int, int, int>
+ expected_values[] = {make_tuple(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9),
+ make_tuple(bar, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ };
+ VerifyGenerator(gen, expected_values);
+}
+
+# endif // GTEST_HAS_COMBINE
+
+// Tests that an generator produces correct sequence after being
+// assigned from another generator.
+TEST(ParamGeneratorTest, AssignmentWorks)
+{
+ ParamGenerator<int> gen = Values(1, 2);
+ const ParamGenerator<int> gen2 = Values(3, 4);
+ gen = gen2;
+
+ const int expected_values[] = {3, 4};
+ VerifyGenerator(gen, expected_values);
+}
+
+// This test verifies that the tests are expanded and run as specified:
+// one test per element from the sequence produced by the generator
+// specified in INSTANTIATE_TEST_CASE_P. It also verifies that the test's
+// fixture constructor, SetUp(), and TearDown() have run and have been
+// supplied with the correct parameters.
+
+// The use of environment object allows detection of the case where no test
+// case functionality is run at all. In this case TestCaseTearDown will not
+// be able to detect missing tests, naturally.
+template <int kExpectedCalls>
+class TestGenerationEnvironment : public ::testing::Environment
+{
+ public:
+ static TestGenerationEnvironment* Instance() {
+ static TestGenerationEnvironment* instance = new TestGenerationEnvironment;
+ return instance;
+ }
+
+ void FixtureConstructorExecuted() { fixture_constructor_count_++; }
+ void SetUpExecuted() { set_up_count_++; }
+ void TearDownExecuted() { tear_down_count_++; }
+ void TestBodyExecuted() { test_body_count_++; }
+
+ virtual void TearDown() {
+ // If all MultipleTestGenerationTest tests have been de-selected
+ // by the filter flag, the following checks make no sense.
+ bool perform_check = false;
+
+ for (int i = 0; i < kExpectedCalls; ++i) {
+ Message msg;
+ msg << "TestsExpandedAndRun/" << i;
+ if (UnitTestOptions::FilterMatchesTest(
+ "TestExpansionModule/MultipleTestGenerationTest",
+ msg.GetString().c_str())) {
+ perform_check = true;
+ }
+ }
+ if (perform_check) {
+ EXPECT_EQ(kExpectedCalls, fixture_constructor_count_)
+ << "Fixture constructor of ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ EXPECT_EQ(kExpectedCalls, set_up_count_)
+ << "Fixture SetUp method of ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ EXPECT_EQ(kExpectedCalls, tear_down_count_)
+ << "Fixture TearDown method of ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ EXPECT_EQ(kExpectedCalls, test_body_count_)
+ << "Test in ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ }
+ }
+
+ private:
+ TestGenerationEnvironment() : fixture_constructor_count_(0), set_up_count_(0),
+ tear_down_count_(0), test_body_count_(0) {}
+
+ int fixture_constructor_count_;
+ int set_up_count_;
+ int tear_down_count_;
+ int test_body_count_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationEnvironment);
+};
+
+const int test_generation_params[] = {36, 42, 72};
+
+class TestGenerationTest : public TestWithParam<int>
+{
+ public:
+ enum {
+ PARAMETER_COUNT =
+ sizeof(test_generation_params)/sizeof(test_generation_params[0])
+ };
+
+ typedef TestGenerationEnvironment<PARAMETER_COUNT> Environment;
+
+ TestGenerationTest() {
+ Environment::Instance()->FixtureConstructorExecuted();
+ current_parameter_ = GetParam();
+ }
+ virtual void SetUp() {
+ Environment::Instance()->SetUpExecuted();
+ EXPECT_EQ(current_parameter_, GetParam());
+ }
+ virtual void TearDown() {
+ Environment::Instance()->TearDownExecuted();
+ EXPECT_EQ(current_parameter_, GetParam());
+ }
+
+ static void SetUpTestCase() {
+ bool all_tests_in_test_case_selected = true;
+
+ for (int i = 0; i < PARAMETER_COUNT; ++i) {
+ Message test_name;
+ test_name << "TestsExpandedAndRun/" << i;
+ if (!UnitTestOptions::FilterMatchesTest(
+ "TestExpansionModule/MultipleTestGenerationTest",
+ test_name.GetString())) {
+ all_tests_in_test_case_selected = false;
+ }
+ }
+ EXPECT_TRUE(all_tests_in_test_case_selected)
+ << "When running the TestGenerationTest test case all of its tests\n"
+ << "must be selected by the filter flag for the test case to pass.\n"
+ << "If not all of them are enabled, we can't reliably conclude\n"
+ << "that the correct number of tests have been generated.";
+
+ collected_parameters_.clear();
+ }
+
+ static void TearDownTestCase() {
+ vector<int> expected_values(test_generation_params,
+ test_generation_params + PARAMETER_COUNT);
+ // Test execution order is not guaranteed by Google Test,
+ // so the order of values in collected_parameters_ can be
+ // different and we have to sort to compare.
+ sort(expected_values.begin(), expected_values.end());
+ sort(collected_parameters_.begin(), collected_parameters_.end());
+
+ EXPECT_TRUE(collected_parameters_ == expected_values);
+ }
+
+ protected:
+ int current_parameter_;
+ static vector<int> collected_parameters_;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest);
+};
+vector<int> TestGenerationTest::collected_parameters_;
+
+TEST_P(TestGenerationTest, TestsExpandedAndRun)
+{
+ Environment::Instance()->TestBodyExecuted();
+ EXPECT_EQ(current_parameter_, GetParam());
+ collected_parameters_.push_back(GetParam());
+}
+INSTANTIATE_TEST_CASE_P(TestExpansionModule, TestGenerationTest,
+ ValuesIn(test_generation_params));
+
+// This test verifies that the element sequence (third parameter of
+// INSTANTIATE_TEST_CASE_P) is evaluated in InitGoogleTest() and neither at
+// the call site of INSTANTIATE_TEST_CASE_P nor in RUN_ALL_TESTS(). For
+// that, we declare param_value_ to be a static member of
+// GeneratorEvaluationTest and initialize it to 0. We set it to 1 in
+// main(), just before invocation of InitGoogleTest(). After calling
+// InitGoogleTest(), we set the value to 2. If the sequence is evaluated
+// before or after InitGoogleTest, INSTANTIATE_TEST_CASE_P will create a
+// test with parameter other than 1, and the test body will fail the
+// assertion.
+class GeneratorEvaluationTest : public TestWithParam<int>
+{
+ public:
+ static int param_value() { return param_value_; }
+ static void set_param_value(int param_value) { param_value_ = param_value; }
+
+ private:
+ static int param_value_;
+};
+int GeneratorEvaluationTest::param_value_ = 0;
+
+TEST_P(GeneratorEvaluationTest, GeneratorsEvaluatedInMain)
+{
+ EXPECT_EQ(1, GetParam());
+}
+INSTANTIATE_TEST_CASE_P(GenEvalModule,
+ GeneratorEvaluationTest,
+ Values(GeneratorEvaluationTest::param_value()));
+
+// Tests that generators defined in a different translation unit are
+// functional. Generator extern_gen is defined in gtest-param-test_test2.cc.
+extern ParamGenerator<int> extern_gen;
+class ExternalGeneratorTest : public TestWithParam<int> {};
+TEST_P(ExternalGeneratorTest, ExternalGenerator)
+{
+ // Sequence produced by extern_gen contains only a single value
+ // which we verify here.
+ EXPECT_EQ(GetParam(), 33);
+}
+INSTANTIATE_TEST_CASE_P(ExternalGeneratorModule,
+ ExternalGeneratorTest,
+ extern_gen);
+
+// Tests that a parameterized test case can be defined in one translation
+// unit and instantiated in another. This test will be instantiated in
+// gtest-param-test_test2.cc. ExternalInstantiationTest fixture class is
+// defined in gtest-param-test_test.h.
+TEST_P(ExternalInstantiationTest, IsMultipleOf33)
+{
+ EXPECT_EQ(0, GetParam() % 33);
+}
+
+// Tests that a parameterized test case can be instantiated with multiple
+// generators.
+class MultipleInstantiationTest : public TestWithParam<int> {};
+TEST_P(MultipleInstantiationTest, AllowsMultipleInstances)
+{
+}
+INSTANTIATE_TEST_CASE_P(Sequence1, MultipleInstantiationTest, Values(1, 2));
+INSTANTIATE_TEST_CASE_P(Sequence2, MultipleInstantiationTest, Range(3, 5));
+
+// Tests that a parameterized test case can be instantiated
+// in multiple translation units. This test will be instantiated
+// here and in gtest-param-test_test2.cc.
+// InstantiationInMultipleTranslationUnitsTest fixture class
+// is defined in gtest-param-test_test.h.
+TEST_P(InstantiationInMultipleTranslaionUnitsTest, IsMultipleOf42)
+{
+ EXPECT_EQ(0, GetParam() % 42);
+}
+INSTANTIATE_TEST_CASE_P(Sequence1,
+ InstantiationInMultipleTranslaionUnitsTest,
+ Values(42, 42*2));
+
+// Tests that each iteration of parameterized test runs in a separate test
+// object.
+class SeparateInstanceTest : public TestWithParam<int>
+{
+ public:
+ SeparateInstanceTest() : count_(0) {}
+
+ static void TearDownTestCase() {
+ EXPECT_GE(global_count_, 2)
+ << "If some (but not all) SeparateInstanceTest tests have been "
+ << "filtered out this test will fail. Make sure that all "
+ << "GeneratorEvaluationTest are selected or de-selected together "
+ << "by the test filter.";
+ }
+
+ protected:
+ int count_;
+ static int global_count_;
+};
+int SeparateInstanceTest::global_count_ = 0;
+
+TEST_P(SeparateInstanceTest, TestsRunInSeparateInstances)
+{
+ EXPECT_EQ(0, count_++);
+ global_count_++;
+}
+INSTANTIATE_TEST_CASE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4));
+
+// Tests that all instantiations of a test have named appropriately. Test
+// defined with TEST_P(TestCaseName, TestName) and instantiated with
+// INSTANTIATE_TEST_CASE_P(SequenceName, TestCaseName, generator) must be named
+// SequenceName/TestCaseName.TestName/i, where i is the 0-based index of the
+// sequence element used to instantiate the test.
+class NamingTest : public TestWithParam<int> {};
+
+TEST_P(NamingTest, TestsReportCorrectNamesAndParameters)
+{
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name());
+
+ Message index_stream;
+ index_stream << "TestsReportCorrectNamesAndParameters/" << GetParam();
+ EXPECT_STREQ(index_stream.GetString().c_str(), test_info->name());
+
+ EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param());
+}
+
+INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5));
+
+// Class that cannot be streamed into an ostream. It needs to be copyable
+// (and, in case of MSVC, also assignable) in order to be a test parameter
+// type. Its default copy constructor and assignment operator do exactly
+// what we need.
+class Unstreamable
+{
+ public:
+ explicit Unstreamable(int value) : value_(value) {}
+
+ private:
+ int value_;
+};
+
+class CommentTest : public TestWithParam<Unstreamable> {};
+
+TEST_P(CommentTest, TestsCorrectlyReportUnstreamableParams)
+{
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param());
+}
+
+INSTANTIATE_TEST_CASE_P(InstantiationWithComments,
+ CommentTest,
+ Values(Unstreamable(1)));
+
+// Verify that we can create a hierarchy of test fixtures, where the base
+// class fixture is not parameterized and the derived class is. In this case
+// ParameterizedDerivedTest inherits from NonParameterizedBaseTest. We
+// perform simple tests on both.
+class NonParameterizedBaseTest : public ::testing::Test
+{
+ public:
+ NonParameterizedBaseTest() : n_(17) { }
+ protected:
+ int n_;
+};
+
+class ParameterizedDerivedTest : public NonParameterizedBaseTest,
+ public ::testing::WithParamInterface<int>
+{
+ protected:
+ ParameterizedDerivedTest() : count_(0) { }
+ int count_;
+ static int global_count_;
+};
+
+int ParameterizedDerivedTest::global_count_ = 0;
+
+TEST_F(NonParameterizedBaseTest, FixtureIsInitialized)
+{
+ EXPECT_EQ(17, n_);
+}
+
+TEST_P(ParameterizedDerivedTest, SeesSequence)
+{
+ EXPECT_EQ(17, n_);
+ EXPECT_EQ(0, count_++);
+ EXPECT_EQ(GetParam(), global_count_++);
+}
+
+class ParameterizedDeathTest : public ::testing::TestWithParam<int> { };
+
+TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF)
+{
+ EXPECT_DEATH_IF_SUPPORTED(GetParam(),
+ ".* value-parameterized test .*");
+}
+
+INSTANTIATE_TEST_CASE_P(RangeZeroToFive, ParameterizedDerivedTest, Range(0, 5));
+
+#endif // GTEST_HAS_PARAM_TEST
+
+TEST(CompileTest, CombineIsDefinedOnlyWhenGtestHasParamTestIsDefined)
+{
+#if GTEST_HAS_COMBINE && !GTEST_HAS_PARAM_TEST
+ FAIL() << "GTEST_HAS_COMBINE is defined while GTEST_HAS_PARAM_TEST is not\n"
+#endif
+}
+
+int main(int argc, char** argv)
+{
+#if GTEST_HAS_PARAM_TEST
+ // Used in TestGenerationTest test case.
+ AddGlobalTestEnvironment(TestGenerationTest::Environment::Instance());
+ // Used in GeneratorEvaluationTest test case. Tests that the updated value
+ // will be picked up for instantiating tests in GeneratorEvaluationTest.
+ GeneratorEvaluationTest::set_param_value(1);
+#endif // GTEST_HAS_PARAM_TEST
+
+ ::testing::InitGoogleTest(&argc, argv);
+
+#if GTEST_HAS_PARAM_TEST
+ // Used in GeneratorEvaluationTest test case. Tests that value updated
+ // here will NOT be used for instantiating tests in
+ // GeneratorEvaluationTest.
+ GeneratorEvaluationTest::set_param_value(2);
+#endif // GTEST_HAS_PARAM_TEST
+
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest-param-test_test.h b/external/gtest-1.6.0/test/gtest-param-test_test.h
new file mode 100644
index 0000000..5942e1f
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-param-test_test.h
@@ -0,0 +1,59 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl at google.com (Vlad Losev)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file provides classes and functions used internally
+// for testing Google Test itself.
+
+#ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_
+#define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_
+
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+// Test fixture for testing definition and instantiation of a test
+// in separate translation units.
+class ExternalInstantiationTest : public ::testing::TestWithParam<int>
+{
+};
+
+// Test fixture for testing instantiation of a test in multiple
+// translation units.
+class InstantiationInMultipleTranslaionUnitsTest
+ : public ::testing::TestWithParam<int>
+{
+};
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_
diff --git a/external/gtest-1.6.0/test/gtest-port_test.cc b/external/gtest-1.6.0/test/gtest-port_test.cc
new file mode 100644
index 0000000..3861017
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-port_test.cc
@@ -0,0 +1,1370 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl at google.com (Vlad Losev), wan at google.com (Zhanyong Wan)
+//
+// This file tests the internal cross-platform support utilities.
+
+#include "gtest/internal/gtest-port.h"
+
+#include <stdio.h>
+
+#if GTEST_OS_MAC
+# include <time.h>
+#endif // GTEST_OS_MAC
+
+#include <list>
+#include <utility> // For std::pair and std::make_pair.
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "gtest/gtest-spi.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+using std::make_pair;
+using std::pair;
+
+namespace testing
+{
+namespace internal
+{
+
+TEST(IsXDigitTest, WorksForNarrowAscii)
+{
+ EXPECT_TRUE(IsXDigit('0'));
+ EXPECT_TRUE(IsXDigit('9'));
+ EXPECT_TRUE(IsXDigit('A'));
+ EXPECT_TRUE(IsXDigit('F'));
+ EXPECT_TRUE(IsXDigit('a'));
+ EXPECT_TRUE(IsXDigit('f'));
+
+ EXPECT_FALSE(IsXDigit('-'));
+ EXPECT_FALSE(IsXDigit('g'));
+ EXPECT_FALSE(IsXDigit('G'));
+}
+
+TEST(IsXDigitTest, ReturnsFalseForNarrowNonAscii)
+{
+ EXPECT_FALSE(IsXDigit(static_cast<char>(0x80)));
+ EXPECT_FALSE(IsXDigit(static_cast<char>('0' | 0x80)));
+}
+
+TEST(IsXDigitTest, WorksForWideAscii)
+{
+ EXPECT_TRUE(IsXDigit(L'0'));
+ EXPECT_TRUE(IsXDigit(L'9'));
+ EXPECT_TRUE(IsXDigit(L'A'));
+ EXPECT_TRUE(IsXDigit(L'F'));
+ EXPECT_TRUE(IsXDigit(L'a'));
+ EXPECT_TRUE(IsXDigit(L'f'));
+
+ EXPECT_FALSE(IsXDigit(L'-'));
+ EXPECT_FALSE(IsXDigit(L'g'));
+ EXPECT_FALSE(IsXDigit(L'G'));
+}
+
+TEST(IsXDigitTest, ReturnsFalseForWideNonAscii)
+{
+ EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(0x80)));
+ EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(L'0' | 0x80)));
+ EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(L'0' | 0x100)));
+}
+
+class Base
+{
+ public:
+ // Copy constructor and assignment operator do exactly what we need, so we
+ // use them.
+ Base() : member_(0) {}
+ explicit Base(int n) : member_(n) {}
+ virtual ~Base() {}
+ int member() { return member_; }
+
+ private:
+ int member_;
+};
+
+class Derived : public Base
+{
+ public:
+ explicit Derived(int n) : Base(n) {}
+};
+
+TEST(ImplicitCastTest, ConvertsPointers)
+{
+ Derived derived(0);
+ EXPECT_TRUE(&derived == ::testing::internal::ImplicitCast_<Base*>(&derived));
+}
+
+TEST(ImplicitCastTest, CanUseInheritance)
+{
+ Derived derived(1);
+ Base base = ::testing::internal::ImplicitCast_<Base>(derived);
+ EXPECT_EQ(derived.member(), base.member());
+}
+
+class Castable
+{
+ public:
+ explicit Castable(bool* converted) : converted_(converted) {}
+ operator Base() {
+ *converted_ = true;
+ return Base();
+ }
+
+ private:
+ bool* converted_;
+};
+
+TEST(ImplicitCastTest, CanUseNonConstCastOperator)
+{
+ bool converted = false;
+ Castable castable(&converted);
+ Base base = ::testing::internal::ImplicitCast_<Base>(castable);
+ EXPECT_TRUE(converted);
+}
+
+class ConstCastable
+{
+ public:
+ explicit ConstCastable(bool* converted) : converted_(converted) {}
+ operator Base() const {
+ *converted_ = true;
+ return Base();
+ }
+
+ private:
+ bool* converted_;
+};
+
+TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues)
+{
+ bool converted = false;
+ const ConstCastable const_castable(&converted);
+ Base base = ::testing::internal::ImplicitCast_<Base>(const_castable);
+ EXPECT_TRUE(converted);
+}
+
+class ConstAndNonConstCastable
+{
+ public:
+ ConstAndNonConstCastable(bool* converted, bool* const_converted)
+ : converted_(converted), const_converted_(const_converted) {}
+ operator Base() {
+ *converted_ = true;
+ return Base();
+ }
+ operator Base() const {
+ *const_converted_ = true;
+ return Base();
+ }
+
+ private:
+ bool* converted_;
+ bool* const_converted_;
+};
+
+TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately)
+{
+ bool converted = false;
+ bool const_converted = false;
+ ConstAndNonConstCastable castable(&converted, &const_converted);
+ Base base = ::testing::internal::ImplicitCast_<Base>(castable);
+ EXPECT_TRUE(converted);
+ EXPECT_FALSE(const_converted);
+
+ converted = false;
+ const_converted = false;
+ const ConstAndNonConstCastable const_castable(&converted, &const_converted);
+ base = ::testing::internal::ImplicitCast_<Base>(const_castable);
+ EXPECT_FALSE(converted);
+ EXPECT_TRUE(const_converted);
+}
+
+class To
+{
+ public:
+ To(bool* converted) { *converted = true; } // NOLINT
+};
+
+TEST(ImplicitCastTest, CanUseImplicitConstructor)
+{
+ bool converted = false;
+ To to = ::testing::internal::ImplicitCast_<To>(&converted);
+ (void)to;
+ EXPECT_TRUE(converted);
+}
+
+TEST(IteratorTraitsTest, WorksForSTLContainerIterators)
+{
+ StaticAssertTypeEq<int,
+ IteratorTraits< ::std::vector<int>::const_iterator>::value_type>();
+ StaticAssertTypeEq<bool,
+ IteratorTraits< ::std::list<bool>::iterator>::value_type>();
+}
+
+TEST(IteratorTraitsTest, WorksForPointerToNonConst)
+{
+ StaticAssertTypeEq<char, IteratorTraits<char*>::value_type>();
+ StaticAssertTypeEq<const void*, IteratorTraits<const void**>::value_type>();
+}
+
+TEST(IteratorTraitsTest, WorksForPointerToConst)
+{
+ StaticAssertTypeEq<char, IteratorTraits<const char*>::value_type>();
+ StaticAssertTypeEq<const void*,
+ IteratorTraits<const void* const*>::value_type>();
+}
+
+// Tests that the element_type typedef is available in scoped_ptr and refers
+// to the parameter type.
+TEST(ScopedPtrTest, DefinesElementType)
+{
+ StaticAssertTypeEq<int, ::testing::internal::scoped_ptr<int>::element_type>();
+}
+
+// TODO(vladl at google.com): Implement THE REST of scoped_ptr tests.
+
+TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement)
+{
+ if (AlwaysFalse())
+ GTEST_CHECK_(false) << "This should never be executed; "
+ "It's a compilation test only.";
+
+ if (AlwaysTrue())
+ GTEST_CHECK_(true);
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ GTEST_CHECK_(true) << "";
+}
+
+TEST(GtestCheckSyntaxTest, WorksWithSwitch)
+{
+ switch (0) {
+ case 1:
+ break;
+ default:
+ GTEST_CHECK_(true);
+ }
+
+ switch (0)
+ case 0:
+ GTEST_CHECK_(true) << "Check failed in switch case";
+}
+
+// Verifies behavior of FormatFileLocation.
+TEST(FormatFileLocationTest, FormatsFileLocation)
+{
+ EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42));
+ EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42));
+}
+
+TEST(FormatFileLocationTest, FormatsUnknownFile)
+{
+ EXPECT_PRED_FORMAT2(
+ IsSubstring, "unknown file", FormatFileLocation(NULL, 42));
+ EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation(NULL, 42));
+}
+
+TEST(FormatFileLocationTest, FormatsUknownLine)
+{
+ EXPECT_EQ("foo.cc:", FormatFileLocation("foo.cc", -1));
+}
+
+TEST(FormatFileLocationTest, FormatsUknownFileAndLine)
+{
+ EXPECT_EQ("unknown file:", FormatFileLocation(NULL, -1));
+}
+
+// Verifies behavior of FormatCompilerIndependentFileLocation.
+TEST(FormatCompilerIndependentFileLocationTest, FormatsFileLocation)
+{
+ EXPECT_EQ("foo.cc:42", FormatCompilerIndependentFileLocation("foo.cc", 42));
+}
+
+TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFile)
+{
+ EXPECT_EQ("unknown file:42",
+ FormatCompilerIndependentFileLocation(NULL, 42));
+}
+
+TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine)
+{
+ EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1));
+}
+
+TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine)
+{
+ EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1));
+}
+
+#if GTEST_OS_MAC || GTEST_OS_QNX
+void* ThreadFunc(void* data)
+{
+ pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data);
+ pthread_mutex_lock(mutex);
+ pthread_mutex_unlock(mutex);
+ return NULL;
+}
+
+TEST(GetThreadCountTest, ReturnsCorrectValue)
+{
+ EXPECT_EQ(1U, GetThreadCount());
+ pthread_mutex_t mutex;
+ pthread_attr_t attr;
+ pthread_t thread_id;
+
+ // TODO(vladl at google.com): turn mutex into internal::Mutex for automatic
+ // destruction.
+ pthread_mutex_init(&mutex, NULL);
+ pthread_mutex_lock(&mutex);
+ ASSERT_EQ(0, pthread_attr_init(&attr));
+ ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
+
+ const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex);
+ ASSERT_EQ(0, pthread_attr_destroy(&attr));
+ ASSERT_EQ(0, status);
+ EXPECT_EQ(2U, GetThreadCount());
+ pthread_mutex_unlock(&mutex);
+
+ void* dummy;
+ ASSERT_EQ(0, pthread_join(thread_id, &dummy));
+
+# if GTEST_OS_MAC
+
+ // MacOS X may not immediately report the updated thread count after
+ // joining a thread, causing flakiness in this test. To counter that, we
+ // wait for up to .5 seconds for the OS to report the correct value.
+ for (int i = 0; i < 5; ++i) {
+ if (GetThreadCount() == 1)
+ break;
+
+ SleepMilliseconds(100);
+ }
+
+# endif // GTEST_OS_MAC
+
+ EXPECT_EQ(1U, GetThreadCount());
+ pthread_mutex_destroy(&mutex);
+}
+#else
+TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads)
+{
+ EXPECT_EQ(0U, GetThreadCount());
+}
+#endif // GTEST_OS_MAC || GTEST_OS_QNX
+
+TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure)
+{
+ const bool a_false_condition = false;
+ const char regex[] =
+#ifdef _MSC_VER
+ "gtest-port_test\\.cc\\(\\d+\\):"
+#elif GTEST_USES_POSIX_RE
+ "gtest-port_test\\.cc:[0-9]+"
+#else
+ "gtest-port_test\\.cc:\\d+"
+#endif // _MSC_VER
+ ".*a_false_condition.*Extra info.*";
+
+ EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info",
+ regex);
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess)
+{
+ EXPECT_EXIT({
+ GTEST_CHECK_(true) << "Extra info";
+ ::std::cerr << "Success\n";
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "Success");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Verifies that Google Test choose regular expression engine appropriate to
+// the platform. The test will produce compiler errors in case of failure.
+// For simplicity, we only cover the most important platforms here.
+TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine)
+{
+#if GTEST_HAS_POSIX_RE
+
+ EXPECT_TRUE(GTEST_USES_POSIX_RE);
+
+#else
+
+ EXPECT_TRUE(GTEST_USES_SIMPLE_RE);
+
+#endif
+}
+
+#if GTEST_USES_POSIX_RE
+
+# if GTEST_HAS_TYPED_TEST
+
+template <typename Str>
+class RETest : public ::testing::Test {};
+
+// Defines StringTypes as the list of all string types that class RE
+// supports.
+typedef testing::Types<
+::std::string,
+# if GTEST_HAS_GLOBAL_STRING
+::string,
+# endif // GTEST_HAS_GLOBAL_STRING
+const char*> StringTypes;
+
+TYPED_TEST_CASE(RETest, StringTypes);
+
+// Tests RE's implicit constructors.
+TYPED_TEST(RETest, ImplicitConstructorWorks)
+{
+ const RE empty(TypeParam(""));
+ EXPECT_STREQ("", empty.pattern());
+
+ const RE simple(TypeParam("hello"));
+ EXPECT_STREQ("hello", simple.pattern());
+
+ const RE normal(TypeParam(".*(\\w+)"));
+ EXPECT_STREQ(".*(\\w+)", normal.pattern());
+}
+
+// Tests that RE's constructors reject invalid regular expressions.
+TYPED_TEST(RETest, RejectsInvalidRegex)
+{
+ EXPECT_NONFATAL_FAILURE({
+ const RE invalid(TypeParam("?"));
+ }, "\"?\" is not a valid POSIX Extended regular expression.");
+}
+
+// Tests RE::FullMatch().
+TYPED_TEST(RETest, FullMatchWorks)
+{
+ const RE empty(TypeParam(""));
+ EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty));
+ EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty));
+
+ const RE re(TypeParam("a.*z"));
+ EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re));
+ EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re));
+ EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re));
+ EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re));
+}
+
+// Tests RE::PartialMatch().
+TYPED_TEST(RETest, PartialMatchWorks)
+{
+ const RE empty(TypeParam(""));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty));
+
+ const RE re(TypeParam("a.*z"));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re));
+ EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re));
+}
+
+# endif // GTEST_HAS_TYPED_TEST
+
+#elif GTEST_USES_SIMPLE_RE
+
+TEST(IsInSetTest, NulCharIsNotInAnySet)
+{
+ EXPECT_FALSE(IsInSet('\0', ""));
+ EXPECT_FALSE(IsInSet('\0', "\0"));
+ EXPECT_FALSE(IsInSet('\0', "a"));
+}
+
+TEST(IsInSetTest, WorksForNonNulChars)
+{
+ EXPECT_FALSE(IsInSet('a', "Ab"));
+ EXPECT_FALSE(IsInSet('c', ""));
+
+ EXPECT_TRUE(IsInSet('b', "bcd"));
+ EXPECT_TRUE(IsInSet('b', "ab"));
+}
+
+TEST(IsAsciiDigitTest, IsFalseForNonDigit)
+{
+ EXPECT_FALSE(IsAsciiDigit('\0'));
+ EXPECT_FALSE(IsAsciiDigit(' '));
+ EXPECT_FALSE(IsAsciiDigit('+'));
+ EXPECT_FALSE(IsAsciiDigit('-'));
+ EXPECT_FALSE(IsAsciiDigit('.'));
+ EXPECT_FALSE(IsAsciiDigit('a'));
+}
+
+TEST(IsAsciiDigitTest, IsTrueForDigit)
+{
+ EXPECT_TRUE(IsAsciiDigit('0'));
+ EXPECT_TRUE(IsAsciiDigit('1'));
+ EXPECT_TRUE(IsAsciiDigit('5'));
+ EXPECT_TRUE(IsAsciiDigit('9'));
+}
+
+TEST(IsAsciiPunctTest, IsFalseForNonPunct)
+{
+ EXPECT_FALSE(IsAsciiPunct('\0'));
+ EXPECT_FALSE(IsAsciiPunct(' '));
+ EXPECT_FALSE(IsAsciiPunct('\n'));
+ EXPECT_FALSE(IsAsciiPunct('a'));
+ EXPECT_FALSE(IsAsciiPunct('0'));
+}
+
+TEST(IsAsciiPunctTest, IsTrueForPunct)
+{
+ for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) {
+ EXPECT_PRED1(IsAsciiPunct, *p);
+ }
+}
+
+TEST(IsRepeatTest, IsFalseForNonRepeatChar)
+{
+ EXPECT_FALSE(IsRepeat('\0'));
+ EXPECT_FALSE(IsRepeat(' '));
+ EXPECT_FALSE(IsRepeat('a'));
+ EXPECT_FALSE(IsRepeat('1'));
+ EXPECT_FALSE(IsRepeat('-'));
+}
+
+TEST(IsRepeatTest, IsTrueForRepeatChar)
+{
+ EXPECT_TRUE(IsRepeat('?'));
+ EXPECT_TRUE(IsRepeat('*'));
+ EXPECT_TRUE(IsRepeat('+'));
+}
+
+TEST(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace)
+{
+ EXPECT_FALSE(IsAsciiWhiteSpace('\0'));
+ EXPECT_FALSE(IsAsciiWhiteSpace('a'));
+ EXPECT_FALSE(IsAsciiWhiteSpace('1'));
+ EXPECT_FALSE(IsAsciiWhiteSpace('+'));
+ EXPECT_FALSE(IsAsciiWhiteSpace('_'));
+}
+
+TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace)
+{
+ EXPECT_TRUE(IsAsciiWhiteSpace(' '));
+ EXPECT_TRUE(IsAsciiWhiteSpace('\n'));
+ EXPECT_TRUE(IsAsciiWhiteSpace('\r'));
+ EXPECT_TRUE(IsAsciiWhiteSpace('\t'));
+ EXPECT_TRUE(IsAsciiWhiteSpace('\v'));
+ EXPECT_TRUE(IsAsciiWhiteSpace('\f'));
+}
+
+TEST(IsAsciiWordCharTest, IsFalseForNonWordChar)
+{
+ EXPECT_FALSE(IsAsciiWordChar('\0'));
+ EXPECT_FALSE(IsAsciiWordChar('+'));
+ EXPECT_FALSE(IsAsciiWordChar('.'));
+ EXPECT_FALSE(IsAsciiWordChar(' '));
+ EXPECT_FALSE(IsAsciiWordChar('\n'));
+}
+
+TEST(IsAsciiWordCharTest, IsTrueForLetter)
+{
+ EXPECT_TRUE(IsAsciiWordChar('a'));
+ EXPECT_TRUE(IsAsciiWordChar('b'));
+ EXPECT_TRUE(IsAsciiWordChar('A'));
+ EXPECT_TRUE(IsAsciiWordChar('Z'));
+}
+
+TEST(IsAsciiWordCharTest, IsTrueForDigit)
+{
+ EXPECT_TRUE(IsAsciiWordChar('0'));
+ EXPECT_TRUE(IsAsciiWordChar('1'));
+ EXPECT_TRUE(IsAsciiWordChar('7'));
+ EXPECT_TRUE(IsAsciiWordChar('9'));
+}
+
+TEST(IsAsciiWordCharTest, IsTrueForUnderscore)
+{
+ EXPECT_TRUE(IsAsciiWordChar('_'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForNonPrintable)
+{
+ EXPECT_FALSE(IsValidEscape('\0'));
+ EXPECT_FALSE(IsValidEscape('\007'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForDigit)
+{
+ EXPECT_FALSE(IsValidEscape('0'));
+ EXPECT_FALSE(IsValidEscape('9'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForWhiteSpace)
+{
+ EXPECT_FALSE(IsValidEscape(' '));
+ EXPECT_FALSE(IsValidEscape('\n'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForSomeLetter)
+{
+ EXPECT_FALSE(IsValidEscape('a'));
+ EXPECT_FALSE(IsValidEscape('Z'));
+}
+
+TEST(IsValidEscapeTest, IsTrueForPunct)
+{
+ EXPECT_TRUE(IsValidEscape('.'));
+ EXPECT_TRUE(IsValidEscape('-'));
+ EXPECT_TRUE(IsValidEscape('^'));
+ EXPECT_TRUE(IsValidEscape('$'));
+ EXPECT_TRUE(IsValidEscape('('));
+ EXPECT_TRUE(IsValidEscape(']'));
+ EXPECT_TRUE(IsValidEscape('{'));
+ EXPECT_TRUE(IsValidEscape('|'));
+}
+
+TEST(IsValidEscapeTest, IsTrueForSomeLetter)
+{
+ EXPECT_TRUE(IsValidEscape('d'));
+ EXPECT_TRUE(IsValidEscape('D'));
+ EXPECT_TRUE(IsValidEscape('s'));
+ EXPECT_TRUE(IsValidEscape('S'));
+ EXPECT_TRUE(IsValidEscape('w'));
+ EXPECT_TRUE(IsValidEscape('W'));
+}
+
+TEST(AtomMatchesCharTest, EscapedPunct)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, '\\', ' '));
+ EXPECT_FALSE(AtomMatchesChar(true, '_', '.'));
+ EXPECT_FALSE(AtomMatchesChar(true, '.', 'a'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\'));
+ EXPECT_TRUE(AtomMatchesChar(true, '_', '_'));
+ EXPECT_TRUE(AtomMatchesChar(true, '+', '+'));
+ EXPECT_TRUE(AtomMatchesChar(true, '.', '.'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_d)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'd', '.'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'd', '0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'd', '9'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_D)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 'D', '0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'D', '9'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'D', '-'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_s)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 's', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 's', 'a'));
+ EXPECT_FALSE(AtomMatchesChar(true, 's', '.'));
+ EXPECT_FALSE(AtomMatchesChar(true, 's', '9'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 's', ' '));
+ EXPECT_TRUE(AtomMatchesChar(true, 's', '\n'));
+ EXPECT_TRUE(AtomMatchesChar(true, 's', '\t'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_S)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 'S', ' '));
+ EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'S', '9'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_w)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', '+'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', ' '));
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', '0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', '_'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_W)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', '9'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', '_'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'W', '*'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n'));
+}
+
+TEST(AtomMatchesCharTest, EscapedWhiteSpace)
+{
+ EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a'));
+ EXPECT_FALSE(AtomMatchesChar(true, 't', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 't', 't'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r'));
+ EXPECT_TRUE(AtomMatchesChar(true, 't', '\t'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v'));
+}
+
+TEST(AtomMatchesCharTest, UnescapedDot)
+{
+ EXPECT_FALSE(AtomMatchesChar(false, '.', '\n'));
+
+ EXPECT_TRUE(AtomMatchesChar(false, '.', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(false, '.', '.'));
+ EXPECT_TRUE(AtomMatchesChar(false, '.', 'a'));
+ EXPECT_TRUE(AtomMatchesChar(false, '.', ' '));
+}
+
+TEST(AtomMatchesCharTest, UnescapedChar)
+{
+ EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b'));
+ EXPECT_FALSE(AtomMatchesChar(false, '$', 'a'));
+
+ EXPECT_TRUE(AtomMatchesChar(false, '$', '$'));
+ EXPECT_TRUE(AtomMatchesChar(false, '5', '5'));
+ EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z'));
+}
+
+TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid)
+{
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)),
+ "NULL is not a valid simple regular expression");
+ EXPECT_NONFATAL_FAILURE(
+ ASSERT_FALSE(ValidateRegex("a\\")),
+ "Syntax error at index 1 in simple regular expression \"a\\\": ");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")),
+ "'\\' cannot appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")),
+ "'\\' cannot appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")),
+ "invalid escape sequence \"\\h\"");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")),
+ "'^' can only appear at the beginning");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")),
+ "'^' can only appear at the beginning");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")),
+ "'$' can only appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")),
+ "'$' can only appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")),
+ "'(' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")),
+ "')' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")),
+ "'[' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")),
+ "'{' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")),
+ "'?' can only follow a repeatable token");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")),
+ "'*' can only follow a repeatable token");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")),
+ "'+' can only follow a repeatable token");
+}
+
+TEST(ValidateRegexTest, ReturnsTrueForValid)
+{
+ EXPECT_TRUE(ValidateRegex(""));
+ EXPECT_TRUE(ValidateRegex("a"));
+ EXPECT_TRUE(ValidateRegex(".*"));
+ EXPECT_TRUE(ValidateRegex("^a_+"));
+ EXPECT_TRUE(ValidateRegex("^a\\t\\&?"));
+ EXPECT_TRUE(ValidateRegex("09*$"));
+ EXPECT_TRUE(ValidateRegex("^Z$"));
+ EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}"));
+}
+
+TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne)
+{
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba"));
+ // Repeating more than once.
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab"));
+
+ // Repeating zero times.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba"));
+ // Repeating once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab"));
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##"));
+}
+
+TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany)
+{
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab"));
+
+ // Repeating zero times.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc"));
+ // Repeating once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc"));
+ // Repeating more than once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g"));
+}
+
+TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany)
+{
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab"));
+ // Repeating zero times.
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc"));
+
+ // Repeating once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc"));
+ // Repeating more than once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g"));
+}
+
+TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex)
+{
+ EXPECT_TRUE(MatchRegexAtHead("", ""));
+ EXPECT_TRUE(MatchRegexAtHead("", "ab"));
+}
+
+TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex)
+{
+ EXPECT_FALSE(MatchRegexAtHead("$", "a"));
+
+ EXPECT_TRUE(MatchRegexAtHead("$", ""));
+ EXPECT_TRUE(MatchRegexAtHead("a$", "a"));
+}
+
+TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence)
+{
+ EXPECT_FALSE(MatchRegexAtHead("\\w", "+"));
+ EXPECT_FALSE(MatchRegexAtHead("\\W", "ab"));
+
+ EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab"));
+ EXPECT_TRUE(MatchRegexAtHead("\\d", "1a"));
+}
+
+TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition)
+{
+ EXPECT_FALSE(MatchRegexAtHead(".+a", "abc"));
+ EXPECT_FALSE(MatchRegexAtHead("a?b", "aab"));
+
+ EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab"));
+ EXPECT_TRUE(MatchRegexAtHead("a?b", "b"));
+ EXPECT_TRUE(MatchRegexAtHead("a?b", "ab"));
+}
+
+TEST(MatchRegexAtHeadTest,
+ WorksWhenRegexStartsWithRepetionOfEscapeSequence)
+{
+ EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc"));
+ EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b"));
+
+ EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab"));
+ EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b"));
+ EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b"));
+ EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b"));
+}
+
+TEST(MatchRegexAtHeadTest, MatchesSequentially)
+{
+ EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc"));
+
+ EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc"));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull)
+{
+ EXPECT_FALSE(MatchRegexAnywhere("", NULL));
+}
+
+TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret)
+{
+ EXPECT_FALSE(MatchRegexAnywhere("^a", "ba"));
+ EXPECT_FALSE(MatchRegexAnywhere("^$", "a"));
+
+ EXPECT_TRUE(MatchRegexAnywhere("^a", "ab"));
+ EXPECT_TRUE(MatchRegexAnywhere("^", "ab"));
+ EXPECT_TRUE(MatchRegexAnywhere("^$", ""));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch)
+{
+ EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123"));
+ EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888"));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix)
+{
+ EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5"));
+ EXPECT_TRUE(MatchRegexAnywhere(".*=", "="));
+ EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc"));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix)
+{
+ EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5"));
+ EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...="));
+}
+
+// Tests RE's implicit constructors.
+TEST(RETest, ImplicitConstructorWorks)
+{
+ const RE empty("");
+ EXPECT_STREQ("", empty.pattern());
+
+ const RE simple("hello");
+ EXPECT_STREQ("hello", simple.pattern());
+}
+
+// Tests that RE's constructors reject invalid regular expressions.
+TEST(RETest, RejectsInvalidRegex)
+{
+ EXPECT_NONFATAL_FAILURE({
+ const RE normal(NULL);
+ }, "NULL is not a valid simple regular expression");
+
+ EXPECT_NONFATAL_FAILURE({
+ const RE normal(".*(\\w+");
+ }, "'(' is unsupported");
+
+ EXPECT_NONFATAL_FAILURE({
+ const RE invalid("^?");
+ }, "'?' can only follow a repeatable token");
+}
+
+// Tests RE::FullMatch().
+TEST(RETest, FullMatchWorks)
+{
+ const RE empty("");
+ EXPECT_TRUE(RE::FullMatch("", empty));
+ EXPECT_FALSE(RE::FullMatch("a", empty));
+
+ const RE re1("a");
+ EXPECT_TRUE(RE::FullMatch("a", re1));
+
+ const RE re("a.*z");
+ EXPECT_TRUE(RE::FullMatch("az", re));
+ EXPECT_TRUE(RE::FullMatch("axyz", re));
+ EXPECT_FALSE(RE::FullMatch("baz", re));
+ EXPECT_FALSE(RE::FullMatch("azy", re));
+}
+
+// Tests RE::PartialMatch().
+TEST(RETest, PartialMatchWorks)
+{
+ const RE empty("");
+ EXPECT_TRUE(RE::PartialMatch("", empty));
+ EXPECT_TRUE(RE::PartialMatch("a", empty));
+
+ const RE re("a.*z");
+ EXPECT_TRUE(RE::PartialMatch("az", re));
+ EXPECT_TRUE(RE::PartialMatch("axyz", re));
+ EXPECT_TRUE(RE::PartialMatch("baz", re));
+ EXPECT_TRUE(RE::PartialMatch("azy", re));
+ EXPECT_FALSE(RE::PartialMatch("zza", re));
+}
+
+#endif // GTEST_USES_POSIX_RE
+
+#if !GTEST_OS_WINDOWS_MOBILE
+
+TEST(CaptureTest, CapturesStdout)
+{
+ CaptureStdout();
+ fprintf(stdout, "abc");
+ EXPECT_STREQ("abc", GetCapturedStdout().c_str());
+
+ CaptureStdout();
+ fprintf(stdout, "def%cghi", '\0');
+ EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout()));
+}
+
+TEST(CaptureTest, CapturesStderr)
+{
+ CaptureStderr();
+ fprintf(stderr, "jkl");
+ EXPECT_STREQ("jkl", GetCapturedStderr().c_str());
+
+ CaptureStderr();
+ fprintf(stderr, "jkl%cmno", '\0');
+ EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr()));
+}
+
+// Tests that stdout and stderr capture don't interfere with each other.
+TEST(CaptureTest, CapturesStdoutAndStderr)
+{
+ CaptureStdout();
+ CaptureStderr();
+ fprintf(stdout, "pqr");
+ fprintf(stderr, "stu");
+ EXPECT_STREQ("pqr", GetCapturedStdout().c_str());
+ EXPECT_STREQ("stu", GetCapturedStderr().c_str());
+}
+
+TEST(CaptureDeathTest, CannotReenterStdoutCapture)
+{
+ CaptureStdout();
+ EXPECT_DEATH_IF_SUPPORTED(CaptureStdout(),
+ "Only one stdout capturer can exist at a time");
+ GetCapturedStdout();
+
+ // We cannot test stderr capturing using death tests as they use it
+ // themselves.
+}
+
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues)
+{
+ ThreadLocal<int> t1;
+ EXPECT_EQ(0, t1.get());
+
+ ThreadLocal<void*> t2;
+ EXPECT_TRUE(t2.get() == NULL);
+}
+
+TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam)
+{
+ ThreadLocal<int> t1(123);
+ EXPECT_EQ(123, t1.get());
+
+ int i = 0;
+ ThreadLocal<int*> t2(&i);
+ EXPECT_EQ(&i, t2.get());
+}
+
+class NoDefaultContructor
+{
+ public:
+ explicit NoDefaultContructor(const char*) {}
+ NoDefaultContructor(const NoDefaultContructor&) {}
+};
+
+TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion)
+{
+ ThreadLocal<NoDefaultContructor> bar(NoDefaultContructor("foo"));
+ bar.pointer();
+}
+
+TEST(ThreadLocalTest, GetAndPointerReturnSameValue)
+{
+ ThreadLocal<std::string> thread_local_string;
+
+ EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get()));
+
+ // Verifies the condition still holds after calling set.
+ thread_local_string.set("foo");
+ EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get()));
+}
+
+TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue)
+{
+ ThreadLocal<std::string> thread_local_string;
+ const ThreadLocal<std::string>& const_thread_local_string =
+ thread_local_string;
+
+ EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer());
+
+ thread_local_string.set("foo");
+ EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer());
+}
+
+#if GTEST_IS_THREADSAFE
+
+void AddTwo(int* param) { *param += 2; }
+
+TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc)
+{
+ int i = 40;
+ ThreadWithParam<int*> thread(&AddTwo, &i, NULL);
+ thread.Join();
+ EXPECT_EQ(42, i);
+}
+
+TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked)
+{
+ // AssertHeld() is flaky only in the presence of multiple threads accessing
+ // the lock. In this case, the test is robust.
+ EXPECT_DEATH_IF_SUPPORTED({
+ Mutex m;
+ { MutexLock lock(&m); }
+ m.AssertHeld();
+ },
+ "thread .*hold");
+}
+
+TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked)
+{
+ Mutex m;
+ MutexLock lock(&m);
+ m.AssertHeld();
+}
+
+class AtomicCounterWithMutex
+{
+ public:
+ explicit AtomicCounterWithMutex(Mutex* mutex) :
+ value_(0), mutex_(mutex), random_(42) {}
+
+ void Increment() {
+ MutexLock lock(mutex_);
+ int temp = value_;
+ {
+ // Locking a mutex puts up a memory barrier, preventing reads and
+ // writes to value_ rearranged when observed from other threads.
+ //
+ // We cannot use Mutex and MutexLock here or rely on their memory
+ // barrier functionality as we are testing them here.
+ pthread_mutex_t memory_barrier_mutex;
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_mutex_init(&memory_barrier_mutex, NULL));
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex));
+
+ SleepMilliseconds(random_.Generate(30));
+
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex));
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex));
+ }
+ value_ = temp + 1;
+ }
+ int value() const { return value_; }
+
+ private:
+ volatile int value_;
+ Mutex* const mutex_; // Protects value_.
+ Random random_;
+};
+
+void CountingThreadFunc(pair<AtomicCounterWithMutex*, int> param)
+{
+ for (int i = 0; i < param.second; ++i)
+ param.first->Increment();
+}
+
+// Tests that the mutex only lets one thread at a time to lock it.
+TEST(MutexTest, OnlyOneThreadCanLockAtATime)
+{
+ Mutex mutex;
+ AtomicCounterWithMutex locked_counter(&mutex);
+
+ typedef ThreadWithParam<pair<AtomicCounterWithMutex*, int> > ThreadType;
+ const int kCycleCount = 20;
+ const int kThreadCount = 7;
+ scoped_ptr<ThreadType> counting_threads[kThreadCount];
+ Notification threads_can_start;
+ // Creates and runs kThreadCount threads that increment locked_counter
+ // kCycleCount times each.
+ for (int i = 0; i < kThreadCount; ++i) {
+ counting_threads[i].reset(new ThreadType(&CountingThreadFunc,
+ make_pair(&locked_counter,
+ kCycleCount),
+ &threads_can_start));
+ }
+ threads_can_start.Notify();
+ for (int i = 0; i < kThreadCount; ++i)
+ counting_threads[i]->Join();
+
+ // If the mutex lets more than one thread to increment the counter at a
+ // time, they are likely to encounter a race condition and have some
+ // increments overwritten, resulting in the lower then expected counter
+ // value.
+ EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value());
+}
+
+template <typename T>
+void RunFromThread(void (func)(T), T param)
+{
+ ThreadWithParam<T> thread(func, param, NULL);
+ thread.Join();
+}
+
+void RetrieveThreadLocalValue(
+ pair<ThreadLocal<std::string>*, std::string*> param)
+{
+ *param.second = param.first->get();
+}
+
+TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault)
+{
+ ThreadLocal<std::string> thread_local_string("foo");
+ EXPECT_STREQ("foo", thread_local_string.get().c_str());
+
+ thread_local_string.set("bar");
+ EXPECT_STREQ("bar", thread_local_string.get().c_str());
+
+ std::string result;
+ RunFromThread(&RetrieveThreadLocalValue,
+ make_pair(&thread_local_string, &result));
+ EXPECT_STREQ("foo", result.c_str());
+}
+
+// DestructorTracker keeps track of whether its instances have been
+// destroyed.
+static std::vector<bool> g_destroyed;
+
+class DestructorTracker
+{
+ public:
+ DestructorTracker() : index_(GetNewIndex()) {}
+ DestructorTracker(const DestructorTracker& /* rhs */)
+ : index_(GetNewIndex()) {}
+ ~DestructorTracker() {
+ // We never access g_destroyed concurrently, so we don't need to
+ // protect the write operation under a mutex.
+ g_destroyed[index_] = true;
+ }
+
+ private:
+ static int GetNewIndex() {
+ g_destroyed.push_back(false);
+ return g_destroyed.size() - 1;
+ }
+ const int index_;
+};
+
+typedef ThreadLocal<DestructorTracker>* ThreadParam;
+
+void CallThreadLocalGet(ThreadParam thread_local_param)
+{
+ thread_local_param->get();
+}
+
+// Tests that when a ThreadLocal object dies in a thread, it destroys
+// the managed object for that thread.
+TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying)
+{
+ g_destroyed.clear();
+
+ {
+ // The next line default constructs a DestructorTracker object as
+ // the default value of objects managed by thread_local_tracker.
+ ThreadLocal<DestructorTracker> thread_local_tracker;
+ ASSERT_EQ(1U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+
+ // This creates another DestructorTracker object for the main thread.
+ thread_local_tracker.get();
+ ASSERT_EQ(2U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+ ASSERT_FALSE(g_destroyed[1]);
+ }
+
+ // Now thread_local_tracker has died. It should have destroyed both the
+ // default value shared by all threads and the value for the main
+ // thread.
+ ASSERT_EQ(2U, g_destroyed.size());
+ EXPECT_TRUE(g_destroyed[0]);
+ EXPECT_TRUE(g_destroyed[1]);
+
+ g_destroyed.clear();
+}
+
+// Tests that when a thread exits, the thread-local object for that
+// thread is destroyed.
+TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit)
+{
+ g_destroyed.clear();
+
+ {
+ // The next line default constructs a DestructorTracker object as
+ // the default value of objects managed by thread_local_tracker.
+ ThreadLocal<DestructorTracker> thread_local_tracker;
+ ASSERT_EQ(1U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+
+ // This creates another DestructorTracker object in the new thread.
+ ThreadWithParam<ThreadParam> thread(
+ &CallThreadLocalGet, &thread_local_tracker, NULL);
+ thread.Join();
+
+ // Now the new thread has exited. The per-thread object for it
+ // should have been destroyed.
+ ASSERT_EQ(2U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+ ASSERT_TRUE(g_destroyed[1]);
+ }
+
+ // Now thread_local_tracker has died. The default value should have been
+ // destroyed too.
+ ASSERT_EQ(2U, g_destroyed.size());
+ EXPECT_TRUE(g_destroyed[0]);
+ EXPECT_TRUE(g_destroyed[1]);
+
+ g_destroyed.clear();
+}
+
+TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread)
+{
+ ThreadLocal<std::string> thread_local_string;
+ thread_local_string.set("Foo");
+ EXPECT_STREQ("Foo", thread_local_string.get().c_str());
+
+ std::string result;
+ RunFromThread(&RetrieveThreadLocalValue,
+ make_pair(&thread_local_string, &result));
+ EXPECT_TRUE(result.empty());
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+} // namespace internal
+} // namespace testing
diff --git a/external/gtest-1.6.0/test/gtest-printers_test.cc b/external/gtest-1.6.0/test/gtest-printers_test.cc
new file mode 100644
index 0000000..d3e284d
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-printers_test.cc
@@ -0,0 +1,1718 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file tests the universal value printer.
+
+#include "gtest/gtest-printers.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <algorithm>
+#include <deque>
+#include <list>
+#include <map>
+#include <set>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+// hash_map and hash_set are available under Visual C++.
+#if _MSC_VER
+# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available.
+# include <hash_map> // NOLINT
+# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available.
+# include <hash_set> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+// Some user-defined types for testing the universal value printer.
+
+// An anonymous enum type.
+enum AnonymousEnum {
+ kAE1 = -1,
+ kAE2 = 1
+};
+
+// An enum without a user-defined printer.
+enum EnumWithoutPrinter {
+ kEWP1 = -2,
+ kEWP2 = 42
+};
+
+// An enum with a << operator.
+enum EnumWithStreaming {
+ kEWS1 = 10
+};
+
+std::ostream& operator<<(std::ostream& os, EnumWithStreaming e)
+{
+ return os << (e == kEWS1 ? "kEWS1" : "invalid");
+}
+
+// An enum with a PrintTo() function.
+enum EnumWithPrintTo {
+ kEWPT1 = 1
+};
+
+void PrintTo(EnumWithPrintTo e, std::ostream* os)
+{
+ *os << (e == kEWPT1 ? "kEWPT1" : "invalid");
+}
+
+// A class implicitly convertible to BiggestInt.
+class BiggestIntConvertible
+{
+ public:
+ operator ::testing::internal::BiggestInt() const { return 42; }
+};
+
+// A user-defined unprintable class template in the global namespace.
+template <typename T>
+class UnprintableTemplateInGlobal
+{
+ public:
+ UnprintableTemplateInGlobal() : value_() {}
+ private:
+ T value_;
+};
+
+// A user-defined streamable type in the global namespace.
+class StreamableInGlobal
+{
+ public:
+ virtual ~StreamableInGlobal() {}
+};
+
+inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */)
+{
+ os << "StreamableInGlobal";
+}
+
+void operator<<(::std::ostream& os, const StreamableInGlobal* /* x */)
+{
+ os << "StreamableInGlobal*";
+}
+
+namespace foo
+{
+
+// A user-defined unprintable type in a user namespace.
+class UnprintableInFoo
+{
+ public:
+ UnprintableInFoo() : z_(0) { memcpy(xy_, "\xEF\x12\x0\x0\x34\xAB\x0\x0", 8); }
+ private:
+ char xy_[8];
+ double z_;
+};
+
+// A user-defined printable type in a user-chosen namespace.
+struct PrintableViaPrintTo {
+ PrintableViaPrintTo() : value() {}
+ int value;
+};
+
+void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os)
+{
+ *os << "PrintableViaPrintTo: " << x.value;
+}
+
+// A type with a user-defined << for printing its pointer.
+struct PointerPrintable {
+};
+
+::std::ostream& operator<<(::std::ostream& os,
+ const PointerPrintable* /* x */)
+{
+ return os << "PointerPrintable*";
+}
+
+// A user-defined printable class template in a user-chosen namespace.
+template <typename T>
+class PrintableViaPrintToTemplate
+{
+ public:
+ explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {}
+
+ const T& value() const { return value_; }
+ private:
+ T value_;
+};
+
+template <typename T>
+void PrintTo(const PrintableViaPrintToTemplate<T>& x, ::std::ostream* os)
+{
+ *os << "PrintableViaPrintToTemplate: " << x.value();
+}
+
+// A user-defined streamable class template in a user namespace.
+template <typename T>
+class StreamableTemplateInFoo
+{
+ public:
+ StreamableTemplateInFoo() : value_() {}
+
+ const T& value() const { return value_; }
+ private:
+ T value_;
+};
+
+template <typename T>
+inline ::std::ostream& operator<<(::std::ostream& os,
+ const StreamableTemplateInFoo<T>& x)
+{
+ return os << "StreamableTemplateInFoo: " << x.value();
+}
+
+} // namespace foo
+
+namespace testing
+{
+namespace gtest_printers_test
+{
+
+using ::std::deque;
+using ::std::list;
+using ::std::make_pair;
+using ::std::map;
+using ::std::multimap;
+using ::std::multiset;
+using ::std::pair;
+using ::std::set;
+using ::std::vector;
+using ::testing::PrintToString;
+using ::testing::internal::FormatForComparisonFailureMessage;
+using ::testing::internal::ImplicitCast_;
+using ::testing::internal::NativeArray;
+using ::testing::internal::RE;
+using ::testing::internal::Strings;
+using ::testing::internal::UniversalPrint;
+using ::testing::internal::UniversalPrinter;
+using ::testing::internal::UniversalTersePrint;
+using ::testing::internal::UniversalTersePrintTupleFieldsToStrings;
+using ::testing::internal::kReference;
+using ::testing::internal::string;
+
+#if GTEST_HAS_TR1_TUPLE
+using ::std::tr1::make_tuple;
+using ::std::tr1::tuple;
+#endif
+
+// The hash_* classes are not part of the C++ standard. STLport
+// defines them in namespace std. MSVC defines them in ::stdext. GCC
+// defines them in ::.
+#ifdef _STLP_HASH_MAP // We got <hash_map> from STLport.
+using ::std::hash_map;
+using ::std::hash_set;
+using ::std::hash_multimap;
+using ::std::hash_multiset;
+#elif _MSC_VER
+using ::stdext::hash_map;
+using ::stdext::hash_set;
+using ::stdext::hash_multimap;
+using ::stdext::hash_multiset;
+#endif
+
+// Prints a value to a string using the universal value printer. This
+// is a helper for testing UniversalPrinter<T>::Print() for various types.
+template <typename T>
+string Print(const T& value)
+{
+ ::std::stringstream ss;
+ UniversalPrinter<T>::Print(value, &ss);
+ return ss.str();
+}
+
+// Prints a value passed by reference to a string, using the universal
+// value printer. This is a helper for testing
+// UniversalPrinter<T&>::Print() for various types.
+template <typename T>
+string PrintByRef(const T& value)
+{
+ ::std::stringstream ss;
+ UniversalPrinter<T&>::Print(value, &ss);
+ return ss.str();
+}
+
+// Tests printing various enum types.
+
+TEST(PrintEnumTest, AnonymousEnum)
+{
+ EXPECT_EQ("-1", Print(kAE1));
+ EXPECT_EQ("1", Print(kAE2));
+}
+
+TEST(PrintEnumTest, EnumWithoutPrinter)
+{
+ EXPECT_EQ("-2", Print(kEWP1));
+ EXPECT_EQ("42", Print(kEWP2));
+}
+
+TEST(PrintEnumTest, EnumWithStreaming)
+{
+ EXPECT_EQ("kEWS1", Print(kEWS1));
+ EXPECT_EQ("invalid", Print(static_cast<EnumWithStreaming>(0)));
+}
+
+TEST(PrintEnumTest, EnumWithPrintTo)
+{
+ EXPECT_EQ("kEWPT1", Print(kEWPT1));
+ EXPECT_EQ("invalid", Print(static_cast<EnumWithPrintTo>(0)));
+}
+
+// Tests printing a class implicitly convertible to BiggestInt.
+
+TEST(PrintClassTest, BiggestIntConvertible)
+{
+ EXPECT_EQ("42", Print(BiggestIntConvertible()));
+}
+
+// Tests printing various char types.
+
+// char.
+TEST(PrintCharTest, PlainChar)
+{
+ EXPECT_EQ("'\\0'", Print('\0'));
+ EXPECT_EQ("'\\'' (39, 0x27)", Print('\''));
+ EXPECT_EQ("'\"' (34, 0x22)", Print('"'));
+ EXPECT_EQ("'?' (63, 0x3F)", Print('?'));
+ EXPECT_EQ("'\\\\' (92, 0x5C)", Print('\\'));
+ EXPECT_EQ("'\\a' (7)", Print('\a'));
+ EXPECT_EQ("'\\b' (8)", Print('\b'));
+ EXPECT_EQ("'\\f' (12, 0xC)", Print('\f'));
+ EXPECT_EQ("'\\n' (10, 0xA)", Print('\n'));
+ EXPECT_EQ("'\\r' (13, 0xD)", Print('\r'));
+ EXPECT_EQ("'\\t' (9)", Print('\t'));
+ EXPECT_EQ("'\\v' (11, 0xB)", Print('\v'));
+ EXPECT_EQ("'\\x7F' (127)", Print('\x7F'));
+ EXPECT_EQ("'\\xFF' (255)", Print('\xFF'));
+ EXPECT_EQ("' ' (32, 0x20)", Print(' '));
+ EXPECT_EQ("'a' (97, 0x61)", Print('a'));
+}
+
+// signed char.
+TEST(PrintCharTest, SignedChar)
+{
+ EXPECT_EQ("'\\0'", Print(static_cast<signed char>('\0')));
+ EXPECT_EQ("'\\xCE' (-50)",
+ Print(static_cast<signed char>(-50)));
+}
+
+// unsigned char.
+TEST(PrintCharTest, UnsignedChar)
+{
+ EXPECT_EQ("'\\0'", Print(static_cast<unsigned char>('\0')));
+ EXPECT_EQ("'b' (98, 0x62)",
+ Print(static_cast<unsigned char>('b')));
+}
+
+// Tests printing other simple, built-in types.
+
+// bool.
+TEST(PrintBuiltInTypeTest, Bool)
+{
+ EXPECT_EQ("false", Print(false));
+ EXPECT_EQ("true", Print(true));
+}
+
+// wchar_t.
+TEST(PrintBuiltInTypeTest, Wchar_t)
+{
+ EXPECT_EQ("L'\\0'", Print(L'\0'));
+ EXPECT_EQ("L'\\'' (39, 0x27)", Print(L'\''));
+ EXPECT_EQ("L'\"' (34, 0x22)", Print(L'"'));
+ EXPECT_EQ("L'?' (63, 0x3F)", Print(L'?'));
+ EXPECT_EQ("L'\\\\' (92, 0x5C)", Print(L'\\'));
+ EXPECT_EQ("L'\\a' (7)", Print(L'\a'));
+ EXPECT_EQ("L'\\b' (8)", Print(L'\b'));
+ EXPECT_EQ("L'\\f' (12, 0xC)", Print(L'\f'));
+ EXPECT_EQ("L'\\n' (10, 0xA)", Print(L'\n'));
+ EXPECT_EQ("L'\\r' (13, 0xD)", Print(L'\r'));
+ EXPECT_EQ("L'\\t' (9)", Print(L'\t'));
+ EXPECT_EQ("L'\\v' (11, 0xB)", Print(L'\v'));
+ EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F'));
+ EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF'));
+ EXPECT_EQ("L' ' (32, 0x20)", Print(L' '));
+ EXPECT_EQ("L'a' (97, 0x61)", Print(L'a'));
+ EXPECT_EQ("L'\\x576' (1398)", Print(static_cast<wchar_t>(0x576)));
+ EXPECT_EQ("L'\\xC74D' (51021)", Print(static_cast<wchar_t>(0xC74D)));
+}
+
+// Test that Int64 provides more storage than wchar_t.
+TEST(PrintTypeSizeTest, Wchar_t)
+{
+ EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64));
+}
+
+// Various integer types.
+TEST(PrintBuiltInTypeTest, Integer)
+{
+ EXPECT_EQ("'\\xFF' (255)", Print(static_cast<unsigned char>(255))); // uint8
+ EXPECT_EQ("'\\x80' (-128)", Print(static_cast<signed char>(-128))); // int8
+ EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16
+ EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16
+ EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32
+ EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32
+ EXPECT_EQ("18446744073709551615",
+ Print(static_cast<testing::internal::UInt64>(-1))); // uint64
+ EXPECT_EQ("-9223372036854775808",
+ Print(static_cast<testing::internal::Int64>(1) << 63)); // int64
+}
+
+// Size types.
+TEST(PrintBuiltInTypeTest, Size_t)
+{
+ EXPECT_EQ("1", Print(sizeof('a'))); // size_t.
+#if !GTEST_OS_WINDOWS
+ // Windows has no ssize_t type.
+ EXPECT_EQ("-2", Print(static_cast<ssize_t>(-2))); // ssize_t.
+#endif // !GTEST_OS_WINDOWS
+}
+
+// Floating-points.
+TEST(PrintBuiltInTypeTest, FloatingPoints)
+{
+ EXPECT_EQ("1.5", Print(1.5f)); // float
+ EXPECT_EQ("-2.5", Print(-2.5)); // double
+}
+
+// Since ::std::stringstream::operator<<(const void *) formats the pointer
+// output differently with different compilers, we have to create the expected
+// output first and use it as our expectation.
+static string PrintPointer(const void* p)
+{
+ ::std::stringstream expected_result_stream;
+ expected_result_stream << p;
+ return expected_result_stream.str();
+}
+
+// Tests printing C strings.
+
+// const char*.
+TEST(PrintCStringTest, Const)
+{
+ const char* p = "World";
+ EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p));
+}
+
+// char*.
+TEST(PrintCStringTest, NonConst)
+{
+ char p[] = "Hi";
+ EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"",
+ Print(static_cast<char*>(p)));
+}
+
+// NULL C string.
+TEST(PrintCStringTest, Null)
+{
+ const char* p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// Tests that C strings are escaped properly.
+TEST(PrintCStringTest, EscapesProperly)
+{
+ const char* p = "'\"?\\\a\b\f\n\r\t\v\x7F\xFF a";
+ EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"?\\\\\\a\\b\\f"
+ "\\n\\r\\t\\v\\x7F\\xFF a\"",
+ Print(p));
+}
+
+
+
+// MSVC compiler can be configured to define whar_t as a typedef
+// of unsigned short. Defining an overload for const wchar_t* in that case
+// would cause pointers to unsigned shorts be printed as wide strings,
+// possibly accessing more memory than intended and causing invalid
+// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
+// wchar_t is implemented as a native type.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+
+// const wchar_t*.
+TEST(PrintWideCStringTest, Const)
+{
+ const wchar_t* p = L"World";
+ EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p));
+}
+
+// wchar_t*.
+TEST(PrintWideCStringTest, NonConst)
+{
+ wchar_t p[] = L"Hi";
+ EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"",
+ Print(static_cast<wchar_t*>(p)));
+}
+
+// NULL wide C string.
+TEST(PrintWideCStringTest, Null)
+{
+ const wchar_t* p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// Tests that wide C strings are escaped properly.
+TEST(PrintWideCStringTest, EscapesProperly)
+{
+ const wchar_t s[] = {'\'', '"', '?', '\\', '\a', '\b', '\f', '\n', '\r',
+ '\t', '\v', 0xD3, 0x576, 0x8D3, 0xC74D, ' ', 'a', '\0'
+ };
+ EXPECT_EQ(PrintPointer(s) + " pointing to L\"'\\\"?\\\\\\a\\b\\f"
+ "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"",
+ Print(static_cast<const wchar_t*>(s)));
+}
+#endif // native wchar_t
+
+// Tests printing pointers to other char types.
+
+// signed char*.
+TEST(PrintCharPointerTest, SignedChar)
+{
+ signed char* p = reinterpret_cast<signed char*>(0x1234);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// const signed char*.
+TEST(PrintCharPointerTest, ConstSignedChar)
+{
+ signed char* p = reinterpret_cast<signed char*>(0x1234);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// unsigned char*.
+TEST(PrintCharPointerTest, UnsignedChar)
+{
+ unsigned char* p = reinterpret_cast<unsigned char*>(0x1234);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// const unsigned char*.
+TEST(PrintCharPointerTest, ConstUnsignedChar)
+{
+ const unsigned char* p = reinterpret_cast<const unsigned char*>(0x1234);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// Tests printing pointers to simple, built-in types.
+
+// bool*.
+TEST(PrintPointerToBuiltInTypeTest, Bool)
+{
+ bool* p = reinterpret_cast<bool*>(0xABCD);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// void*.
+TEST(PrintPointerToBuiltInTypeTest, Void)
+{
+ void* p = reinterpret_cast<void*>(0xABCD);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// const void*.
+TEST(PrintPointerToBuiltInTypeTest, ConstVoid)
+{
+ const void* p = reinterpret_cast<const void*>(0xABCD);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// Tests printing pointers to pointers.
+TEST(PrintPointerToPointerTest, IntPointerPointer)
+{
+ int** p = reinterpret_cast<int**>(0xABCD);
+ EXPECT_EQ(PrintPointer(p), Print(p));
+ p = NULL;
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// Tests printing (non-member) function pointers.
+
+void MyFunction(int /* n */) {}
+
+TEST(PrintPointerTest, NonMemberFunctionPointer)
+{
+ // We cannot directly cast &MyFunction to const void* because the
+ // standard disallows casting between pointers to functions and
+ // pointers to objects, and some compilers (e.g. GCC 3.4) enforce
+ // this limitation.
+ EXPECT_EQ(
+ PrintPointer(reinterpret_cast<const void*>(
+ reinterpret_cast<internal::BiggestInt>(&MyFunction))),
+ Print(&MyFunction));
+ int (*p)(bool) = NULL; // NOLINT
+ EXPECT_EQ("NULL", Print(p));
+}
+
+// An assertion predicate determining whether a one string is a prefix for
+// another.
+template <typename StringType>
+AssertionResult HasPrefix(const StringType& str, const StringType& prefix)
+{
+ if (str.find(prefix, 0) == 0)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(prefix[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure()
+ << begin_string_quote << prefix << "\" is not a prefix of "
+ << begin_string_quote << str << "\"\n";
+}
+
+// Tests printing member variable pointers. Although they are called
+// pointers, they don't point to a location in the address space.
+// Their representation is implementation-defined. Thus they will be
+// printed as raw bytes.
+
+struct Foo {
+ public:
+ virtual ~Foo() {}
+ int MyMethod(char x) { return x + 1; }
+ virtual char MyVirtualMethod(int /* n */) { return 'a'; }
+
+ int value;
+};
+
+TEST(PrintPointerTest, MemberVariablePointer)
+{
+ EXPECT_TRUE(HasPrefix(Print(&Foo::value),
+ Print(sizeof(&Foo::value)) + "-byte object "));
+ int (Foo::*p) = NULL; // NOLINT
+ EXPECT_TRUE(HasPrefix(Print(p),
+ Print(sizeof(p)) + "-byte object "));
+}
+
+// Tests printing member function pointers. Although they are called
+// pointers, they don't point to a location in the address space.
+// Their representation is implementation-defined. Thus they will be
+// printed as raw bytes.
+TEST(PrintPointerTest, MemberFunctionPointer)
+{
+ EXPECT_TRUE(HasPrefix(Print(&Foo::MyMethod),
+ Print(sizeof(&Foo::MyMethod)) + "-byte object "));
+ EXPECT_TRUE(
+ HasPrefix(Print(&Foo::MyVirtualMethod),
+ Print(sizeof((&Foo::MyVirtualMethod))) + "-byte object "));
+ int (Foo::*p)(char) = NULL; // NOLINT
+ EXPECT_TRUE(HasPrefix(Print(p),
+ Print(sizeof(p)) + "-byte object "));
+}
+
+// Tests printing C arrays.
+
+// The difference between this and Print() is that it ensures that the
+// argument is a reference to an array.
+template <typename T, size_t N>
+string PrintArrayHelper(T(&a)[N])
+{
+ return Print(a);
+}
+
+// One-dimensional array.
+TEST(PrintArrayTest, OneDimensionalArray)
+{
+ int a[5] = { 1, 2, 3, 4, 5 };
+ EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a));
+}
+
+// Two-dimensional array.
+TEST(PrintArrayTest, TwoDimensionalArray)
+{
+ int a[2][5] = {
+ { 1, 2, 3, 4, 5 },
+ { 6, 7, 8, 9, 0 }
+ };
+ EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a));
+}
+
+// Array of const elements.
+TEST(PrintArrayTest, ConstArray)
+{
+ const bool a[1] = { false };
+ EXPECT_EQ("{ false }", PrintArrayHelper(a));
+}
+
+// char array without terminating NUL.
+TEST(PrintArrayTest, CharArrayWithNoTerminatingNul)
+{
+ // Array a contains '\0' in the middle and doesn't end with '\0'.
+ char a[] = { 'H', '\0', 'i' };
+ EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
+}
+
+// const char array with terminating NUL.
+TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul)
+{
+ const char a[] = "\0Hi";
+ EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a));
+}
+
+// const wchar_t array without terminating NUL.
+TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul)
+{
+ // Array a contains '\0' in the middle and doesn't end with '\0'.
+ const wchar_t a[] = { L'H', L'\0', L'i' };
+ EXPECT_EQ("L\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
+}
+
+// wchar_t array with terminating NUL.
+TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul)
+{
+ const wchar_t a[] = L"\0Hi";
+ EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a));
+}
+
+// Array of objects.
+TEST(PrintArrayTest, ObjectArray)
+{
+ string a[3] = { "Hi", "Hello", "Ni hao" };
+ EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a));
+}
+
+// Array with many elements.
+TEST(PrintArrayTest, BigArray)
+{
+ int a[100] = { 1, 2, 3 };
+ EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }",
+ PrintArrayHelper(a));
+}
+
+// Tests printing ::string and ::std::string.
+
+#if GTEST_HAS_GLOBAL_STRING
+// ::string.
+TEST(PrintStringTest, StringInGlobalNamespace)
+{
+ const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a";
+ const ::string str(s, sizeof(s));
+ EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"",
+ Print(str));
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+// ::std::string.
+TEST(PrintStringTest, StringInStdNamespace)
+{
+ const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a";
+ const ::std::string str(s, sizeof(s));
+ EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"",
+ Print(str));
+}
+
+TEST(PrintStringTest, StringAmbiguousHex)
+{
+ // "\x6BANANA" is ambiguous, it can be interpreted as starting with either of:
+ // '\x6', '\x6B', or '\x6BA'.
+
+ // a hex escaping sequence following by a decimal digit
+ EXPECT_EQ("\"0\\x12\" \"3\"", Print(::std::string("0\x12" "3")));
+ // a hex escaping sequence following by a hex digit (lower-case)
+ EXPECT_EQ("\"mm\\x6\" \"bananas\"", Print(::std::string("mm\x6" "bananas")));
+ // a hex escaping sequence following by a hex digit (upper-case)
+ EXPECT_EQ("\"NOM\\x6\" \"BANANA\"", Print(::std::string("NOM\x6" "BANANA")));
+ // a hex escaping sequence following by a non-xdigit
+ EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!")));
+}
+
+// Tests printing ::wstring and ::std::wstring.
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// ::wstring.
+TEST(PrintWideStringTest, StringInGlobalNamespace)
+{
+ const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a";
+ const ::wstring str(s, sizeof(s)/sizeof(wchar_t));
+ EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v"
+ "\\xD3\\x576\\x8D3\\xC74D a\\0\"",
+ Print(str));
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+// ::std::wstring.
+TEST(PrintWideStringTest, StringInStdNamespace)
+{
+ const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a";
+ const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t));
+ EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v"
+ "\\xD3\\x576\\x8D3\\xC74D a\\0\"",
+ Print(str));
+}
+
+TEST(PrintWideStringTest, StringAmbiguousHex)
+{
+ // same for wide strings.
+ EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" L"3")));
+ EXPECT_EQ("L\"mm\\x6\" L\"bananas\"",
+ Print(::std::wstring(L"mm\x6" L"bananas")));
+ EXPECT_EQ("L\"NOM\\x6\" L\"BANANA\"",
+ Print(::std::wstring(L"NOM\x6" L"BANANA")));
+ EXPECT_EQ("L\"!\\x5-!\"", Print(::std::wstring(L"!\x5-!")));
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+// Tests printing types that support generic streaming (i.e. streaming
+// to std::basic_ostream<Char, CharTraits> for any valid Char and
+// CharTraits types).
+
+// Tests printing a non-template type that supports generic streaming.
+
+class AllowsGenericStreaming {};
+
+template <typename Char, typename CharTraits>
+std::basic_ostream<Char, CharTraits>& operator<<(
+ std::basic_ostream<Char, CharTraits>& os,
+ const AllowsGenericStreaming& /* a */)
+{
+ return os << "AllowsGenericStreaming";
+}
+
+TEST(PrintTypeWithGenericStreamingTest, NonTemplateType)
+{
+ AllowsGenericStreaming a;
+ EXPECT_EQ("AllowsGenericStreaming", Print(a));
+}
+
+// Tests printing a template type that supports generic streaming.
+
+template <typename T>
+class AllowsGenericStreamingTemplate {};
+
+template <typename Char, typename CharTraits, typename T>
+std::basic_ostream<Char, CharTraits>& operator<<(
+ std::basic_ostream<Char, CharTraits>& os,
+ const AllowsGenericStreamingTemplate<T>& /* a */)
+{
+ return os << "AllowsGenericStreamingTemplate";
+}
+
+TEST(PrintTypeWithGenericStreamingTest, TemplateType)
+{
+ AllowsGenericStreamingTemplate<int> a;
+ EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a));
+}
+
+// Tests printing a type that supports generic streaming and can be
+// implicitly converted to another printable type.
+
+template <typename T>
+class AllowsGenericStreamingAndImplicitConversionTemplate
+{
+ public:
+ operator bool() const { return false; }
+};
+
+template <typename Char, typename CharTraits, typename T>
+std::basic_ostream<Char, CharTraits>& operator<<(
+ std::basic_ostream<Char, CharTraits>& os,
+ const AllowsGenericStreamingAndImplicitConversionTemplate<T>& /* a */)
+{
+ return os << "AllowsGenericStreamingAndImplicitConversionTemplate";
+}
+
+TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible)
+{
+ AllowsGenericStreamingAndImplicitConversionTemplate<int> a;
+ EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a));
+}
+
+#if GTEST_HAS_STRING_PIECE_
+
+// Tests printing StringPiece.
+
+TEST(PrintStringPieceTest, SimpleStringPiece)
+{
+ const StringPiece sp = "Hello";
+ EXPECT_EQ("\"Hello\"", Print(sp));
+}
+
+TEST(PrintStringPieceTest, UnprintableCharacters)
+{
+ const char str[] = "NUL (\0) and \r\t";
+ const StringPiece sp(str, sizeof(str) - 1);
+ EXPECT_EQ("\"NUL (\\0) and \\r\\t\"", Print(sp));
+}
+
+#endif // GTEST_HAS_STRING_PIECE_
+
+// Tests printing STL containers.
+
+TEST(PrintStlContainerTest, EmptyDeque)
+{
+ deque<char> empty;
+ EXPECT_EQ("{}", Print(empty));
+}
+
+TEST(PrintStlContainerTest, NonEmptyDeque)
+{
+ deque<int> non_empty;
+ non_empty.push_back(1);
+ non_empty.push_back(3);
+ EXPECT_EQ("{ 1, 3 }", Print(non_empty));
+}
+
+#if GTEST_HAS_HASH_MAP_
+
+TEST(PrintStlContainerTest, OneElementHashMap)
+{
+ hash_map<int, char> map1;
+ map1[1] = 'a';
+ EXPECT_EQ("{ (1, 'a' (97, 0x61)) }", Print(map1));
+}
+
+TEST(PrintStlContainerTest, HashMultiMap)
+{
+ hash_multimap<int, bool> map1;
+ map1.insert(make_pair(5, true));
+ map1.insert(make_pair(5, false));
+
+ // Elements of hash_multimap can be printed in any order.
+ const string result = Print(map1);
+ EXPECT_TRUE(result == "{ (5, true), (5, false) }" ||
+ result == "{ (5, false), (5, true) }")
+ << " where Print(map1) returns \"" << result << "\".";
+}
+
+#endif // GTEST_HAS_HASH_MAP_
+
+#if GTEST_HAS_HASH_SET_
+
+TEST(PrintStlContainerTest, HashSet)
+{
+ hash_set<string> set1;
+ set1.insert("hello");
+ EXPECT_EQ("{ \"hello\" }", Print(set1));
+}
+
+TEST(PrintStlContainerTest, HashMultiSet)
+{
+ const int kSize = 5;
+ int a[kSize] = { 1, 1, 2, 5, 1 };
+ hash_multiset<int> set1(a, a + kSize);
+
+ // Elements of hash_multiset can be printed in any order.
+ const string result = Print(set1);
+ const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit.
+
+ // Verifies the result matches the expected pattern; also extracts
+ // the numbers in the result.
+ ASSERT_EQ(expected_pattern.length(), result.length());
+ std::vector<int> numbers;
+ for (size_t i = 0; i != result.length(); i++) {
+ if (expected_pattern[i] == 'd') {
+ ASSERT_NE(isdigit(static_cast<unsigned char>(result[i])), 0);
+ numbers.push_back(result[i] - '0');
+ } else {
+ EXPECT_EQ(expected_pattern[i], result[i]) << " where result is "
+ << result;
+ }
+ }
+
+ // Makes sure the result contains the right numbers.
+ std::sort(numbers.begin(), numbers.end());
+ std::sort(a, a + kSize);
+ EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin()));
+}
+
+#endif // GTEST_HAS_HASH_SET_
+
+TEST(PrintStlContainerTest, List)
+{
+ const string a[] = {
+ "hello",
+ "world"
+ };
+ const list<string> strings(a, a + 2);
+ EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings));
+}
+
+TEST(PrintStlContainerTest, Map)
+{
+ map<int, bool> map1;
+ map1[1] = true;
+ map1[5] = false;
+ map1[3] = true;
+ EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1));
+}
+
+TEST(PrintStlContainerTest, MultiMap)
+{
+ multimap<bool, int> map1;
+ // The make_pair template function would deduce the type as
+ // pair<bool, int> here, and since the key part in a multimap has to
+ // be constant, without a templated ctor in the pair class (as in
+ // libCstd on Solaris), make_pair call would fail to compile as no
+ // implicit conversion is found. Thus explicit typename is used
+ // here instead.
+ map1.insert(pair<const bool, int>(true, 0));
+ map1.insert(pair<const bool, int>(true, 1));
+ map1.insert(pair<const bool, int>(false, 2));
+ EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1));
+}
+
+TEST(PrintStlContainerTest, Set)
+{
+ const unsigned int a[] = { 3, 0, 5 };
+ set<unsigned int> set1(a, a + 3);
+ EXPECT_EQ("{ 0, 3, 5 }", Print(set1));
+}
+
+TEST(PrintStlContainerTest, MultiSet)
+{
+ const int a[] = { 1, 1, 2, 5, 1 };
+ multiset<int> set1(a, a + 5);
+ EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1));
+}
+
+TEST(PrintStlContainerTest, Pair)
+{
+ pair<const bool, int> p(true, 5);
+ EXPECT_EQ("(true, 5)", Print(p));
+}
+
+TEST(PrintStlContainerTest, Vector)
+{
+ vector<int> v;
+ v.push_back(1);
+ v.push_back(2);
+ EXPECT_EQ("{ 1, 2 }", Print(v));
+}
+
+TEST(PrintStlContainerTest, LongSequence)
+{
+ const int a[100] = { 1, 2, 3 };
+ const vector<int> v(a, a + 100);
+ EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "
+ "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v));
+}
+
+TEST(PrintStlContainerTest, NestedContainer)
+{
+ const int a1[] = { 1, 2 };
+ const int a2[] = { 3, 4, 5 };
+ const list<int> l1(a1, a1 + 2);
+ const list<int> l2(a2, a2 + 3);
+
+ vector<list<int> > v;
+ v.push_back(l1);
+ v.push_back(l2);
+ EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v));
+}
+
+TEST(PrintStlContainerTest, OneDimensionalNativeArray)
+{
+ const int a[3] = { 1, 2, 3 };
+ NativeArray<int> b(a, 3, kReference);
+ EXPECT_EQ("{ 1, 2, 3 }", Print(b));
+}
+
+TEST(PrintStlContainerTest, TwoDimensionalNativeArray)
+{
+ const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
+ NativeArray<int[3]> b(a, 2, kReference);
+ EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b));
+}
+
+// Tests that a class named iterator isn't treated as a container.
+
+struct iterator {
+ char x;
+};
+
+TEST(PrintStlContainerTest, Iterator)
+{
+ iterator it = {};
+ EXPECT_EQ("1-byte object <00>", Print(it));
+}
+
+// Tests that a class named const_iterator isn't treated as a container.
+
+struct const_iterator {
+ char x;
+};
+
+TEST(PrintStlContainerTest, ConstIterator)
+{
+ const_iterator it = {};
+ EXPECT_EQ("1-byte object <00>", Print(it));
+}
+
+#if GTEST_HAS_TR1_TUPLE
+// Tests printing tuples.
+
+// Tuples of various arities.
+TEST(PrintTupleTest, VariousSizes)
+{
+ tuple<> t0;
+ EXPECT_EQ("()", Print(t0));
+
+ tuple<int> t1(5);
+ EXPECT_EQ("(5)", Print(t1));
+
+ tuple<char, bool> t2('a', true);
+ EXPECT_EQ("('a' (97, 0x61), true)", Print(t2));
+
+ tuple<bool, int, int> t3(false, 2, 3);
+ EXPECT_EQ("(false, 2, 3)", Print(t3));
+
+ tuple<bool, int, int, int> t4(false, 2, 3, 4);
+ EXPECT_EQ("(false, 2, 3, 4)", Print(t4));
+
+ tuple<bool, int, int, int, bool> t5(false, 2, 3, 4, true);
+ EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5));
+
+ tuple<bool, int, int, int, bool, int> t6(false, 2, 3, 4, true, 6);
+ EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6));
+
+ tuple<bool, int, int, int, bool, int, int> t7(false, 2, 3, 4, true, 6, 7);
+ EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7));
+
+ tuple<bool, int, int, int, bool, int, int, bool> t8(
+ false, 2, 3, 4, true, 6, 7, true);
+ EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8));
+
+ tuple<bool, int, int, int, bool, int, int, bool, int> t9(
+ false, 2, 3, 4, true, 6, 7, true, 9);
+ EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9));
+
+ const char* const str = "8";
+ // VC++ 2010's implementation of tuple of C++0x is deficient, requiring
+ // an explicit type cast of NULL to be used.
+ tuple<bool, char, short, testing::internal::Int32, // NOLINT
+ testing::internal::Int64, float, double, const char*, void*, string>
+ t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str,
+ ImplicitCast_<void*>(NULL), "10");
+ EXPECT_EQ("(false, 'a' (97, 0x61), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) +
+ " pointing to \"8\", NULL, \"10\")",
+ Print(t10));
+}
+
+// Nested tuples.
+TEST(PrintTupleTest, NestedTuple)
+{
+ tuple<tuple<int, bool>, char> nested(make_tuple(5, true), 'a');
+ EXPECT_EQ("((5, true), 'a' (97, 0x61))", Print(nested));
+}
+
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Tests printing user-defined unprintable types.
+
+// Unprintable types in the global namespace.
+TEST(PrintUnprintableTypeTest, InGlobalNamespace)
+{
+ EXPECT_EQ("1-byte object <00>",
+ Print(UnprintableTemplateInGlobal<char>()));
+}
+
+// Unprintable types in a user namespace.
+TEST(PrintUnprintableTypeTest, InUserNamespace)
+{
+ EXPECT_EQ("16-byte object <EF-12 00-00 34-AB 00-00 00-00 00-00 00-00 00-00>",
+ Print(::foo::UnprintableInFoo()));
+}
+
+// Unprintable types are that too big to be printed completely.
+
+struct Big {
+ Big() { memset(array, 0, sizeof(array)); }
+ char array[257];
+};
+
+TEST(PrintUnpritableTypeTest, BigObject)
+{
+ EXPECT_EQ("257-byte object <00-00 00-00 00-00 00-00 00-00 00-00 "
+ "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+ "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+ "00-00 00-00 00-00 00-00 00-00 00-00 ... 00-00 00-00 00-00 "
+ "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+ "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+ "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00>",
+ Print(Big()));
+}
+
+// Tests printing user-defined streamable types.
+
+// Streamable types in the global namespace.
+TEST(PrintStreamableTypeTest, InGlobalNamespace)
+{
+ StreamableInGlobal x;
+ EXPECT_EQ("StreamableInGlobal", Print(x));
+ EXPECT_EQ("StreamableInGlobal*", Print(&x));
+}
+
+// Printable template types in a user namespace.
+TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace)
+{
+ EXPECT_EQ("StreamableTemplateInFoo: 0",
+ Print(::foo::StreamableTemplateInFoo<int>()));
+}
+
+// Tests printing user-defined types that have a PrintTo() function.
+TEST(PrintPrintableTypeTest, InUserNamespace)
+{
+ EXPECT_EQ("PrintableViaPrintTo: 0",
+ Print(::foo::PrintableViaPrintTo()));
+}
+
+// Tests printing a pointer to a user-defined type that has a <<
+// operator for its pointer.
+TEST(PrintPrintableTypeTest, PointerInUserNamespace)
+{
+ ::foo::PointerPrintable x;
+ EXPECT_EQ("PointerPrintable*", Print(&x));
+}
+
+// Tests printing user-defined class template that have a PrintTo() function.
+TEST(PrintPrintableTypeTest, TemplateInUserNamespace)
+{
+ EXPECT_EQ("PrintableViaPrintToTemplate: 5",
+ Print(::foo::PrintableViaPrintToTemplate<int>(5)));
+}
+
+#if GTEST_HAS_PROTOBUF_
+
+// Tests printing a protocol message.
+TEST(PrintProtocolMessageTest, PrintsShortDebugString)
+{
+ testing::internal::TestMessage msg;
+ msg.set_member("yes");
+ EXPECT_EQ("<member:\"yes\">", Print(msg));
+}
+
+// Tests printing a short proto2 message.
+TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort)
+{
+ testing::internal::FooMessage msg;
+ msg.set_int_field(2);
+ msg.set_string_field("hello");
+ EXPECT_PRED2(RE::FullMatch, Print(msg),
+ "<int_field:\\s*2\\s+string_field:\\s*\"hello\">");
+}
+
+// Tests printing a long proto2 message.
+TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong)
+{
+ testing::internal::FooMessage msg;
+ msg.set_int_field(2);
+ msg.set_string_field("hello");
+ msg.add_names("peter");
+ msg.add_names("paul");
+ msg.add_names("mary");
+ EXPECT_PRED2(RE::FullMatch, Print(msg),
+ "<\n"
+ "int_field:\\s*2\n"
+ "string_field:\\s*\"hello\"\n"
+ "names:\\s*\"peter\"\n"
+ "names:\\s*\"paul\"\n"
+ "names:\\s*\"mary\"\n"
+ ">");
+}
+
+#endif // GTEST_HAS_PROTOBUF_
+
+// Tests that the universal printer prints both the address and the
+// value of a reference.
+TEST(PrintReferenceTest, PrintsAddressAndValue)
+{
+ int n = 5;
+ EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n));
+
+ int a[2][3] = {
+ { 0, 1, 2 },
+ { 3, 4, 5 }
+ };
+ EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }",
+ PrintByRef(a));
+
+ const ::foo::UnprintableInFoo x;
+ EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object "
+ "<EF-12 00-00 34-AB 00-00 00-00 00-00 00-00 00-00>",
+ PrintByRef(x));
+}
+
+// Tests that the universal printer prints a function pointer passed by
+// reference.
+TEST(PrintReferenceTest, HandlesFunctionPointer)
+{
+ void (*fp)(int n) = &MyFunction;
+ const string fp_pointer_string =
+ PrintPointer(reinterpret_cast<const void*>(&fp));
+ // We cannot directly cast &MyFunction to const void* because the
+ // standard disallows casting between pointers to functions and
+ // pointers to objects, and some compilers (e.g. GCC 3.4) enforce
+ // this limitation.
+ const string fp_string = PrintPointer(reinterpret_cast<const void*>(
+ reinterpret_cast<internal::BiggestInt>(fp)));
+ EXPECT_EQ("@" + fp_pointer_string + " " + fp_string,
+ PrintByRef(fp));
+}
+
+// Tests that the universal printer prints a member function pointer
+// passed by reference.
+TEST(PrintReferenceTest, HandlesMemberFunctionPointer)
+{
+ int (Foo::*p)(char ch) = &Foo::MyMethod;
+ EXPECT_TRUE(HasPrefix(
+ PrintByRef(p),
+ "@" + PrintPointer(reinterpret_cast<const void*>(&p)) + " " +
+ Print(sizeof(p)) + "-byte object "));
+
+ char(Foo::*p2)(int n) = &Foo::MyVirtualMethod;
+ EXPECT_TRUE(HasPrefix(
+ PrintByRef(p2),
+ "@" + PrintPointer(reinterpret_cast<const void*>(&p2)) + " " +
+ Print(sizeof(p2)) + "-byte object "));
+}
+
+// Tests that the universal printer prints a member variable pointer
+// passed by reference.
+TEST(PrintReferenceTest, HandlesMemberVariablePointer)
+{
+ int (Foo::*p) = &Foo::value; // NOLINT
+ EXPECT_TRUE(HasPrefix(
+ PrintByRef(p),
+ "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object "));
+}
+
+// Tests that FormatForComparisonFailureMessage(), which is used to print
+// an operand in a comparison assertion (e.g. ASSERT_EQ) when the assertion
+// fails, formats the operand in the desired way.
+
+// scalar
+TEST(FormatForComparisonFailureMessageTest, WorksForScalar)
+{
+ EXPECT_STREQ("123",
+ FormatForComparisonFailureMessage(123, 124).c_str());
+}
+
+// non-char pointer
+TEST(FormatForComparisonFailureMessageTest, WorksForNonCharPointer)
+{
+ int n = 0;
+ EXPECT_EQ(PrintPointer(&n),
+ FormatForComparisonFailureMessage(&n, &n).c_str());
+}
+
+// non-char array
+TEST(FormatForComparisonFailureMessageTest, FormatsNonCharArrayAsPointer)
+{
+ // In expression 'array == x', 'array' is compared by pointer.
+ // Therefore we want to print an array operand as a pointer.
+ int n[] = { 1, 2, 3 };
+ EXPECT_EQ(PrintPointer(n),
+ FormatForComparisonFailureMessage(n, n).c_str());
+}
+
+// Tests formatting a char pointer when it's compared with another pointer.
+// In this case we want to print it as a raw pointer, as the comparision is by
+// pointer.
+
+// char pointer vs pointer
+TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsPointer)
+{
+ // In expression 'p == x', where 'p' and 'x' are (const or not) char
+ // pointers, the operands are compared by pointer. Therefore we
+ // want to print 'p' as a pointer instead of a C string (we don't
+ // even know if it's supposed to point to a valid C string).
+
+ // const char*
+ const char* s = "hello";
+ EXPECT_EQ(PrintPointer(s),
+ FormatForComparisonFailureMessage(s, s).c_str());
+
+ // char*
+ char ch = 'a';
+ EXPECT_EQ(PrintPointer(&ch),
+ FormatForComparisonFailureMessage(&ch, &ch).c_str());
+}
+
+// wchar_t pointer vs pointer
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsPointer)
+{
+ // In expression 'p == x', where 'p' and 'x' are (const or not) char
+ // pointers, the operands are compared by pointer. Therefore we
+ // want to print 'p' as a pointer instead of a wide C string (we don't
+ // even know if it's supposed to point to a valid wide C string).
+
+ // const wchar_t*
+ const wchar_t* s = L"hello";
+ EXPECT_EQ(PrintPointer(s),
+ FormatForComparisonFailureMessage(s, s).c_str());
+
+ // wchar_t*
+ wchar_t ch = L'a';
+ EXPECT_EQ(PrintPointer(&ch),
+ FormatForComparisonFailureMessage(&ch, &ch).c_str());
+}
+
+// Tests formatting a char pointer when it's compared to a string object.
+// In this case we want to print the char pointer as a C string.
+
+#if GTEST_HAS_GLOBAL_STRING
+// char pointer vs ::string
+TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsString)
+{
+ const char* s = "hello \"world";
+ EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(s, ::string()).c_str());
+
+ // char*
+ char str[] = "hi\1";
+ char* p = str;
+ EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(p, ::string()).c_str());
+}
+#endif
+
+// char pointer vs std::string
+TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsStdString)
+{
+ const char* s = "hello \"world";
+ EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(s, ::std::string()).c_str());
+
+ // char*
+ char str[] = "hi\1";
+ char* p = str;
+ EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(p, ::std::string()).c_str());
+}
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// wchar_t pointer vs ::wstring
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsWString)
+{
+ const wchar_t* s = L"hi \"world";
+ EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(s, ::wstring()).c_str());
+
+ // wchar_t*
+ wchar_t str[] = L"hi\1";
+ wchar_t* p = str;
+ EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(p, ::wstring()).c_str());
+}
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+// wchar_t pointer vs std::wstring
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsStdWString)
+{
+ const wchar_t* s = L"hi \"world";
+ EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(s, ::std::wstring()).c_str());
+
+ // wchar_t*
+ wchar_t str[] = L"hi\1";
+ wchar_t* p = str;
+ EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped.
+ FormatForComparisonFailureMessage(p, ::std::wstring()).c_str());
+}
+#endif
+
+// Tests formatting a char array when it's compared with a pointer or array.
+// In this case we want to print the array as a row pointer, as the comparison
+// is by pointer.
+
+// char array vs pointer
+TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsPointer)
+{
+ char str[] = "hi \"world\"";
+ char* p = NULL;
+ EXPECT_EQ(PrintPointer(str),
+ FormatForComparisonFailureMessage(str, p).c_str());
+}
+
+// char array vs char array
+TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsCharArray)
+{
+ const char str[] = "hi \"world\"";
+ EXPECT_EQ(PrintPointer(str),
+ FormatForComparisonFailureMessage(str, str).c_str());
+}
+
+// wchar_t array vs pointer
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsPointer)
+{
+ wchar_t str[] = L"hi \"world\"";
+ wchar_t* p = NULL;
+ EXPECT_EQ(PrintPointer(str),
+ FormatForComparisonFailureMessage(str, p).c_str());
+}
+
+// wchar_t array vs wchar_t array
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWCharArray)
+{
+ const wchar_t str[] = L"hi \"world\"";
+ EXPECT_EQ(PrintPointer(str),
+ FormatForComparisonFailureMessage(str, str).c_str());
+}
+
+// Tests formatting a char array when it's compared with a string object.
+// In this case we want to print the array as a C string.
+
+#if GTEST_HAS_GLOBAL_STRING
+// char array vs string
+TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsString)
+{
+ const char str[] = "hi \"w\0rld\"";
+ EXPECT_STREQ("\"hi \\\"w\"", // The content should be escaped.
+ // Embedded NUL terminates the string.
+ FormatForComparisonFailureMessage(str, ::string()).c_str());
+}
+#endif
+
+// char array vs std::string
+TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsStdString)
+{
+ const char str[] = "hi \"world\"";
+ EXPECT_STREQ("\"hi \\\"world\\\"\"", // The content should be escaped.
+ FormatForComparisonFailureMessage(str, ::std::string()).c_str());
+}
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// wchar_t array vs wstring
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWString)
+{
+ const wchar_t str[] = L"hi \"world\"";
+ EXPECT_STREQ("L\"hi \\\"world\\\"\"", // The content should be escaped.
+ FormatForComparisonFailureMessage(str, ::wstring()).c_str());
+}
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+// wchar_t array vs std::wstring
+TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsStdWString)
+{
+ const wchar_t str[] = L"hi \"w\0rld\"";
+ EXPECT_STREQ(
+ "L\"hi \\\"w\"", // The content should be escaped.
+ // Embedded NUL terminates the string.
+ FormatForComparisonFailureMessage(str, ::std::wstring()).c_str());
+}
+#endif
+
+// Useful for testing PrintToString(). We cannot use EXPECT_EQ()
+// there as its implementation uses PrintToString(). The caller must
+// ensure that 'value' has no side effect.
+#define EXPECT_PRINT_TO_STRING_(value, expected_string) \
+ EXPECT_TRUE(PrintToString(value) == (expected_string)) \
+ << " where " #value " prints as " << (PrintToString(value))
+
+TEST(PrintToStringTest, WorksForScalar)
+{
+ EXPECT_PRINT_TO_STRING_(123, "123");
+}
+
+TEST(PrintToStringTest, WorksForPointerToConstChar)
+{
+ const char* p = "hello";
+ EXPECT_PRINT_TO_STRING_(p, "\"hello\"");
+}
+
+TEST(PrintToStringTest, WorksForPointerToNonConstChar)
+{
+ char s[] = "hello";
+ char* p = s;
+ EXPECT_PRINT_TO_STRING_(p, "\"hello\"");
+}
+
+TEST(PrintToStringTest, EscapesForPointerToConstChar)
+{
+ const char* p = "hello\n";
+ EXPECT_PRINT_TO_STRING_(p, "\"hello\\n\"");
+}
+
+TEST(PrintToStringTest, EscapesForPointerToNonConstChar)
+{
+ char s[] = "hello\1";
+ char* p = s;
+ EXPECT_PRINT_TO_STRING_(p, "\"hello\\x1\"");
+}
+
+TEST(PrintToStringTest, WorksForArray)
+{
+ int n[3] = { 1, 2, 3 };
+ EXPECT_PRINT_TO_STRING_(n, "{ 1, 2, 3 }");
+}
+
+TEST(PrintToStringTest, WorksForCharArray)
+{
+ char s[] = "hello";
+ EXPECT_PRINT_TO_STRING_(s, "\"hello\"");
+}
+
+TEST(PrintToStringTest, WorksForCharArrayWithEmbeddedNul)
+{
+ const char str_with_nul[] = "hello\0 world";
+ EXPECT_PRINT_TO_STRING_(str_with_nul, "\"hello\\0 world\"");
+
+ char mutable_str_with_nul[] = "hello\0 world";
+ EXPECT_PRINT_TO_STRING_(mutable_str_with_nul, "\"hello\\0 world\"");
+}
+
+#undef EXPECT_PRINT_TO_STRING_
+
+TEST(UniversalTersePrintTest, WorksForNonReference)
+{
+ ::std::stringstream ss;
+ UniversalTersePrint(123, &ss);
+ EXPECT_EQ("123", ss.str());
+}
+
+TEST(UniversalTersePrintTest, WorksForReference)
+{
+ const int& n = 123;
+ ::std::stringstream ss;
+ UniversalTersePrint(n, &ss);
+ EXPECT_EQ("123", ss.str());
+}
+
+TEST(UniversalTersePrintTest, WorksForCString)
+{
+ const char* s1 = "abc";
+ ::std::stringstream ss1;
+ UniversalTersePrint(s1, &ss1);
+ EXPECT_EQ("\"abc\"", ss1.str());
+
+ char* s2 = const_cast<char*>(s1);
+ ::std::stringstream ss2;
+ UniversalTersePrint(s2, &ss2);
+ EXPECT_EQ("\"abc\"", ss2.str());
+
+ const char* s3 = NULL;
+ ::std::stringstream ss3;
+ UniversalTersePrint(s3, &ss3);
+ EXPECT_EQ("NULL", ss3.str());
+}
+
+TEST(UniversalPrintTest, WorksForNonReference)
+{
+ ::std::stringstream ss;
+ UniversalPrint(123, &ss);
+ EXPECT_EQ("123", ss.str());
+}
+
+TEST(UniversalPrintTest, WorksForReference)
+{
+ const int& n = 123;
+ ::std::stringstream ss;
+ UniversalPrint(n, &ss);
+ EXPECT_EQ("123", ss.str());
+}
+
+TEST(UniversalPrintTest, WorksForCString)
+{
+ const char* s1 = "abc";
+ ::std::stringstream ss1;
+ UniversalPrint(s1, &ss1);
+ EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str()));
+
+ char* s2 = const_cast<char*>(s1);
+ ::std::stringstream ss2;
+ UniversalPrint(s2, &ss2);
+ EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str()));
+
+ const char* s3 = NULL;
+ ::std::stringstream ss3;
+ UniversalPrint(s3, &ss3);
+ EXPECT_EQ("NULL", ss3.str());
+}
+
+TEST(UniversalPrintTest, WorksForCharArray)
+{
+ const char str[] = "\"Line\0 1\"\nLine 2";
+ ::std::stringstream ss1;
+ UniversalPrint(str, &ss1);
+ EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss1.str());
+
+ const char mutable_str[] = "\"Line\0 1\"\nLine 2";
+ ::std::stringstream ss2;
+ UniversalPrint(mutable_str, &ss2);
+ EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss2.str());
+}
+
+#if GTEST_HAS_TR1_TUPLE
+
+TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple)
+{
+ Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple());
+ EXPECT_EQ(0u, result.size());
+}
+
+TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple)
+{
+ Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1));
+ ASSERT_EQ(1u, result.size());
+ EXPECT_EQ("1", result[0]);
+}
+
+TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple)
+{
+ Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a'));
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("1", result[0]);
+ EXPECT_EQ("'a' (97, 0x61)", result[1]);
+}
+
+TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely)
+{
+ const int n = 1;
+ Strings result = UniversalTersePrintTupleFieldsToStrings(
+ tuple<const int&, const char*>(n, "a"));
+ ASSERT_EQ(2u, result.size());
+ EXPECT_EQ("1", result[0]);
+ EXPECT_EQ("\"a\"", result[1]);
+}
+
+#endif // GTEST_HAS_TR1_TUPLE
+
+} // namespace gtest_printers_test
+} // namespace testing
diff --git a/external/gtest-1.6.0/test/gtest-test-part_test.cc b/external/gtest-1.6.0/test/gtest-test-part_test.cc
new file mode 100644
index 0000000..089290b
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-test-part_test.cc
@@ -0,0 +1,225 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule at google.com (Markus Heule)
+//
+
+#include "gtest/gtest-test-part.h"
+
+#include "gtest/gtest.h"
+
+using testing::Message;
+using testing::Test;
+using testing::TestPartResult;
+using testing::TestPartResultArray;
+
+namespace
+{
+
+// Tests the TestPartResult class.
+
+// The test fixture for testing TestPartResult.
+class TestPartResultTest : public Test
+{
+ protected:
+ TestPartResultTest()
+ : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"),
+ r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"),
+ r3_(TestPartResult::kFatalFailure, NULL, -1, "Failure!") {}
+
+ TestPartResult r1_, r2_, r3_;
+};
+
+
+TEST_F(TestPartResultTest, ConstructorWorks)
+{
+ Message message;
+ message << "something is terribly wrong";
+ message << static_cast<const char*>(testing::internal::kStackTraceMarker);
+ message << "some unimportant stack trace";
+
+ const TestPartResult result(TestPartResult::kNonFatalFailure,
+ "some_file.cc",
+ 42,
+ message.GetString().c_str());
+
+ EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type());
+ EXPECT_STREQ("some_file.cc", result.file_name());
+ EXPECT_EQ(42, result.line_number());
+ EXPECT_STREQ(message.GetString().c_str(), result.message());
+ EXPECT_STREQ("something is terribly wrong", result.summary());
+}
+
+TEST_F(TestPartResultTest, ResultAccessorsWork)
+{
+ const TestPartResult success(TestPartResult::kSuccess,
+ "file.cc",
+ 42,
+ "message");
+ EXPECT_TRUE(success.passed());
+ EXPECT_FALSE(success.failed());
+ EXPECT_FALSE(success.nonfatally_failed());
+ EXPECT_FALSE(success.fatally_failed());
+
+ const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure,
+ "file.cc",
+ 42,
+ "message");
+ EXPECT_FALSE(nonfatal_failure.passed());
+ EXPECT_TRUE(nonfatal_failure.failed());
+ EXPECT_TRUE(nonfatal_failure.nonfatally_failed());
+ EXPECT_FALSE(nonfatal_failure.fatally_failed());
+
+ const TestPartResult fatal_failure(TestPartResult::kFatalFailure,
+ "file.cc",
+ 42,
+ "message");
+ EXPECT_FALSE(fatal_failure.passed());
+ EXPECT_TRUE(fatal_failure.failed());
+ EXPECT_FALSE(fatal_failure.nonfatally_failed());
+ EXPECT_TRUE(fatal_failure.fatally_failed());
+}
+
+// Tests TestPartResult::type().
+TEST_F(TestPartResultTest, type)
+{
+ EXPECT_EQ(TestPartResult::kSuccess, r1_.type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type());
+ EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type());
+}
+
+// Tests TestPartResult::file_name().
+TEST_F(TestPartResultTest, file_name)
+{
+ EXPECT_STREQ("foo/bar.cc", r1_.file_name());
+ EXPECT_STREQ(NULL, r3_.file_name());
+}
+
+// Tests TestPartResult::line_number().
+TEST_F(TestPartResultTest, line_number)
+{
+ EXPECT_EQ(10, r1_.line_number());
+ EXPECT_EQ(-1, r2_.line_number());
+}
+
+// Tests TestPartResult::message().
+TEST_F(TestPartResultTest, message)
+{
+ EXPECT_STREQ("Success!", r1_.message());
+}
+
+// Tests TestPartResult::passed().
+TEST_F(TestPartResultTest, Passed)
+{
+ EXPECT_TRUE(r1_.passed());
+ EXPECT_FALSE(r2_.passed());
+ EXPECT_FALSE(r3_.passed());
+}
+
+// Tests TestPartResult::failed().
+TEST_F(TestPartResultTest, Failed)
+{
+ EXPECT_FALSE(r1_.failed());
+ EXPECT_TRUE(r2_.failed());
+ EXPECT_TRUE(r3_.failed());
+}
+
+// Tests TestPartResult::fatally_failed().
+TEST_F(TestPartResultTest, FatallyFailed)
+{
+ EXPECT_FALSE(r1_.fatally_failed());
+ EXPECT_FALSE(r2_.fatally_failed());
+ EXPECT_TRUE(r3_.fatally_failed());
+}
+
+// Tests TestPartResult::nonfatally_failed().
+TEST_F(TestPartResultTest, NonfatallyFailed)
+{
+ EXPECT_FALSE(r1_.nonfatally_failed());
+ EXPECT_TRUE(r2_.nonfatally_failed());
+ EXPECT_FALSE(r3_.nonfatally_failed());
+}
+
+// Tests the TestPartResultArray class.
+
+class TestPartResultArrayTest : public Test
+{
+ protected:
+ TestPartResultArrayTest()
+ : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"),
+ r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {}
+
+ const TestPartResult r1_, r2_;
+};
+
+// Tests that TestPartResultArray initially has size 0.
+TEST_F(TestPartResultArrayTest, InitialSizeIsZero)
+{
+ TestPartResultArray results;
+ EXPECT_EQ(0, results.size());
+}
+
+// Tests that TestPartResultArray contains the given TestPartResult
+// after one Append() operation.
+TEST_F(TestPartResultArrayTest, ContainsGivenResultAfterAppend)
+{
+ TestPartResultArray results;
+ results.Append(r1_);
+ EXPECT_EQ(1, results.size());
+ EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message());
+}
+
+// Tests that TestPartResultArray contains the given TestPartResults
+// after two Append() operations.
+TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends)
+{
+ TestPartResultArray results;
+ results.Append(r1_);
+ results.Append(r2_);
+ EXPECT_EQ(2, results.size());
+ EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message());
+ EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message());
+}
+
+typedef TestPartResultArrayTest TestPartResultArrayDeathTest;
+
+// Tests that the program dies when GetTestPartResult() is called with
+// an invalid index.
+TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound)
+{
+ TestPartResultArray results;
+ results.Append(r1_);
+
+ EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), "");
+ EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), "");
+}
+
+// TODO(mheule at google.com): Add a test for the class HasNewFatalFailureHelper.
+
+} // namespace
diff --git a/external/gtest-1.6.0/test/gtest-tuple_test.cc b/external/gtest-1.6.0/test/gtest-tuple_test.cc
new file mode 100644
index 0000000..728df99
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-tuple_test.cc
@@ -0,0 +1,342 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/internal/gtest-tuple.h"
+#include <utility>
+#include "gtest/gtest.h"
+
+namespace
+{
+
+using ::std::tr1::get;
+using ::std::tr1::make_tuple;
+using ::std::tr1::tuple;
+using ::std::tr1::tuple_element;
+using ::std::tr1::tuple_size;
+using ::testing::StaticAssertTypeEq;
+
+// Tests that tuple_element<K, tuple<T0, T1, ..., TN> >::type returns TK.
+TEST(tuple_element_Test, ReturnsElementType)
+{
+ StaticAssertTypeEq<int, tuple_element<0, tuple<int, char> >::type>();
+ StaticAssertTypeEq<int&, tuple_element<1, tuple<double, int&> >::type>();
+ StaticAssertTypeEq<bool, tuple_element<2, tuple<double, int, bool> >::type>();
+}
+
+// Tests that tuple_size<T>::value gives the number of fields in tuple
+// type T.
+TEST(tuple_size_Test, ReturnsNumberOfFields)
+{
+ EXPECT_EQ(0, +tuple_size<tuple<> >::value);
+ EXPECT_EQ(1, +tuple_size<tuple<void*> >::value);
+ EXPECT_EQ(1, +tuple_size<tuple<char> >::value);
+ EXPECT_EQ(1, +(tuple_size<tuple<tuple<int, double> > >::value));
+ EXPECT_EQ(2, +(tuple_size<tuple<int&, const char> >::value));
+ EXPECT_EQ(3, +(tuple_size<tuple<char*, void, const bool&> >::value));
+}
+
+// Tests comparing a tuple with itself.
+TEST(ComparisonTest, ComparesWithSelf)
+{
+ const tuple<int, char, bool> a(5, 'a', false);
+
+ EXPECT_TRUE(a == a);
+ EXPECT_FALSE(a != a);
+}
+
+// Tests comparing two tuples with the same value.
+TEST(ComparisonTest, ComparesEqualTuples)
+{
+ const tuple<int, bool> a(5, true), b(5, true);
+
+ EXPECT_TRUE(a == b);
+ EXPECT_FALSE(a != b);
+}
+
+// Tests comparing two different tuples that have no reference fields.
+TEST(ComparisonTest, ComparesUnequalTuplesWithoutReferenceFields)
+{
+ typedef tuple<const int, char> FooTuple;
+
+ const FooTuple a(0, 'x');
+ const FooTuple b(1, 'a');
+
+ EXPECT_TRUE(a != b);
+ EXPECT_FALSE(a == b);
+
+ const FooTuple c(1, 'b');
+
+ EXPECT_TRUE(b != c);
+ EXPECT_FALSE(b == c);
+}
+
+// Tests comparing two different tuples that have reference fields.
+TEST(ComparisonTest, ComparesUnequalTuplesWithReferenceFields)
+{
+ typedef tuple<int&, const char&> FooTuple;
+
+ int i = 5;
+ const char ch = 'a';
+ const FooTuple a(i, ch);
+
+ int j = 6;
+ const FooTuple b(j, ch);
+
+ EXPECT_TRUE(a != b);
+ EXPECT_FALSE(a == b);
+
+ j = 5;
+ const char ch2 = 'b';
+ const FooTuple c(j, ch2);
+
+ EXPECT_TRUE(b != c);
+ EXPECT_FALSE(b == c);
+}
+
+// Tests that a tuple field with a reference type is an alias of the
+// variable it's supposed to reference.
+TEST(ReferenceFieldTest, IsAliasOfReferencedVariable)
+{
+ int n = 0;
+ tuple<bool, int&> t(true, n);
+
+ n = 1;
+ EXPECT_EQ(n, get<1>(t))
+ << "Changing a underlying variable should update the reference field.";
+
+ // Makes sure that the implementation doesn't do anything funny with
+ // the & operator for the return type of get<>().
+ EXPECT_EQ(&n, &(get<1>(t)))
+ << "The address of a reference field should equal the address of "
+ << "the underlying variable.";
+
+ get<1>(t) = 2;
+ EXPECT_EQ(2, n)
+ << "Changing a reference field should update the underlying variable.";
+}
+
+// Tests that tuple's default constructor default initializes each field.
+// This test needs to compile without generating warnings.
+TEST(TupleConstructorTest, DefaultConstructorDefaultInitializesEachField)
+{
+ // The TR1 report requires that tuple's default constructor default
+ // initializes each field, even if it's a primitive type. If the
+ // implementation forgets to do this, this test will catch it by
+ // generating warnings about using uninitialized variables (assuming
+ // a decent compiler).
+
+ tuple<> empty;
+
+ tuple<int> a1, b1;
+ b1 = a1;
+ EXPECT_EQ(0, get<0>(b1));
+
+ tuple<int, double> a2, b2;
+ b2 = a2;
+ EXPECT_EQ(0, get<0>(b2));
+ EXPECT_EQ(0.0, get<1>(b2));
+
+ tuple<double, char, bool*> a3, b3;
+ b3 = a3;
+ EXPECT_EQ(0.0, get<0>(b3));
+ EXPECT_EQ('\0', get<1>(b3));
+ EXPECT_TRUE(get<2>(b3) == NULL);
+
+ tuple<int, int, int, int, int, int, int, int, int, int> a10, b10;
+ b10 = a10;
+ EXPECT_EQ(0, get<0>(b10));
+ EXPECT_EQ(0, get<1>(b10));
+ EXPECT_EQ(0, get<2>(b10));
+ EXPECT_EQ(0, get<3>(b10));
+ EXPECT_EQ(0, get<4>(b10));
+ EXPECT_EQ(0, get<5>(b10));
+ EXPECT_EQ(0, get<6>(b10));
+ EXPECT_EQ(0, get<7>(b10));
+ EXPECT_EQ(0, get<8>(b10));
+ EXPECT_EQ(0, get<9>(b10));
+}
+
+// Tests constructing a tuple from its fields.
+TEST(TupleConstructorTest, ConstructsFromFields)
+{
+ int n = 1;
+ // Reference field.
+ tuple<int&> a(n);
+ EXPECT_EQ(&n, &(get<0>(a)));
+
+ // Non-reference fields.
+ tuple<int, char> b(5, 'a');
+ EXPECT_EQ(5, get<0>(b));
+ EXPECT_EQ('a', get<1>(b));
+
+ // Const reference field.
+ const int m = 2;
+ tuple<bool, const int&> c(true, m);
+ EXPECT_TRUE(get<0>(c));
+ EXPECT_EQ(&m, &(get<1>(c)));
+}
+
+// Tests tuple's copy constructor.
+TEST(TupleConstructorTest, CopyConstructor)
+{
+ tuple<double, bool> a(0.0, true);
+ tuple<double, bool> b(a);
+
+ EXPECT_DOUBLE_EQ(0.0, get<0>(b));
+ EXPECT_TRUE(get<1>(b));
+}
+
+// Tests constructing a tuple from another tuple that has a compatible
+// but different type.
+TEST(TupleConstructorTest, ConstructsFromDifferentTupleType)
+{
+ tuple<int, int, char> a(0, 1, 'a');
+ tuple<double, long, int> b(a);
+
+ EXPECT_DOUBLE_EQ(0.0, get<0>(b));
+ EXPECT_EQ(1, get<1>(b));
+ EXPECT_EQ('a', get<2>(b));
+}
+
+// Tests constructing a 2-tuple from an std::pair.
+TEST(TupleConstructorTest, ConstructsFromPair)
+{
+ ::std::pair<int, char> a(1, 'a');
+ tuple<int, char> b(a);
+ tuple<int, const char&> c(a);
+}
+
+// Tests assigning a tuple to another tuple with the same type.
+TEST(TupleAssignmentTest, AssignsToSameTupleType)
+{
+ const tuple<int, long> a(5, 7L);
+ tuple<int, long> b;
+ b = a;
+ EXPECT_EQ(5, get<0>(b));
+ EXPECT_EQ(7L, get<1>(b));
+}
+
+// Tests assigning a tuple to another tuple with a different but
+// compatible type.
+TEST(TupleAssignmentTest, AssignsToDifferentTupleType)
+{
+ const tuple<int, long, bool> a(1, 7L, true);
+ tuple<long, int, bool> b;
+ b = a;
+ EXPECT_EQ(1L, get<0>(b));
+ EXPECT_EQ(7, get<1>(b));
+ EXPECT_TRUE(get<2>(b));
+}
+
+// Tests assigning an std::pair to a 2-tuple.
+TEST(TupleAssignmentTest, AssignsFromPair)
+{
+ const ::std::pair<int, bool> a(5, true);
+ tuple<int, bool> b;
+ b = a;
+ EXPECT_EQ(5, get<0>(b));
+ EXPECT_TRUE(get<1>(b));
+
+ tuple<long, bool> c;
+ c = a;
+ EXPECT_EQ(5L, get<0>(c));
+ EXPECT_TRUE(get<1>(c));
+}
+
+// A fixture for testing big tuples.
+class BigTupleTest : public testing::Test
+{
+ protected:
+ typedef tuple<int, int, int, int, int, int, int, int, int, int> BigTuple;
+
+ BigTupleTest() :
+ a_(1, 0, 0, 0, 0, 0, 0, 0, 0, 2),
+ b_(1, 0, 0, 0, 0, 0, 0, 0, 0, 3) {}
+
+ BigTuple a_, b_;
+};
+
+// Tests constructing big tuples.
+TEST_F(BigTupleTest, Construction)
+{
+ BigTuple a;
+ BigTuple b(b_);
+}
+
+// Tests that get<N>(t) returns the N-th (0-based) field of tuple t.
+TEST_F(BigTupleTest, get)
+{
+ EXPECT_EQ(1, get<0>(a_));
+ EXPECT_EQ(2, get<9>(a_));
+
+ // Tests that get() works on a const tuple too.
+ const BigTuple a(a_);
+ EXPECT_EQ(1, get<0>(a));
+ EXPECT_EQ(2, get<9>(a));
+}
+
+// Tests comparing big tuples.
+TEST_F(BigTupleTest, Comparisons)
+{
+ EXPECT_TRUE(a_ == a_);
+ EXPECT_FALSE(a_ != a_);
+
+ EXPECT_TRUE(a_ != b_);
+ EXPECT_FALSE(a_ == b_);
+}
+
+TEST(MakeTupleTest, WorksForScalarTypes)
+{
+ tuple<bool, int> a;
+ a = make_tuple(true, 5);
+ EXPECT_TRUE(get<0>(a));
+ EXPECT_EQ(5, get<1>(a));
+
+ tuple<char, int, long> b;
+ b = make_tuple('a', 'b', 5);
+ EXPECT_EQ('a', get<0>(b));
+ EXPECT_EQ('b', get<1>(b));
+ EXPECT_EQ(5, get<2>(b));
+}
+
+TEST(MakeTupleTest, WorksForPointers)
+{
+ int a[] = { 1, 2, 3, 4 };
+ const char* const str = "hi";
+ int* const p = a;
+
+ tuple<const char*, int*> t;
+ t = make_tuple(str, p);
+ EXPECT_EQ(str, get<0>(t));
+ EXPECT_EQ(p, get<1>(t));
+}
+
+} // namespace
diff --git a/external/gtest-1.6.0/test/gtest-typed-test2_test.cc b/external/gtest-1.6.0/test/gtest-typed-test2_test.cc
new file mode 100644
index 0000000..c284700
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-typed-test2_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include <vector>
+
+#include "test/gtest-typed-test_test.h"
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Tests that the same type-parameterized test case can be
+// instantiated in different translation units linked together.
+// (ContainerTest is also instantiated in gtest-typed-test_test.cc.)
+INSTANTIATE_TYPED_TEST_CASE_P(Vector, ContainerTest,
+ testing::Types<std::vector<int> >);
+
+#endif // GTEST_HAS_TYPED_TEST_P
diff --git a/external/gtest-1.6.0/test/gtest-typed-test_test.cc b/external/gtest-1.6.0/test/gtest-typed-test_test.cc
new file mode 100644
index 0000000..14b300e
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-typed-test_test.cc
@@ -0,0 +1,384 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include <set>
+#include <vector>
+
+#include "test/gtest-typed-test_test.h"
+#include "gtest/gtest.h"
+
+using testing::Test;
+
+// Used for testing that SetUpTestCase()/TearDownTestCase(), fixture
+// ctor/dtor, and SetUp()/TearDown() work correctly in typed tests and
+// type-parameterized test.
+template <typename T>
+class CommonTest : public Test
+{
+ // For some technical reason, SetUpTestCase() and TearDownTestCase()
+ // must be public.
+ public:
+ static void SetUpTestCase() {
+ shared_ = new T(5);
+ }
+
+ static void TearDownTestCase() {
+ delete shared_;
+ shared_ = NULL;
+ }
+
+ // This 'protected:' is optional. There's no harm in making all
+ // members of this fixture class template public.
+ protected:
+ // We used to use std::list here, but switched to std::vector since
+ // MSVC's <list> doesn't compile cleanly with /W4.
+ typedef std::vector<T> Vector;
+ typedef std::set<int> IntSet;
+
+ CommonTest() : value_(1) {}
+
+ virtual ~CommonTest() { EXPECT_EQ(3, value_); }
+
+ virtual void SetUp() {
+ EXPECT_EQ(1, value_);
+ value_++;
+ }
+
+ virtual void TearDown() {
+ EXPECT_EQ(2, value_);
+ value_++;
+ }
+
+ T value_;
+ static T* shared_;
+};
+
+template <typename T>
+T* CommonTest<T>::shared_ = NULL;
+
+// This #ifdef block tests typed tests.
+#if GTEST_HAS_TYPED_TEST
+
+using testing::Types;
+
+// Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor,
+// and SetUp()/TearDown() work correctly in typed tests
+
+typedef Types<char, int> TwoTypes;
+TYPED_TEST_CASE(CommonTest, TwoTypes);
+
+TYPED_TEST(CommonTest, ValuesAreCorrect)
+{
+ // Static members of the fixture class template can be visited via
+ // the TestFixture:: prefix.
+ EXPECT_EQ(5, *TestFixture::shared_);
+
+ // Typedefs in the fixture class template can be visited via the
+ // "typename TestFixture::" prefix.
+ typename TestFixture::Vector empty;
+ EXPECT_EQ(0U, empty.size());
+
+ typename TestFixture::IntSet empty2;
+ EXPECT_EQ(0U, empty2.size());
+
+ // Non-static members of the fixture class must be visited via
+ // 'this', as required by C++ for class templates.
+ EXPECT_EQ(2, this->value_);
+}
+
+// The second test makes sure shared_ is not deleted after the first
+// test.
+TYPED_TEST(CommonTest, ValuesAreStillCorrect)
+{
+ // Static members of the fixture class template can also be visited
+ // via 'this'.
+ ASSERT_TRUE(this->shared_ != NULL);
+ EXPECT_EQ(5, *this->shared_);
+
+ // TypeParam can be used to refer to the type parameter.
+ EXPECT_EQ(static_cast<TypeParam>(2), this->value_);
+}
+
+// Tests that multiple TYPED_TEST_CASE's can be defined in the same
+// translation unit.
+
+template <typename T>
+class TypedTest1 : public Test
+{
+};
+
+// Verifies that the second argument of TYPED_TEST_CASE can be a
+// single type.
+TYPED_TEST_CASE(TypedTest1, int);
+TYPED_TEST(TypedTest1, A) {}
+
+template <typename T>
+class TypedTest2 : public Test
+{
+};
+
+// Verifies that the second argument of TYPED_TEST_CASE can be a
+// Types<...> type list.
+TYPED_TEST_CASE(TypedTest2, Types<int>);
+
+// This also verifies that tests from different typed test cases can
+// share the same name.
+TYPED_TEST(TypedTest2, A) {}
+
+// Tests that a typed test case can be defined in a namespace.
+
+namespace library1
+{
+
+template <typename T>
+class NumericTest : public Test
+{
+};
+
+typedef Types<int, long> NumericTypes;
+TYPED_TEST_CASE(NumericTest, NumericTypes);
+
+TYPED_TEST(NumericTest, DefaultIsZero)
+{
+ EXPECT_EQ(0, TypeParam());
+}
+
+} // namespace library1
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// This #ifdef block tests type-parameterized tests.
+#if GTEST_HAS_TYPED_TEST_P
+
+using testing::Types;
+using testing::internal::TypedTestCasePState;
+
+// Tests TypedTestCasePState.
+
+class TypedTestCasePStateTest : public Test
+{
+ protected:
+ virtual void SetUp() {
+ state_.AddTestName("foo.cc", 0, "FooTest", "A");
+ state_.AddTestName("foo.cc", 0, "FooTest", "B");
+ state_.AddTestName("foo.cc", 0, "FooTest", "C");
+ }
+
+ TypedTestCasePState state_;
+};
+
+TEST_F(TypedTestCasePStateTest, SucceedsForMatchingList)
+{
+ const char* tests = "A, B, C";
+ EXPECT_EQ(tests,
+ state_.VerifyRegisteredTestNames("foo.cc", 1, tests));
+}
+
+// Makes sure that the order of the tests and spaces around the names
+// don't matter.
+TEST_F(TypedTestCasePStateTest, IgnoresOrderAndSpaces)
+{
+ const char* tests = "A,C, B";
+ EXPECT_EQ(tests,
+ state_.VerifyRegisteredTestNames("foo.cc", 1, tests));
+}
+
+typedef TypedTestCasePStateTest TypedTestCasePStateDeathTest;
+
+TEST_F(TypedTestCasePStateDeathTest, DetectsDuplicates)
+{
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"),
+ "foo\\.cc.1.?: Test A is listed more than once\\.");
+}
+
+TEST_F(TypedTestCasePStateDeathTest, DetectsExtraTest)
+{
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"),
+ "foo\\.cc.1.?: No test named D can be found in this test case\\.");
+}
+
+TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest)
+{
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"),
+ "foo\\.cc.1.?: You forgot to list test B\\.");
+}
+
+// Tests that defining a test for a parameterized test case generates
+// a run-time error if the test case has been registered.
+TEST_F(TypedTestCasePStateDeathTest, DetectsTestAfterRegistration)
+{
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C");
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.AddTestName("foo.cc", 2, "FooTest", "D"),
+ "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_CASE_P"
+ "\\(FooTest, \\.\\.\\.\\)\\.");
+}
+
+// Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor,
+// and SetUp()/TearDown() work correctly in type-parameterized tests.
+
+template <typename T>
+class DerivedTest : public CommonTest<T>
+{
+};
+
+TYPED_TEST_CASE_P(DerivedTest);
+
+TYPED_TEST_P(DerivedTest, ValuesAreCorrect)
+{
+ // Static members of the fixture class template can be visited via
+ // the TestFixture:: prefix.
+ EXPECT_EQ(5, *TestFixture::shared_);
+
+ // Non-static members of the fixture class must be visited via
+ // 'this', as required by C++ for class templates.
+ EXPECT_EQ(2, this->value_);
+}
+
+// The second test makes sure shared_ is not deleted after the first
+// test.
+TYPED_TEST_P(DerivedTest, ValuesAreStillCorrect)
+{
+ // Static members of the fixture class template can also be visited
+ // via 'this'.
+ ASSERT_TRUE(this->shared_ != NULL);
+ EXPECT_EQ(5, *this->shared_);
+ EXPECT_EQ(2, this->value_);
+}
+
+REGISTER_TYPED_TEST_CASE_P(DerivedTest,
+ ValuesAreCorrect, ValuesAreStillCorrect);
+
+typedef Types<short, long> MyTwoTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, DerivedTest, MyTwoTypes);
+
+// Tests that multiple TYPED_TEST_CASE_P's can be defined in the same
+// translation unit.
+
+template <typename T>
+class TypedTestP1 : public Test
+{
+};
+
+TYPED_TEST_CASE_P(TypedTestP1);
+
+// For testing that the code between TYPED_TEST_CASE_P() and
+// TYPED_TEST_P() is not enclosed in a namespace.
+typedef int IntAfterTypedTestCaseP;
+
+TYPED_TEST_P(TypedTestP1, A) {}
+TYPED_TEST_P(TypedTestP1, B) {}
+
+// For testing that the code between TYPED_TEST_P() and
+// REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace.
+typedef int IntBeforeRegisterTypedTestCaseP;
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP1, A, B);
+
+template <typename T>
+class TypedTestP2 : public Test
+{
+};
+
+TYPED_TEST_CASE_P(TypedTestP2);
+
+// This also verifies that tests from different type-parameterized
+// test cases can share the same name.
+TYPED_TEST_P(TypedTestP2, A) {}
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP2, A);
+
+// Verifies that the code between TYPED_TEST_CASE_P() and
+// REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace.
+IntAfterTypedTestCaseP after = 0;
+IntBeforeRegisterTypedTestCaseP before = 0;
+
+// Verifies that the last argument of INSTANTIATE_TYPED_TEST_CASE_P()
+// can be either a single type or a Types<...> type list.
+INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP1, int);
+INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP2, Types<int>);
+
+// Tests that the same type-parameterized test case can be
+// instantiated more than once in the same translation unit.
+INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types<double>);
+
+// Tests that the same type-parameterized test case can be
+// instantiated in different translation units linked together.
+// (ContainerTest is also instantiated in gtest-typed-test_test.cc.)
+typedef Types<std::vector<double>, std::set<char> > MyContainers;
+INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers);
+
+// Tests that a type-parameterized test case can be defined and
+// instantiated in a namespace.
+
+namespace library2
+{
+
+template <typename T>
+class NumericTest : public Test
+{
+};
+
+TYPED_TEST_CASE_P(NumericTest);
+
+TYPED_TEST_P(NumericTest, DefaultIsZero)
+{
+ EXPECT_EQ(0, TypeParam());
+}
+
+TYPED_TEST_P(NumericTest, ZeroIsLessThanOne)
+{
+ EXPECT_LT(TypeParam(0), TypeParam(1));
+}
+
+REGISTER_TYPED_TEST_CASE_P(NumericTest,
+ DefaultIsZero, ZeroIsLessThanOne);
+typedef Types<int, double> NumericTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes);
+
+} // namespace library2
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
+
+// Google Test may not support type-parameterized tests with some
+// compilers. If we use conditional compilation to compile out all
+// code referring to the gtest_main library, MSVC linker will not link
+// that library at all and consequently complain about missing entry
+// point defined in that library (fatal error LNK1561: entry point
+// must be defined). This dummy test keeps gtest_main linked in.
+TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
diff --git a/external/gtest-1.6.0/test/gtest-typed-test_test.h b/external/gtest-1.6.0/test/gtest-typed-test_test.h
new file mode 100644
index 0000000..84bf8e8
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-typed-test_test.h
@@ -0,0 +1,69 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_TEST_GTEST_TYPED_TEST_TEST_H_
+#define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_
+
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_TYPED_TEST_P
+
+using testing::Test;
+
+// For testing that the same type-parameterized test case can be
+// instantiated in different translation units linked together.
+// ContainerTest will be instantiated in both gtest-typed-test_test.cc
+// and gtest-typed-test2_test.cc.
+
+template <typename T>
+class ContainerTest : public Test
+{
+};
+
+TYPED_TEST_CASE_P(ContainerTest);
+
+TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed)
+{
+ TypeParam container;
+}
+
+TYPED_TEST_P(ContainerTest, InitialSizeIsZero)
+{
+ TypeParam container;
+ EXPECT_EQ(0U, container.size());
+}
+
+REGISTER_TYPED_TEST_CASE_P(ContainerTest,
+ CanBeDefaultConstructed, InitialSizeIsZero);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_
diff --git a/external/gtest-1.6.0/test/gtest-unittest-api_test.cc b/external/gtest-1.6.0/test/gtest-unittest-api_test.cc
new file mode 100644
index 0000000..dc1b93e
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest-unittest-api_test.cc
@@ -0,0 +1,350 @@
+// Copyright 2009 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This file contains tests verifying correctness of data provided via
+// UnitTest's public methods.
+
+#include "gtest/gtest.h"
+
+#include <string.h> // For strcmp.
+#include <algorithm>
+
+using ::testing::InitGoogleTest;
+
+namespace testing
+{
+namespace internal
+{
+
+template <typename T>
+struct LessByName {
+ bool operator()(const T* a, const T* b) {
+ return strcmp(a->name(), b->name()) < 0;
+ }
+};
+
+class UnitTestHelper
+{
+ public:
+ // Returns the array of pointers to all test cases sorted by the test case
+ // name. The caller is responsible for deleting the array.
+ static TestCase const** const GetSortedTestCases() {
+ UnitTest& unit_test = *UnitTest::GetInstance();
+ TestCase const** const test_cases =
+ new const TestCase*[unit_test.total_test_case_count()];
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i)
+ test_cases[i] = unit_test.GetTestCase(i);
+
+ std::sort(test_cases,
+ test_cases + unit_test.total_test_case_count(),
+ LessByName<TestCase>());
+ return test_cases;
+ }
+
+ // Returns the test case by its name. The caller doesn't own the returned
+ // pointer.
+ static const TestCase* FindTestCase(const char* name) {
+ UnitTest& unit_test = *UnitTest::GetInstance();
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase* test_case = unit_test.GetTestCase(i);
+ if (0 == strcmp(test_case->name(), name))
+ return test_case;
+ }
+ return NULL;
+ }
+
+ // Returns the array of pointers to all tests in a particular test case
+ // sorted by the test name. The caller is responsible for deleting the
+ // array.
+ static TestInfo const** const GetSortedTests(const TestCase* test_case) {
+ TestInfo const** const tests =
+ new const TestInfo*[test_case->total_test_count()];
+
+ for (int i = 0; i < test_case->total_test_count(); ++i)
+ tests[i] = test_case->GetTestInfo(i);
+
+ std::sort(tests, tests + test_case->total_test_count(),
+ LessByName<TestInfo>());
+ return tests;
+ }
+};
+
+#if GTEST_HAS_TYPED_TEST
+template <typename T> class TestCaseWithCommentTest : public Test {};
+TYPED_TEST_CASE(TestCaseWithCommentTest, Types<int>);
+TYPED_TEST(TestCaseWithCommentTest, Dummy) {}
+
+const int kTypedTestCases = 1;
+const int kTypedTests = 1;
+#else
+const int kTypedTestCases = 0;
+const int kTypedTests = 0;
+#endif // GTEST_HAS_TYPED_TEST
+
+// We can only test the accessors that do not change value while tests run.
+// Since tests can be run in any order, the values the accessors that track
+// test execution (such as failed_test_count) can not be predicted.
+TEST(ApiTest, UnitTestImmutableAccessorsWork)
+{
+ UnitTest* unit_test = UnitTest::GetInstance();
+
+ ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count());
+ EXPECT_EQ(1 + kTypedTestCases, unit_test->test_case_to_run_count());
+ EXPECT_EQ(2, unit_test->disabled_test_count());
+ EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count());
+ EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count());
+
+ const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases();
+
+ EXPECT_STREQ("ApiTest", test_cases[0]->name());
+ EXPECT_STREQ("DISABLED_Test", test_cases[1]->name());
+#if GTEST_HAS_TYPED_TEST
+ EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name());
+#endif // GTEST_HAS_TYPED_TEST
+
+ delete[] test_cases;
+
+ // The following lines initiate actions to verify certain methods in
+ // FinalSuccessChecker::TearDown.
+
+ // Records a test property to verify TestResult::GetTestProperty().
+ RecordProperty("key", "value");
+}
+
+AssertionResult IsNull(const char* str)
+{
+ if (str != NULL) {
+ return testing::AssertionFailure() << "argument is " << str;
+ }
+ return AssertionSuccess();
+}
+
+TEST(ApiTest, TestCaseImmutableAccessorsWork)
+{
+ const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest");
+ ASSERT_TRUE(test_case != NULL);
+
+ EXPECT_STREQ("ApiTest", test_case->name());
+ EXPECT_TRUE(IsNull(test_case->type_param()));
+ EXPECT_TRUE(test_case->should_run());
+ EXPECT_EQ(1, test_case->disabled_test_count());
+ EXPECT_EQ(3, test_case->test_to_run_count());
+ ASSERT_EQ(4, test_case->total_test_count());
+
+ const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case);
+
+ EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name());
+ EXPECT_STREQ("ApiTest", tests[0]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[0]->value_param()));
+ EXPECT_TRUE(IsNull(tests[0]->type_param()));
+ EXPECT_FALSE(tests[0]->should_run());
+
+ EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name());
+ EXPECT_STREQ("ApiTest", tests[1]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[1]->value_param()));
+ EXPECT_TRUE(IsNull(tests[1]->type_param()));
+ EXPECT_TRUE(tests[1]->should_run());
+
+ EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name());
+ EXPECT_STREQ("ApiTest", tests[2]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[2]->value_param()));
+ EXPECT_TRUE(IsNull(tests[2]->type_param()));
+ EXPECT_TRUE(tests[2]->should_run());
+
+ EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name());
+ EXPECT_STREQ("ApiTest", tests[3]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[3]->value_param()));
+ EXPECT_TRUE(IsNull(tests[3]->type_param()));
+ EXPECT_TRUE(tests[3]->should_run());
+
+ delete[] tests;
+ tests = NULL;
+
+#if GTEST_HAS_TYPED_TEST
+ test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0");
+ ASSERT_TRUE(test_case != NULL);
+
+ EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name());
+ EXPECT_STREQ(GetTypeName<int>().c_str(), test_case->type_param());
+ EXPECT_TRUE(test_case->should_run());
+ EXPECT_EQ(0, test_case->disabled_test_count());
+ EXPECT_EQ(1, test_case->test_to_run_count());
+ ASSERT_EQ(1, test_case->total_test_count());
+
+ tests = UnitTestHelper::GetSortedTests(test_case);
+
+ EXPECT_STREQ("Dummy", tests[0]->name());
+ EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[0]->value_param()));
+ EXPECT_STREQ(GetTypeName<int>().c_str(), tests[0]->type_param());
+ EXPECT_TRUE(tests[0]->should_run());
+
+ delete[] tests;
+#endif // GTEST_HAS_TYPED_TEST
+}
+
+TEST(ApiTest, TestCaseDisabledAccessorsWork)
+{
+ const TestCase* test_case = UnitTestHelper::FindTestCase("DISABLED_Test");
+ ASSERT_TRUE(test_case != NULL);
+
+ EXPECT_STREQ("DISABLED_Test", test_case->name());
+ EXPECT_TRUE(IsNull(test_case->type_param()));
+ EXPECT_FALSE(test_case->should_run());
+ EXPECT_EQ(1, test_case->disabled_test_count());
+ EXPECT_EQ(0, test_case->test_to_run_count());
+ ASSERT_EQ(1, test_case->total_test_count());
+
+ const TestInfo* const test_info = test_case->GetTestInfo(0);
+ EXPECT_STREQ("Dummy2", test_info->name());
+ EXPECT_STREQ("DISABLED_Test", test_info->test_case_name());
+ EXPECT_TRUE(IsNull(test_info->value_param()));
+ EXPECT_TRUE(IsNull(test_info->type_param()));
+ EXPECT_FALSE(test_info->should_run());
+}
+
+// These two tests are here to provide support for testing
+// test_case_to_run_count, disabled_test_count, and test_to_run_count.
+TEST(ApiTest, DISABLED_Dummy1) {}
+TEST(DISABLED_Test, Dummy2) {}
+
+class FinalSuccessChecker : public Environment
+{
+ protected:
+ virtual void TearDown() {
+ UnitTest* unit_test = UnitTest::GetInstance();
+
+ EXPECT_EQ(1 + kTypedTestCases, unit_test->successful_test_case_count());
+ EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count());
+ EXPECT_EQ(0, unit_test->failed_test_case_count());
+ EXPECT_EQ(0, unit_test->failed_test_count());
+ EXPECT_TRUE(unit_test->Passed());
+ EXPECT_FALSE(unit_test->Failed());
+ ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count());
+
+ const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases();
+
+ EXPECT_STREQ("ApiTest", test_cases[0]->name());
+ EXPECT_TRUE(IsNull(test_cases[0]->type_param()));
+ EXPECT_TRUE(test_cases[0]->should_run());
+ EXPECT_EQ(1, test_cases[0]->disabled_test_count());
+ ASSERT_EQ(4, test_cases[0]->total_test_count());
+ EXPECT_EQ(3, test_cases[0]->successful_test_count());
+ EXPECT_EQ(0, test_cases[0]->failed_test_count());
+ EXPECT_TRUE(test_cases[0]->Passed());
+ EXPECT_FALSE(test_cases[0]->Failed());
+
+ EXPECT_STREQ("DISABLED_Test", test_cases[1]->name());
+ EXPECT_TRUE(IsNull(test_cases[1]->type_param()));
+ EXPECT_FALSE(test_cases[1]->should_run());
+ EXPECT_EQ(1, test_cases[1]->disabled_test_count());
+ ASSERT_EQ(1, test_cases[1]->total_test_count());
+ EXPECT_EQ(0, test_cases[1]->successful_test_count());
+ EXPECT_EQ(0, test_cases[1]->failed_test_count());
+
+#if GTEST_HAS_TYPED_TEST
+ EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name());
+ EXPECT_STREQ(GetTypeName<int>().c_str(), test_cases[2]->type_param());
+ EXPECT_TRUE(test_cases[2]->should_run());
+ EXPECT_EQ(0, test_cases[2]->disabled_test_count());
+ ASSERT_EQ(1, test_cases[2]->total_test_count());
+ EXPECT_EQ(1, test_cases[2]->successful_test_count());
+ EXPECT_EQ(0, test_cases[2]->failed_test_count());
+ EXPECT_TRUE(test_cases[2]->Passed());
+ EXPECT_FALSE(test_cases[2]->Failed());
+#endif // GTEST_HAS_TYPED_TEST
+
+ const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest");
+ const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case);
+ EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name());
+ EXPECT_STREQ("ApiTest", tests[0]->test_case_name());
+ EXPECT_FALSE(tests[0]->should_run());
+
+ EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name());
+ EXPECT_STREQ("ApiTest", tests[1]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[1]->value_param()));
+ EXPECT_TRUE(IsNull(tests[1]->type_param()));
+ EXPECT_TRUE(tests[1]->should_run());
+ EXPECT_TRUE(tests[1]->result()->Passed());
+ EXPECT_EQ(0, tests[1]->result()->test_property_count());
+
+ EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name());
+ EXPECT_STREQ("ApiTest", tests[2]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[2]->value_param()));
+ EXPECT_TRUE(IsNull(tests[2]->type_param()));
+ EXPECT_TRUE(tests[2]->should_run());
+ EXPECT_TRUE(tests[2]->result()->Passed());
+ EXPECT_EQ(0, tests[2]->result()->test_property_count());
+
+ EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name());
+ EXPECT_STREQ("ApiTest", tests[3]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[3]->value_param()));
+ EXPECT_TRUE(IsNull(tests[3]->type_param()));
+ EXPECT_TRUE(tests[3]->should_run());
+ EXPECT_TRUE(tests[3]->result()->Passed());
+ EXPECT_EQ(1, tests[3]->result()->test_property_count());
+ const TestProperty& property = tests[3]->result()->GetTestProperty(0);
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("value", property.value());
+
+ delete[] tests;
+
+#if GTEST_HAS_TYPED_TEST
+ test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0");
+ tests = UnitTestHelper::GetSortedTests(test_case);
+
+ EXPECT_STREQ("Dummy", tests[0]->name());
+ EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name());
+ EXPECT_TRUE(IsNull(tests[0]->value_param()));
+ EXPECT_STREQ(GetTypeName<int>().c_str(), tests[0]->type_param());
+ EXPECT_TRUE(tests[0]->should_run());
+ EXPECT_TRUE(tests[0]->result()->Passed());
+ EXPECT_EQ(0, tests[0]->result()->test_property_count());
+
+ delete[] tests;
+#endif // GTEST_HAS_TYPED_TEST
+ delete[] test_cases;
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+int main(int argc, char** argv)
+{
+ InitGoogleTest(&argc, argv);
+
+ AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker());
+
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_all_test.cc b/external/gtest-1.6.0/test/gtest_all_test.cc
new file mode 100644
index 0000000..955aa62
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_all_test.cc
@@ -0,0 +1,47 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Tests for Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build most of Google Test's own tests
+// by compiling a single file. This file serves this purpose.
+#include "test/gtest-filepath_test.cc"
+#include "test/gtest-linked_ptr_test.cc"
+#include "test/gtest-message_test.cc"
+#include "test/gtest-options_test.cc"
+#include "test/gtest-port_test.cc"
+#include "test/gtest_pred_impl_unittest.cc"
+#include "test/gtest_prod_test.cc"
+#include "test/gtest-test-part_test.cc"
+#include "test/gtest-typed-test_test.cc"
+#include "test/gtest-typed-test2_test.cc"
+#include "test/gtest_unittest.cc"
+#include "test/production.cc"
diff --git a/external/gtest-1.6.0/test/gtest_break_on_failure_unittest.py b/external/gtest-1.6.0/test/gtest_break_on_failure_unittest.py
new file mode 100755
index 0000000..c819183
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_break_on_failure_unittest.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for Google Test's break-on-failure mode.
+
+A user can ask Google Test to seg-fault when an assertion fails, using
+either the GTEST_BREAK_ON_FAILURE environment variable or the
+--gtest_break_on_failure flag. This script tests such functionality
+by invoking gtest_break_on_failure_unittest_ (a program written with
+Google Test) with different environments and command line flags.
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import gtest_test_utils
+import os
+import sys
+
+
+# Constants.
+
+IS_WINDOWS = os.name == 'nt'
+
+# The environment variable for enabling/disabling the break-on-failure mode.
+BREAK_ON_FAILURE_ENV_VAR = 'GTEST_BREAK_ON_FAILURE'
+
+# The command line flag for enabling/disabling the break-on-failure mode.
+BREAK_ON_FAILURE_FLAG = 'gtest_break_on_failure'
+
+# The environment variable for enabling/disabling the throw-on-failure mode.
+THROW_ON_FAILURE_ENV_VAR = 'GTEST_THROW_ON_FAILURE'
+
+# The environment variable for enabling/disabling the catch-exceptions mode.
+CATCH_EXCEPTIONS_ENV_VAR = 'GTEST_CATCH_EXCEPTIONS'
+
+# Path to the gtest_break_on_failure_unittest_ program.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_break_on_failure_unittest_')
+
+
+# Utilities.
+
+
+environ = os.environ.copy()
+
+
+def SetEnvVar(env_var, value):
+ """Sets an environment variable to a given value; unsets it when the
+ given value is None.
+ """
+
+ if value is not None:
+ environ[env_var] = value
+ elif env_var in environ:
+ del environ[env_var]
+
+
+def Run(command):
+ """Runs a command; returns 1 if it was killed by a signal, or 0 otherwise."""
+
+ p = gtest_test_utils.Subprocess(command, env=environ)
+ if p.terminated_by_signal:
+ return 1
+ else:
+ return 0
+
+
+# The tests.
+
+
+class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase):
+ """Tests using the GTEST_BREAK_ON_FAILURE environment variable or
+ the --gtest_break_on_failure flag to turn assertion failures into
+ segmentation faults.
+ """
+
+ def RunAndVerify(self, env_var_value, flag_value, expect_seg_fault):
+ """Runs gtest_break_on_failure_unittest_ and verifies that it does
+ (or does not) have a seg-fault.
+
+ Args:
+ env_var_value: value of the GTEST_BREAK_ON_FAILURE environment
+ variable; None if the variable should be unset.
+ flag_value: value of the --gtest_break_on_failure flag;
+ None if the flag should not be present.
+ expect_seg_fault: 1 if the program is expected to generate a seg-fault;
+ 0 otherwise.
+ """
+
+ SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, env_var_value)
+
+ if env_var_value is None:
+ env_var_value_msg = ' is not set'
+ else:
+ env_var_value_msg = '=' + env_var_value
+
+ if flag_value is None:
+ flag = ''
+ elif flag_value == '0':
+ flag = '--%s=0' % BREAK_ON_FAILURE_FLAG
+ else:
+ flag = '--%s' % BREAK_ON_FAILURE_FLAG
+
+ command = [EXE_PATH]
+ if flag:
+ command.append(flag)
+
+ if expect_seg_fault:
+ should_or_not = 'should'
+ else:
+ should_or_not = 'should not'
+
+ has_seg_fault = Run(command)
+
+ SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, None)
+
+ msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' %
+ (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command),
+ should_or_not))
+ self.assert_(has_seg_fault == expect_seg_fault, msg)
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of the default mode."""
+
+ self.RunAndVerify(env_var_value=None,
+ flag_value=None,
+ expect_seg_fault=0)
+
+ def testEnvVar(self):
+ """Tests using the GTEST_BREAK_ON_FAILURE environment variable."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value=None,
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value='1',
+ flag_value=None,
+ expect_seg_fault=1)
+
+ def testFlag(self):
+ """Tests using the --gtest_break_on_failure flag."""
+
+ self.RunAndVerify(env_var_value=None,
+ flag_value='0',
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value=None,
+ flag_value='1',
+ expect_seg_fault=1)
+
+ def testFlagOverridesEnvVar(self):
+ """Tests that the flag overrides the environment variable."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value='0',
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value='0',
+ flag_value='1',
+ expect_seg_fault=1)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='0',
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='1',
+ expect_seg_fault=1)
+
+ def testBreakOnFailureOverridesThrowOnFailure(self):
+ """Tests that gtest_break_on_failure overrides gtest_throw_on_failure."""
+
+ SetEnvVar(THROW_ON_FAILURE_ENV_VAR, '1')
+ try:
+ self.RunAndVerify(env_var_value=None,
+ flag_value='1',
+ expect_seg_fault=1)
+ finally:
+ SetEnvVar(THROW_ON_FAILURE_ENV_VAR, None)
+
+ if IS_WINDOWS:
+ def testCatchExceptionsDoesNotInterfere(self):
+ """Tests that gtest_catch_exceptions doesn't interfere."""
+
+ SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, '1')
+ try:
+ self.RunAndVerify(env_var_value='1',
+ flag_value='1',
+ expect_seg_fault=1)
+ finally:
+ SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, None)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_break_on_failure_unittest_.cc b/external/gtest-1.6.0/test/gtest_break_on_failure_unittest_.cc
new file mode 100644
index 0000000..9783470
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_break_on_failure_unittest_.cc
@@ -0,0 +1,92 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Unit test for Google Test's break-on-failure mode.
+//
+// A user can ask Google Test to seg-fault when an assertion fails, using
+// either the GTEST_BREAK_ON_FAILURE environment variable or the
+// --gtest_break_on_failure flag. This file is used for testing such
+// functionality.
+//
+// This program will be invoked from a Python unit test. It is
+// expected to fail. Don't run it directly.
+
+#include "gtest/gtest.h"
+
+#if GTEST_OS_WINDOWS
+# include <windows.h>
+# include <stdlib.h>
+#endif
+
+namespace
+{
+
+// A test that's expected to fail.
+TEST(Foo, Bar)
+{
+ EXPECT_EQ(2, 3);
+}
+
+#if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE
+// On Windows Mobile global exception handlers are not supported.
+LONG WINAPI ExitWithExceptionCode(
+ struct _EXCEPTION_POINTERS* exception_pointers)
+{
+ exit(exception_pointers->ExceptionRecord->ExceptionCode);
+}
+#endif
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+#if GTEST_OS_WINDOWS
+ // Suppresses display of the Windows error dialog upon encountering
+ // a general protection fault (segment violation).
+ SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
+
+# if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE
+
+ // The default unhandled exception filter does not always exit
+ // with the exception code as exit code - for example it exits with
+ // 0 for EXCEPTION_ACCESS_VIOLATION and 1 for EXCEPTION_BREAKPOINT
+ // if the application is compiled in debug mode. Thus we use our own
+ // filter which always exits with the exception code for unhandled
+ // exceptions.
+ SetUnhandledExceptionFilter(ExitWithExceptionCode);
+
+# endif
+#endif
+
+ testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_catch_exceptions_test.py b/external/gtest-1.6.0/test/gtest_catch_exceptions_test.py
new file mode 100755
index 0000000..d7ef10e
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_catch_exceptions_test.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Google Test's exception catching behavior.
+
+This script invokes gtest_catch_exceptions_test_ and
+gtest_catch_exceptions_ex_test_ (programs written with
+Google Test) and verifies their output.
+"""
+
+__author__ = 'vladl at google.com (Vlad Losev)'
+
+import os
+
+import gtest_test_utils
+
+# Constants.
+FLAG_PREFIX = '--gtest_'
+LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests'
+NO_CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions=0'
+FILTER_FLAG = FLAG_PREFIX + 'filter'
+
+# Path to the gtest_catch_exceptions_ex_test_ binary, compiled with
+# exceptions enabled.
+EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_catch_exceptions_ex_test_')
+
+# Path to the gtest_catch_exceptions_test_ binary, compiled with
+# exceptions disabled.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_catch_exceptions_no_ex_test_')
+
+TEST_LIST = gtest_test_utils.Subprocess([EXE_PATH, LIST_TESTS_FLAG]).output
+
+SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST
+
+if SUPPORTS_SEH_EXCEPTIONS:
+ BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH]).output
+
+EX_BINARY_OUTPUT = gtest_test_utils.Subprocess([EX_EXE_PATH]).output
+
+# The tests.
+if SUPPORTS_SEH_EXCEPTIONS:
+ # pylint:disable-msg=C6302
+ class CatchSehExceptionsTest(gtest_test_utils.TestCase):
+ """Tests exception-catching behavior."""
+
+
+ def TestSehExceptions(self, test_output):
+ self.assert_('SEH exception with code 0x2a thrown '
+ 'in the test fixture\'s constructor'
+ in test_output)
+ self.assert_('SEH exception with code 0x2a thrown '
+ 'in the test fixture\'s destructor'
+ in test_output)
+ self.assert_('SEH exception with code 0x2a thrown in SetUpTestCase()'
+ in test_output)
+ self.assert_('SEH exception with code 0x2a thrown in TearDownTestCase()'
+ in test_output)
+ self.assert_('SEH exception with code 0x2a thrown in SetUp()'
+ in test_output)
+ self.assert_('SEH exception with code 0x2a thrown in TearDown()'
+ in test_output)
+ self.assert_('SEH exception with code 0x2a thrown in the test body'
+ in test_output)
+
+ def testCatchesSehExceptionsWithCxxExceptionsEnabled(self):
+ self.TestSehExceptions(EX_BINARY_OUTPUT)
+
+ def testCatchesSehExceptionsWithCxxExceptionsDisabled(self):
+ self.TestSehExceptions(BINARY_OUTPUT)
+
+
+class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
+ """Tests C++ exception-catching behavior.
+
+ Tests in this test case verify that:
+ * C++ exceptions are caught and logged as C++ (not SEH) exceptions
+ * Exception thrown affect the remainder of the test work flow in the
+ expected manner.
+ """
+
+ def testCatchesCxxExceptionsInFixtureConstructor(self):
+ self.assert_('C++ exception with description '
+ '"Standard C++ exception" thrown '
+ 'in the test fixture\'s constructor'
+ in EX_BINARY_OUTPUT)
+ self.assert_('unexpected' not in EX_BINARY_OUTPUT,
+ 'This failure belongs in this test only if '
+ '"CxxExceptionInConstructorTest" (no quotes) '
+ 'appears on the same line as words "called unexpectedly"')
+
+ if ('CxxExceptionInDestructorTest.ThrowsExceptionInDestructor' in
+ EX_BINARY_OUTPUT):
+
+ def testCatchesCxxExceptionsInFixtureDestructor(self):
+ self.assert_('C++ exception with description '
+ '"Standard C++ exception" thrown '
+ 'in the test fixture\'s destructor'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInDestructorTest::TearDownTestCase() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+
+ def testCatchesCxxExceptionsInSetUpTestCase(self):
+ self.assert_('C++ exception with description "Standard C++ exception"'
+ ' thrown in SetUpTestCase()'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInConstructorTest::TearDownTestCase() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTestCaseTest constructor '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTestCaseTest destructor '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTestCaseTest::SetUp() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTestCaseTest::TearDown() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTestCaseTest test body '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+
+ def testCatchesCxxExceptionsInTearDownTestCase(self):
+ self.assert_('C++ exception with description "Standard C++ exception"'
+ ' thrown in TearDownTestCase()'
+ in EX_BINARY_OUTPUT)
+
+ def testCatchesCxxExceptionsInSetUp(self):
+ self.assert_('C++ exception with description "Standard C++ exception"'
+ ' thrown in SetUp()'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTest::TearDownTestCase() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTest destructor '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInSetUpTest::TearDown() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('unexpected' not in EX_BINARY_OUTPUT,
+ 'This failure belongs in this test only if '
+ '"CxxExceptionInSetUpTest" (no quotes) '
+ 'appears on the same line as words "called unexpectedly"')
+
+ def testCatchesCxxExceptionsInTearDown(self):
+ self.assert_('C++ exception with description "Standard C++ exception"'
+ ' thrown in TearDown()'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInTearDownTest::TearDownTestCase() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInTearDownTest destructor '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+
+ def testCatchesCxxExceptionsInTestBody(self):
+ self.assert_('C++ exception with description "Standard C++ exception"'
+ ' thrown in the test body'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInTestBodyTest::TearDownTestCase() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInTestBodyTest destructor '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+ self.assert_('CxxExceptionInTestBodyTest::TearDown() '
+ 'called as expected.'
+ in EX_BINARY_OUTPUT)
+
+ def testCatchesNonStdCxxExceptions(self):
+ self.assert_('Unknown C++ exception thrown in the test body'
+ in EX_BINARY_OUTPUT)
+
+ def testUnhandledCxxExceptionsAbortTheProgram(self):
+ # Filters out SEH exception tests on Windows. Unhandled SEH exceptions
+ # cause tests to show pop-up windows there.
+ FITLER_OUT_SEH_TESTS_FLAG = FILTER_FLAG + '=-*Seh*'
+ # By default, Google Test doesn't catch the exceptions.
+ uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess(
+ [EX_EXE_PATH,
+ NO_CATCH_EXCEPTIONS_FLAG,
+ FITLER_OUT_SEH_TESTS_FLAG]).output
+
+ self.assert_('Unhandled C++ exception terminating the program'
+ in uncaught_exceptions_ex_binary_output)
+ self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_catch_exceptions_test_.cc b/external/gtest-1.6.0/test/gtest_catch_exceptions_test_.cc
new file mode 100644
index 0000000..e9cf09e
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_catch_exceptions_test_.cc
@@ -0,0 +1,332 @@
+// Copyright 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl at google.com (Vlad Losev)
+//
+// Tests for Google Test itself. Tests in this file throw C++ or SEH
+// exceptions, and the output is verified by gtest_catch_exceptions_test.py.
+
+#include "gtest/gtest.h"
+
+#include <stdio.h> // NOLINT
+#include <stdlib.h> // For exit().
+
+#if GTEST_HAS_SEH
+# include <windows.h>
+#endif
+
+#if GTEST_HAS_EXCEPTIONS
+# include <exception> // For set_terminate().
+# include <stdexcept>
+#endif
+
+using testing::Test;
+
+#if GTEST_HAS_SEH
+
+class SehExceptionInConstructorTest : public Test
+{
+ public:
+ SehExceptionInConstructorTest() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInConstructorTest, ThrowsExceptionInConstructor) {}
+
+class SehExceptionInDestructorTest : public Test
+{
+ public:
+ ~SehExceptionInDestructorTest() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInDestructorTest, ThrowsExceptionInDestructor) {}
+
+class SehExceptionInSetUpTestCaseTest : public Test
+{
+ public:
+ static void SetUpTestCase() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) {}
+
+class SehExceptionInTearDownTestCaseTest : public Test
+{
+ public:
+ static void TearDownTestCase() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {}
+
+class SehExceptionInSetUpTest : public Test
+{
+ protected:
+ virtual void SetUp() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInSetUpTest, ThrowsExceptionInSetUp) {}
+
+class SehExceptionInTearDownTest : public Test
+{
+ protected:
+ virtual void TearDown() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInTearDownTest, ThrowsExceptionInTearDown) {}
+
+TEST(SehExceptionTest, ThrowsSehException)
+{
+ RaiseException(42, 0, 0, NULL);
+}
+
+#endif // GTEST_HAS_SEH
+
+#if GTEST_HAS_EXCEPTIONS
+
+class CxxExceptionInConstructorTest : public Test
+{
+ public:
+ CxxExceptionInConstructorTest() {
+ // Without this macro VC++ complains about unreachable code at the end of
+ // the constructor.
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(
+ throw std::runtime_error("Standard C++ exception"));
+ }
+
+ static void TearDownTestCase() {
+ printf("%s",
+ "CxxExceptionInConstructorTest::TearDownTestCase() "
+ "called as expected.\n");
+ }
+
+ protected:
+ ~CxxExceptionInConstructorTest() {
+ ADD_FAILURE() << "CxxExceptionInConstructorTest destructor "
+ << "called unexpectedly.";
+ }
+
+ virtual void SetUp() {
+ ADD_FAILURE() << "CxxExceptionInConstructorTest::SetUp() "
+ << "called unexpectedly.";
+ }
+
+ virtual void TearDown() {
+ ADD_FAILURE() << "CxxExceptionInConstructorTest::TearDown() "
+ << "called unexpectedly.";
+ }
+};
+
+TEST_F(CxxExceptionInConstructorTest, ThrowsExceptionInConstructor)
+{
+ ADD_FAILURE() << "CxxExceptionInConstructorTest test body "
+ << "called unexpectedly.";
+}
+
+// Exceptions in destructors are not supported in C++11.
+#if !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
+class CxxExceptionInDestructorTest : public Test
+{
+ public:
+ static void TearDownTestCase() {
+ printf("%s",
+ "CxxExceptionInDestructorTest::TearDownTestCase() "
+ "called as expected.\n");
+ }
+
+ protected:
+ ~CxxExceptionInDestructorTest() {
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(
+ throw std::runtime_error("Standard C++ exception"));
+ }
+};
+
+TEST_F(CxxExceptionInDestructorTest, ThrowsExceptionInDestructor) {}
+#endif // C++11 mode
+
+class CxxExceptionInSetUpTestCaseTest : public Test
+{
+ public:
+ CxxExceptionInSetUpTestCaseTest() {
+ printf("%s",
+ "CxxExceptionInSetUpTestCaseTest constructor "
+ "called as expected.\n");
+ }
+
+ static void SetUpTestCase() {
+ throw std::runtime_error("Standard C++ exception");
+ }
+
+ static void TearDownTestCase() {
+ printf("%s",
+ "CxxExceptionInSetUpTestCaseTest::TearDownTestCase() "
+ "called as expected.\n");
+ }
+
+ protected:
+ ~CxxExceptionInSetUpTestCaseTest() {
+ printf("%s",
+ "CxxExceptionInSetUpTestCaseTest destructor "
+ "called as expected.\n");
+ }
+
+ virtual void SetUp() {
+ printf("%s",
+ "CxxExceptionInSetUpTestCaseTest::SetUp() "
+ "called as expected.\n");
+ }
+
+ virtual void TearDown() {
+ printf("%s",
+ "CxxExceptionInSetUpTestCaseTest::TearDown() "
+ "called as expected.\n");
+ }
+};
+
+TEST_F(CxxExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase)
+{
+ printf("%s",
+ "CxxExceptionInSetUpTestCaseTest test body "
+ "called as expected.\n");
+}
+
+class CxxExceptionInTearDownTestCaseTest : public Test
+{
+ public:
+ static void TearDownTestCase() {
+ throw std::runtime_error("Standard C++ exception");
+ }
+};
+
+TEST_F(CxxExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {}
+
+class CxxExceptionInSetUpTest : public Test
+{
+ public:
+ static void TearDownTestCase() {
+ printf("%s",
+ "CxxExceptionInSetUpTest::TearDownTestCase() "
+ "called as expected.\n");
+ }
+
+ protected:
+ ~CxxExceptionInSetUpTest() {
+ printf("%s",
+ "CxxExceptionInSetUpTest destructor "
+ "called as expected.\n");
+ }
+
+ virtual void SetUp() { throw std::runtime_error("Standard C++ exception"); }
+
+ virtual void TearDown() {
+ printf("%s",
+ "CxxExceptionInSetUpTest::TearDown() "
+ "called as expected.\n");
+ }
+};
+
+TEST_F(CxxExceptionInSetUpTest, ThrowsExceptionInSetUp)
+{
+ ADD_FAILURE() << "CxxExceptionInSetUpTest test body "
+ << "called unexpectedly.";
+}
+
+class CxxExceptionInTearDownTest : public Test
+{
+ public:
+ static void TearDownTestCase() {
+ printf("%s",
+ "CxxExceptionInTearDownTest::TearDownTestCase() "
+ "called as expected.\n");
+ }
+
+ protected:
+ ~CxxExceptionInTearDownTest() {
+ printf("%s",
+ "CxxExceptionInTearDownTest destructor "
+ "called as expected.\n");
+ }
+
+ virtual void TearDown() {
+ throw std::runtime_error("Standard C++ exception");
+ }
+};
+
+TEST_F(CxxExceptionInTearDownTest, ThrowsExceptionInTearDown) {}
+
+class CxxExceptionInTestBodyTest : public Test
+{
+ public:
+ static void TearDownTestCase() {
+ printf("%s",
+ "CxxExceptionInTestBodyTest::TearDownTestCase() "
+ "called as expected.\n");
+ }
+
+ protected:
+ ~CxxExceptionInTestBodyTest() {
+ printf("%s",
+ "CxxExceptionInTestBodyTest destructor "
+ "called as expected.\n");
+ }
+
+ virtual void TearDown() {
+ printf("%s",
+ "CxxExceptionInTestBodyTest::TearDown() "
+ "called as expected.\n");
+ }
+};
+
+TEST_F(CxxExceptionInTestBodyTest, ThrowsStdCxxException)
+{
+ throw std::runtime_error("Standard C++ exception");
+}
+
+TEST(CxxExceptionTest, ThrowsNonStdCxxException)
+{
+ throw "C-string";
+}
+
+// This terminate handler aborts the program using exit() rather than abort().
+// This avoids showing pop-ups on Windows systems and core dumps on Unix-like
+// ones.
+void TerminateHandler()
+{
+ fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program.");
+ fflush(NULL);
+ exit(3);
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+int main(int argc, char** argv)
+{
+#if GTEST_HAS_EXCEPTIONS
+ std::set_terminate(&TerminateHandler);
+#endif
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_color_test.py b/external/gtest-1.6.0/test/gtest_color_test.py
new file mode 100755
index 0000000..d02a53e
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_color_test.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that Google Test correctly determines whether to use colors."""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+
+IS_WINDOWS = os.name = 'nt'
+
+COLOR_ENV_VAR = 'GTEST_COLOR'
+COLOR_FLAG = 'gtest_color'
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_color_test_')
+
+
+def SetEnvVar(env_var, value):
+ """Sets the env variable to 'value'; unsets it when 'value' is None."""
+
+ if value is not None:
+ os.environ[env_var] = value
+ elif env_var in os.environ:
+ del os.environ[env_var]
+
+
+def UsesColor(term, color_env_var, color_flag):
+ """Runs gtest_color_test_ and returns its exit code."""
+
+ SetEnvVar('TERM', term)
+ SetEnvVar(COLOR_ENV_VAR, color_env_var)
+
+ if color_flag is None:
+ args = []
+ else:
+ args = ['--%s=%s' % (COLOR_FLAG, color_flag)]
+ p = gtest_test_utils.Subprocess([COMMAND] + args)
+ return not p.exited or p.exit_code
+
+
+class GTestColorTest(gtest_test_utils.TestCase):
+ def testNoEnvVarNoFlag(self):
+ """Tests the case when there's neither GTEST_COLOR nor --gtest_color."""
+
+ if not IS_WINDOWS:
+ self.assert_(not UsesColor('dumb', None, None))
+ self.assert_(not UsesColor('emacs', None, None))
+ self.assert_(not UsesColor('xterm-mono', None, None))
+ self.assert_(not UsesColor('unknown', None, None))
+ self.assert_(not UsesColor(None, None, None))
+ self.assert_(UsesColor('linux', None, None))
+ self.assert_(UsesColor('cygwin', None, None))
+ self.assert_(UsesColor('xterm', None, None))
+ self.assert_(UsesColor('xterm-color', None, None))
+ self.assert_(UsesColor('xterm-256color', None, None))
+
+ def testFlagOnly(self):
+ """Tests the case when there's --gtest_color but not GTEST_COLOR."""
+
+ self.assert_(not UsesColor('dumb', None, 'no'))
+ self.assert_(not UsesColor('xterm-color', None, 'no'))
+ if not IS_WINDOWS:
+ self.assert_(not UsesColor('emacs', None, 'auto'))
+ self.assert_(UsesColor('xterm', None, 'auto'))
+ self.assert_(UsesColor('dumb', None, 'yes'))
+ self.assert_(UsesColor('xterm', None, 'yes'))
+
+ def testEnvVarOnly(self):
+ """Tests the case when there's GTEST_COLOR but not --gtest_color."""
+
+ self.assert_(not UsesColor('dumb', 'no', None))
+ self.assert_(not UsesColor('xterm-color', 'no', None))
+ if not IS_WINDOWS:
+ self.assert_(not UsesColor('dumb', 'auto', None))
+ self.assert_(UsesColor('xterm-color', 'auto', None))
+ self.assert_(UsesColor('dumb', 'yes', None))
+ self.assert_(UsesColor('xterm-color', 'yes', None))
+
+ def testEnvVarAndFlag(self):
+ """Tests the case when there are both GTEST_COLOR and --gtest_color."""
+
+ self.assert_(not UsesColor('xterm-color', 'no', 'no'))
+ self.assert_(UsesColor('dumb', 'no', 'yes'))
+ self.assert_(UsesColor('xterm-color', 'no', 'auto'))
+
+ def testAliasesOfYesAndNo(self):
+ """Tests using aliases in specifying --gtest_color."""
+
+ self.assert_(UsesColor('dumb', None, 'true'))
+ self.assert_(UsesColor('dumb', None, 'YES'))
+ self.assert_(UsesColor('dumb', None, 'T'))
+ self.assert_(UsesColor('dumb', None, '1'))
+
+ self.assert_(not UsesColor('xterm', None, 'f'))
+ self.assert_(not UsesColor('xterm', None, 'false'))
+ self.assert_(not UsesColor('xterm', None, '0'))
+ self.assert_(not UsesColor('xterm', None, 'unknown'))
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_color_test_.cc b/external/gtest-1.6.0/test/gtest_color_test_.cc
new file mode 100644
index 0000000..09e7946
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_color_test_.cc
@@ -0,0 +1,73 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// A helper program for testing how Google Test determines whether to use
+// colors in the output. It prints "YES" and returns 1 if Google Test
+// decides to use colors, and prints "NO" and returns 0 otherwise.
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+using testing::internal::ShouldUseColor;
+
+// The purpose of this is to ensure that the UnitTest singleton is
+// created before main() is entered, and thus that ShouldUseColor()
+// works the same way as in a real Google-Test-based test. We don't actual
+// run the TEST itself.
+TEST(GTestColorTest, Dummy)
+{
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+
+ if (ShouldUseColor(true)) {
+ // Google Test decides to use colors in the output (assuming it
+ // goes to a TTY).
+ printf("YES\n");
+ return 1;
+ } else {
+ // Google Test decides not to use colors in the output.
+ printf("NO\n");
+ return 0;
+ }
+}
diff --git a/external/gtest-1.6.0/test/gtest_env_var_test.py b/external/gtest-1.6.0/test/gtest_env_var_test.py
new file mode 100755
index 0000000..ac24337
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_env_var_test.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that Google Test correctly parses environment variables."""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+
+IS_WINDOWS = os.name == 'nt'
+IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux'
+
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_env_var_test_')
+
+environ = os.environ.copy()
+
+
+def AssertEq(expected, actual):
+ if expected != actual:
+ print 'Expected: %s' % (expected,)
+ print ' Actual: %s' % (actual,)
+ raise AssertionError
+
+
+def SetEnvVar(env_var, value):
+ """Sets the env variable to 'value'; unsets it when 'value' is None."""
+
+ if value is not None:
+ environ[env_var] = value
+ elif env_var in environ:
+ del environ[env_var]
+
+
+def GetFlag(flag):
+ """Runs gtest_env_var_test_ and returns its output."""
+
+ args = [COMMAND]
+ if flag is not None:
+ args += [flag]
+ return gtest_test_utils.Subprocess(args, env=environ).output
+
+
+def TestFlag(flag, test_val, default_val):
+ """Verifies that the given flag is affected by the corresponding env var."""
+
+ env_var = 'GTEST_' + flag.upper()
+ SetEnvVar(env_var, test_val)
+ AssertEq(test_val, GetFlag(flag))
+ SetEnvVar(env_var, None)
+ AssertEq(default_val, GetFlag(flag))
+
+
+class GTestEnvVarTest(gtest_test_utils.TestCase):
+ def testEnvVarAffectsFlag(self):
+ """Tests that environment variable should affect the corresponding flag."""
+
+ TestFlag('break_on_failure', '1', '0')
+ TestFlag('color', 'yes', 'auto')
+ TestFlag('filter', 'FooTest.Bar', '*')
+ TestFlag('output', 'xml:tmp/foo.xml', '')
+ TestFlag('print_time', '0', '1')
+ TestFlag('repeat', '999', '1')
+ TestFlag('throw_on_failure', '1', '0')
+ TestFlag('death_test_style', 'threadsafe', 'fast')
+ TestFlag('catch_exceptions', '0', '1')
+
+ if IS_LINUX:
+ TestFlag('death_test_use_fork', '1', '0')
+ TestFlag('stack_trace_depth', '0', '100')
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_env_var_test_.cc b/external/gtest-1.6.0/test/gtest_env_var_test_.cc
new file mode 100644
index 0000000..ebdbc28
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_env_var_test_.cc
@@ -0,0 +1,130 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// A helper program for testing that Google Test parses the environment
+// variables correctly.
+
+#include "gtest/gtest.h"
+
+#include <iostream>
+
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+using ::std::cout;
+
+namespace testing
+{
+
+// The purpose of this is to make the test more realistic by ensuring
+// that the UnitTest singleton is created before main() is entered.
+// We don't actual run the TEST itself.
+TEST(GTestEnvVarTest, Dummy)
+{
+}
+
+void PrintFlag(const char* flag)
+{
+ if (strcmp(flag, "break_on_failure") == 0) {
+ cout << GTEST_FLAG(break_on_failure);
+ return;
+ }
+
+ if (strcmp(flag, "catch_exceptions") == 0) {
+ cout << GTEST_FLAG(catch_exceptions);
+ return;
+ }
+
+ if (strcmp(flag, "color") == 0) {
+ cout << GTEST_FLAG(color);
+ return;
+ }
+
+ if (strcmp(flag, "death_test_style") == 0) {
+ cout << GTEST_FLAG(death_test_style);
+ return;
+ }
+
+ if (strcmp(flag, "death_test_use_fork") == 0) {
+ cout << GTEST_FLAG(death_test_use_fork);
+ return;
+ }
+
+ if (strcmp(flag, "filter") == 0) {
+ cout << GTEST_FLAG(filter);
+ return;
+ }
+
+ if (strcmp(flag, "output") == 0) {
+ cout << GTEST_FLAG(output);
+ return;
+ }
+
+ if (strcmp(flag, "print_time") == 0) {
+ cout << GTEST_FLAG(print_time);
+ return;
+ }
+
+ if (strcmp(flag, "repeat") == 0) {
+ cout << GTEST_FLAG(repeat);
+ return;
+ }
+
+ if (strcmp(flag, "stack_trace_depth") == 0) {
+ cout << GTEST_FLAG(stack_trace_depth);
+ return;
+ }
+
+ if (strcmp(flag, "throw_on_failure") == 0) {
+ cout << GTEST_FLAG(throw_on_failure);
+ return;
+ }
+
+ cout << "Invalid flag name " << flag
+ << ". Valid names are break_on_failure, color, filter, etc.\n";
+ exit(1);
+}
+
+} // namespace testing
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+
+ if (argc != 2) {
+ cout << "Usage: gtest_env_var_test_ NAME_OF_FLAG\n";
+ return 1;
+ }
+
+ testing::PrintFlag(argv[1]);
+ return 0;
+}
diff --git a/external/gtest-1.6.0/test/gtest_environment_test.cc b/external/gtest-1.6.0/test/gtest_environment_test.cc
new file mode 100644
index 0000000..087e6af
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_environment_test.cc
@@ -0,0 +1,199 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Tests using global test environments.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gtest/gtest.h"
+
+#define GTEST_IMPLEMENTATION_ 1 // Required for the next #include.
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+GTEST_DECLARE_string_(filter);
+}
+
+namespace
+{
+
+enum FailureType {
+ NO_FAILURE, NON_FATAL_FAILURE, FATAL_FAILURE
+};
+
+// For testing using global test environments.
+class MyEnvironment : public testing::Environment
+{
+ public:
+ MyEnvironment() { Reset(); }
+
+ // Depending on the value of failure_in_set_up_, SetUp() will
+ // generate a non-fatal failure, generate a fatal failure, or
+ // succeed.
+ virtual void SetUp() {
+ set_up_was_run_ = true;
+
+ switch (failure_in_set_up_) {
+ case NON_FATAL_FAILURE:
+ ADD_FAILURE() << "Expected non-fatal failure in global set-up.";
+ break;
+ case FATAL_FAILURE:
+ FAIL() << "Expected fatal failure in global set-up.";
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Generates a non-fatal failure.
+ virtual void TearDown() {
+ tear_down_was_run_ = true;
+ ADD_FAILURE() << "Expected non-fatal failure in global tear-down.";
+ }
+
+ // Resets the state of the environment s.t. it can be reused.
+ void Reset() {
+ failure_in_set_up_ = NO_FAILURE;
+ set_up_was_run_ = false;
+ tear_down_was_run_ = false;
+ }
+
+ // We call this function to set the type of failure SetUp() should
+ // generate.
+ void set_failure_in_set_up(FailureType type) {
+ failure_in_set_up_ = type;
+ }
+
+ // Was SetUp() run?
+ bool set_up_was_run() const { return set_up_was_run_; }
+
+ // Was TearDown() run?
+ bool tear_down_was_run() const { return tear_down_was_run_; }
+
+ private:
+ FailureType failure_in_set_up_;
+ bool set_up_was_run_;
+ bool tear_down_was_run_;
+};
+
+// Was the TEST run?
+bool test_was_run;
+
+// The sole purpose of this TEST is to enable us to check whether it
+// was run.
+TEST(FooTest, Bar)
+{
+ test_was_run = true;
+}
+
+// Prints the message and aborts the program if condition is false.
+void Check(bool condition, const char* msg)
+{
+ if (!condition) {
+ printf("FAILED: %s\n", msg);
+ testing::internal::posix::Abort();
+ }
+}
+
+// Runs the tests. Return true iff successful.
+//
+// The 'failure' parameter specifies the type of failure that should
+// be generated by the global set-up.
+int RunAllTests(MyEnvironment* env, FailureType failure)
+{
+ env->Reset();
+ env->set_failure_in_set_up(failure);
+ test_was_run = false;
+ testing::internal::GetUnitTestImpl()->ClearAdHocTestResult();
+ return RUN_ALL_TESTS();
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+
+ // Registers a global test environment, and verifies that the
+ // registration function returns its argument.
+ MyEnvironment* const env = new MyEnvironment;
+ Check(testing::AddGlobalTestEnvironment(env) == env,
+ "AddGlobalTestEnvironment() should return its argument.");
+
+ // Verifies that RUN_ALL_TESTS() runs the tests when the global
+ // set-up is successful.
+ Check(RunAllTests(env, NO_FAILURE) != 0,
+ "RUN_ALL_TESTS() should return non-zero, as the global tear-down "
+ "should generate a failure.");
+ Check(test_was_run,
+ "The tests should run, as the global set-up should generate no "
+ "failure");
+ Check(env->tear_down_was_run(),
+ "The global tear-down should run, as the global set-up was run.");
+
+ // Verifies that RUN_ALL_TESTS() runs the tests when the global
+ // set-up generates no fatal failure.
+ Check(RunAllTests(env, NON_FATAL_FAILURE) != 0,
+ "RUN_ALL_TESTS() should return non-zero, as both the global set-up "
+ "and the global tear-down should generate a non-fatal failure.");
+ Check(test_was_run,
+ "The tests should run, as the global set-up should generate no "
+ "fatal failure.");
+ Check(env->tear_down_was_run(),
+ "The global tear-down should run, as the global set-up was run.");
+
+ // Verifies that RUN_ALL_TESTS() runs no test when the global set-up
+ // generates a fatal failure.
+ Check(RunAllTests(env, FATAL_FAILURE) != 0,
+ "RUN_ALL_TESTS() should return non-zero, as the global set-up "
+ "should generate a fatal failure.");
+ Check(!test_was_run,
+ "The tests should not run, as the global set-up should generate "
+ "a fatal failure.");
+ Check(env->tear_down_was_run(),
+ "The global tear-down should run, as the global set-up was run.");
+
+ // Verifies that RUN_ALL_TESTS() doesn't do global set-up or
+ // tear-down when there is no test to run.
+ testing::GTEST_FLAG(filter) = "-*";
+ Check(RunAllTests(env, NO_FAILURE) == 0,
+ "RUN_ALL_TESTS() should return zero, as there is no test to run.");
+ Check(!env->set_up_was_run(),
+ "The global set-up should not run, as there is no test to run.");
+ Check(!env->tear_down_was_run(),
+ "The global tear-down should not run, "
+ "as the global set-up was not run.");
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/external/gtest-1.6.0/test/gtest_filter_unittest.py b/external/gtest-1.6.0/test/gtest_filter_unittest.py
new file mode 100755
index 0000000..0d1a770
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_filter_unittest.py
@@ -0,0 +1,633 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for Google Test test filters.
+
+A user can specify which test(s) in a Google Test program to run via either
+the GTEST_FILTER environment variable or the --gtest_filter flag.
+This script tests such functionality by invoking
+gtest_filter_unittest_ (a program written with Google Test) with different
+environments and command line flags.
+
+Note that test sharding may also influence which tests are filtered. Therefore,
+we test that here also.
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import re
+import sets
+import sys
+
+import gtest_test_utils
+
+# Constants.
+
+# Checks if this platform can pass empty environment variables to child
+# processes. We set an env variable to an empty string and invoke a python
+# script in a subprocess to print whether the variable is STILL in
+# os.environ. We then use 'eval' to parse the child's output so that an
+# exception is thrown if the input is anything other than 'True' nor 'False'.
+os.environ['EMPTY_VAR'] = ''
+child = gtest_test_utils.Subprocess(
+ [sys.executable, '-c', 'import os; print \'EMPTY_VAR\' in os.environ'])
+CAN_PASS_EMPTY_ENV = eval(child.output)
+
+
+# Check if this platform can unset environment variables in child processes.
+# We set an env variable to a non-empty string, unset it, and invoke
+# a python script in a subprocess to print whether the variable
+# is NO LONGER in os.environ.
+# We use 'eval' to parse the child's output so that an exception
+# is thrown if the input is neither 'True' nor 'False'.
+os.environ['UNSET_VAR'] = 'X'
+del os.environ['UNSET_VAR']
+child = gtest_test_utils.Subprocess(
+ [sys.executable, '-c', 'import os; print \'UNSET_VAR\' not in os.environ'])
+CAN_UNSET_ENV = eval(child.output)
+
+
+# Checks if we should test with an empty filter. This doesn't
+# make sense on platforms that cannot pass empty env variables (Win32)
+# and on platforms that cannot unset variables (since we cannot tell
+# the difference between "" and NULL -- Borland and Solaris < 5.10)
+CAN_TEST_EMPTY_FILTER = (CAN_PASS_EMPTY_ENV and CAN_UNSET_ENV)
+
+
+# The environment variable for specifying the test filters.
+FILTER_ENV_VAR = 'GTEST_FILTER'
+
+# The environment variables for test sharding.
+TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
+SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
+SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE'
+
+# The command line flag for specifying the test filters.
+FILTER_FLAG = 'gtest_filter'
+
+# The command line flag for including disabled tests.
+ALSO_RUN_DISABED_TESTS_FLAG = 'gtest_also_run_disabled_tests'
+
+# Command to run the gtest_filter_unittest_ program.
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_filter_unittest_')
+
+# Regex for determining whether parameterized tests are enabled in the binary.
+PARAM_TEST_REGEX = re.compile(r'/ParamTest')
+
+# Regex for parsing test case names from Google Test's output.
+TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)')
+
+# Regex for parsing test names from Google Test's output.
+TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)')
+
+# The command line flag to tell Google Test to output the list of tests it
+# will run.
+LIST_TESTS_FLAG = '--gtest_list_tests'
+
+# Indicates whether Google Test supports death tests.
+SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess(
+ [COMMAND, LIST_TESTS_FLAG]).output
+
+# Full names of all tests in gtest_filter_unittests_.
+PARAM_TESTS = [
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ 'SeqQ/ParamTest.TestX/0',
+ 'SeqQ/ParamTest.TestX/1',
+ 'SeqQ/ParamTest.TestY/0',
+ 'SeqQ/ParamTest.TestY/1',
+ ]
+
+DISABLED_TESTS = [
+ 'BarTest.DISABLED_TestFour',
+ 'BarTest.DISABLED_TestFive',
+ 'BazTest.DISABLED_TestC',
+ 'DISABLED_FoobarTest.Test1',
+ 'DISABLED_FoobarTest.DISABLED_Test2',
+ 'DISABLED_FoobarbazTest.TestA',
+ ]
+
+if SUPPORTS_DEATH_TESTS:
+ DEATH_TESTS = [
+ 'HasDeathTest.Test1',
+ 'HasDeathTest.Test2',
+ ]
+else:
+ DEATH_TESTS = []
+
+# All the non-disabled tests.
+ACTIVE_TESTS = [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ 'BazTest.TestB',
+ ] + DEATH_TESTS + PARAM_TESTS
+
+param_tests_present = None
+
+# Utilities.
+
+environ = os.environ.copy()
+
+
+def SetEnvVar(env_var, value):
+ """Sets the env variable to 'value'; unsets it when 'value' is None."""
+
+ if value is not None:
+ environ[env_var] = value
+ elif env_var in environ:
+ del environ[env_var]
+
+
+def RunAndReturnOutput(args = None):
+ """Runs the test program and returns its output."""
+
+ return gtest_test_utils.Subprocess([COMMAND] + (args or []),
+ env=environ).output
+
+
+def RunAndExtractTestList(args = None):
+ """Runs the test program and returns its exit code and a list of tests run."""
+
+ p = gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ)
+ tests_run = []
+ test_case = ''
+ test = ''
+ for line in p.output.split('\n'):
+ match = TEST_CASE_REGEX.match(line)
+ if match is not None:
+ test_case = match.group(1)
+ else:
+ match = TEST_REGEX.match(line)
+ if match is not None:
+ test = match.group(1)
+ tests_run.append(test_case + '.' + test)
+ return (tests_run, p.exit_code)
+
+
+def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs):
+ """Runs the given function and arguments in a modified environment."""
+ try:
+ original_env = environ.copy()
+ environ.update(extra_env)
+ return function(*args, **kwargs)
+ finally:
+ environ.clear()
+ environ.update(original_env)
+
+
+def RunWithSharding(total_shards, shard_index, command):
+ """Runs a test program shard and returns exit code and a list of tests run."""
+
+ extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index),
+ TOTAL_SHARDS_ENV_VAR: str(total_shards)}
+ return InvokeWithModifiedEnv(extra_env, RunAndExtractTestList, command)
+
+# The unit test.
+
+
+class GTestFilterUnitTest(gtest_test_utils.TestCase):
+ """Tests the env variable or the command line flag to filter tests."""
+
+ # Utilities.
+
+ def AssertSetEqual(self, lhs, rhs):
+ """Asserts that two sets are equal."""
+
+ for elem in lhs:
+ self.assert_(elem in rhs, '%s in %s' % (elem, rhs))
+
+ for elem in rhs:
+ self.assert_(elem in lhs, '%s in %s' % (elem, lhs))
+
+ def AssertPartitionIsValid(self, set_var, list_of_sets):
+ """Asserts that list_of_sets is a valid partition of set_var."""
+
+ full_partition = []
+ for slice_var in list_of_sets:
+ full_partition.extend(slice_var)
+ self.assertEqual(len(set_var), len(full_partition))
+ self.assertEqual(sets.Set(set_var), sets.Set(full_partition))
+
+ def AdjustForParameterizedTests(self, tests_to_run):
+ """Adjust tests_to_run in case value parameterized tests are disabled."""
+
+ global param_tests_present
+ if not param_tests_present:
+ return list(sets.Set(tests_to_run) - sets.Set(PARAM_TESTS))
+ else:
+ return tests_to_run
+
+ def RunAndVerify(self, gtest_filter, tests_to_run):
+ """Checks that the binary runs correct set of tests for a given filter."""
+
+ tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
+
+ # First, tests using the environment variable.
+
+ # Windows removes empty variables from the environment when passing it
+ # to a new process. This means it is impossible to pass an empty filter
+ # into a process using the environment variable. However, we can still
+ # test the case when the variable is not supplied (i.e., gtest_filter is
+ # None).
+ # pylint: disable-msg=C6403
+ if CAN_TEST_EMPTY_FILTER or gtest_filter != '':
+ SetEnvVar(FILTER_ENV_VAR, gtest_filter)
+ tests_run = RunAndExtractTestList()[0]
+ SetEnvVar(FILTER_ENV_VAR, None)
+ self.AssertSetEqual(tests_run, tests_to_run)
+ # pylint: enable-msg=C6403
+
+ # Next, tests using the command line flag.
+
+ if gtest_filter is None:
+ args = []
+ else:
+ args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)]
+
+ tests_run = RunAndExtractTestList(args)[0]
+ self.AssertSetEqual(tests_run, tests_to_run)
+
+ def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run,
+ args=None, check_exit_0=False):
+ """Checks that binary runs correct tests for the given filter and shard.
+
+ Runs all shards of gtest_filter_unittest_ with the given filter, and
+ verifies that the right set of tests were run. The union of tests run
+ on each shard should be identical to tests_to_run, without duplicates.
+
+ Args:
+ gtest_filter: A filter to apply to the tests.
+ total_shards: A total number of shards to split test run into.
+ tests_to_run: A set of tests expected to run.
+ args : Arguments to pass to the to the test binary.
+ check_exit_0: When set to a true value, make sure that all shards
+ return 0.
+ """
+
+ tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
+
+ # Windows removes empty variables from the environment when passing it
+ # to a new process. This means it is impossible to pass an empty filter
+ # into a process using the environment variable. However, we can still
+ # test the case when the variable is not supplied (i.e., gtest_filter is
+ # None).
+ # pylint: disable-msg=C6403
+ if CAN_TEST_EMPTY_FILTER or gtest_filter != '':
+ SetEnvVar(FILTER_ENV_VAR, gtest_filter)
+ partition = []
+ for i in range(0, total_shards):
+ (tests_run, exit_code) = RunWithSharding(total_shards, i, args)
+ if check_exit_0:
+ self.assertEqual(0, exit_code)
+ partition.append(tests_run)
+
+ self.AssertPartitionIsValid(tests_to_run, partition)
+ SetEnvVar(FILTER_ENV_VAR, None)
+ # pylint: enable-msg=C6403
+
+ def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run):
+ """Checks that the binary runs correct set of tests for the given filter.
+
+ Runs gtest_filter_unittest_ with the given filter, and enables
+ disabled tests. Verifies that the right set of tests were run.
+
+ Args:
+ gtest_filter: A filter to apply to the tests.
+ tests_to_run: A set of tests expected to run.
+ """
+
+ tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
+
+ # Construct the command line.
+ args = ['--%s' % ALSO_RUN_DISABED_TESTS_FLAG]
+ if gtest_filter is not None:
+ args.append('--%s=%s' % (FILTER_FLAG, gtest_filter))
+
+ tests_run = RunAndExtractTestList(args)[0]
+ self.AssertSetEqual(tests_run, tests_to_run)
+
+ def setUp(self):
+ """Sets up test case.
+
+ Determines whether value-parameterized tests are enabled in the binary and
+ sets the flags accordingly.
+ """
+
+ global param_tests_present
+ if param_tests_present is None:
+ param_tests_present = PARAM_TEST_REGEX.search(
+ RunAndReturnOutput()) is not None
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of not specifying the filter."""
+
+ self.RunAndVerify(None, ACTIVE_TESTS)
+
+ def testDefaultBehaviorWithShards(self):
+ """Tests the behavior without the filter, with sharding enabled."""
+
+ self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS)
+
+ def testEmptyFilter(self):
+ """Tests an empty filter."""
+
+ self.RunAndVerify('', [])
+ self.RunAndVerifyWithSharding('', 1, [])
+ self.RunAndVerifyWithSharding('', 2, [])
+
+ def testBadFilter(self):
+ """Tests a filter that matches nothing."""
+
+ self.RunAndVerify('BadFilter', [])
+ self.RunAndVerifyAllowingDisabled('BadFilter', [])
+
+ def testFullName(self):
+ """Tests filtering by full name."""
+
+ self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz'])
+ self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz'])
+ self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz'])
+
+ def testUniversalFilters(self):
+ """Tests filters that match everything."""
+
+ self.RunAndVerify('*', ACTIVE_TESTS)
+ self.RunAndVerify('*.*', ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS)
+ self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS)
+ self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS)
+
+ def testFilterByTestCase(self):
+ """Tests filtering by test case name."""
+
+ self.RunAndVerify('FooTest.*', ['FooTest.Abc', 'FooTest.Xyz'])
+
+ BAZ_TESTS = ['BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB']
+ self.RunAndVerify('BazTest.*', BAZ_TESTS)
+ self.RunAndVerifyAllowingDisabled('BazTest.*',
+ BAZ_TESTS + ['BazTest.DISABLED_TestC'])
+
+ def testFilterByTest(self):
+ """Tests filtering by test name."""
+
+ self.RunAndVerify('*.TestOne', ['BarTest.TestOne', 'BazTest.TestOne'])
+
+ def testFilterDisabledTests(self):
+ """Select only the disabled tests to run."""
+
+ self.RunAndVerify('DISABLED_FoobarTest.Test1', [])
+ self.RunAndVerifyAllowingDisabled('DISABLED_FoobarTest.Test1',
+ ['DISABLED_FoobarTest.Test1'])
+
+ self.RunAndVerify('*DISABLED_*', [])
+ self.RunAndVerifyAllowingDisabled('*DISABLED_*', DISABLED_TESTS)
+
+ self.RunAndVerify('*.DISABLED_*', [])
+ self.RunAndVerifyAllowingDisabled('*.DISABLED_*', [
+ 'BarTest.DISABLED_TestFour',
+ 'BarTest.DISABLED_TestFive',
+ 'BazTest.DISABLED_TestC',
+ 'DISABLED_FoobarTest.DISABLED_Test2',
+ ])
+
+ self.RunAndVerify('DISABLED_*', [])
+ self.RunAndVerifyAllowingDisabled('DISABLED_*', [
+ 'DISABLED_FoobarTest.Test1',
+ 'DISABLED_FoobarTest.DISABLED_Test2',
+ 'DISABLED_FoobarbazTest.TestA',
+ ])
+
+ def testWildcardInTestCaseName(self):
+ """Tests using wildcard in the test case name."""
+
+ self.RunAndVerify('*a*.*', [
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS)
+
+ def testWildcardInTestName(self):
+ """Tests using wildcard in the test name."""
+
+ self.RunAndVerify('*.*A*', ['FooTest.Abc', 'BazTest.TestA'])
+
+ def testFilterWithoutDot(self):
+ """Tests a filter that has no '.' in it."""
+
+ self.RunAndVerify('*z*', [
+ 'FooTest.Xyz',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ 'BazTest.TestB',
+ ])
+
+ def testTwoPatterns(self):
+ """Tests filters that consist of two patterns."""
+
+ self.RunAndVerify('Foo*.*:*A*', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BazTest.TestA',
+ ])
+
+ # An empty pattern + a non-empty one
+ self.RunAndVerify(':*A*', ['FooTest.Abc', 'BazTest.TestA'])
+
+ def testThreePatterns(self):
+ """Tests filters that consist of three patterns."""
+
+ self.RunAndVerify('*oo*:*A*:*One', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ ])
+
+ # The 2nd pattern is empty.
+ self.RunAndVerify('*oo*::*One', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+
+ 'BazTest.TestOne',
+ ])
+
+ # The last 2 patterns are empty.
+ self.RunAndVerify('*oo*::', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+ ])
+
+ def testNegativeFilters(self):
+ self.RunAndVerify('*-BazTest.TestOne', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+
+ 'BazTest.TestA',
+ 'BazTest.TestB',
+ ] + DEATH_TESTS + PARAM_TESTS)
+
+ self.RunAndVerify('*-FooTest.Abc:BazTest.*', [
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+ ] + DEATH_TESTS + PARAM_TESTS)
+
+ self.RunAndVerify('BarTest.*-BarTest.TestOne', [
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+ ])
+
+ # Tests without leading '*'.
+ self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+ ] + DEATH_TESTS + PARAM_TESTS)
+
+ # Value parameterized tests.
+ self.RunAndVerify('*/*', PARAM_TESTS)
+
+ # Value parameterized tests filtering by the sequence name.
+ self.RunAndVerify('SeqP/*', [
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ ])
+
+ # Value parameterized tests filtering by the test name.
+ self.RunAndVerify('*/0', [
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqQ/ParamTest.TestX/0',
+ 'SeqQ/ParamTest.TestY/0',
+ ])
+
+ def testFlagOverridesEnvVar(self):
+ """Tests that the filter flag overrides the filtering env. variable."""
+
+ SetEnvVar(FILTER_ENV_VAR, 'Foo*')
+ args = ['--%s=%s' % (FILTER_FLAG, '*One')]
+ tests_run = RunAndExtractTestList(args)[0]
+ SetEnvVar(FILTER_ENV_VAR, None)
+
+ self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne'])
+
+ def testShardStatusFileIsCreated(self):
+ """Tests that the shard file is created if specified in the environment."""
+
+ shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
+ 'shard_status_file')
+ self.assert_(not os.path.exists(shard_status_file))
+
+ extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
+ try:
+ InvokeWithModifiedEnv(extra_env, RunAndReturnOutput)
+ finally:
+ self.assert_(os.path.exists(shard_status_file))
+ os.remove(shard_status_file)
+
+ def testShardStatusFileIsCreatedWithListTests(self):
+ """Tests that the shard file is created with the "list_tests" flag."""
+
+ shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
+ 'shard_status_file2')
+ self.assert_(not os.path.exists(shard_status_file))
+
+ extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
+ try:
+ output = InvokeWithModifiedEnv(extra_env,
+ RunAndReturnOutput,
+ [LIST_TESTS_FLAG])
+ finally:
+ # This assertion ensures that Google Test enumerated the tests as
+ # opposed to running them.
+ self.assert_('[==========]' not in output,
+ 'Unexpected output during test enumeration.\n'
+ 'Please ensure that LIST_TESTS_FLAG is assigned the\n'
+ 'correct flag value for listing Google Test tests.')
+
+ self.assert_(os.path.exists(shard_status_file))
+ os.remove(shard_status_file)
+
+ if SUPPORTS_DEATH_TESTS:
+ def testShardingWorksWithDeathTests(self):
+ """Tests integration with death tests and sharding."""
+
+ gtest_filter = 'HasDeathTest.*:SeqP/*'
+ expected_tests = [
+ 'HasDeathTest.Test1',
+ 'HasDeathTest.Test2',
+
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ ]
+
+ for flag in ['--gtest_death_test_style=threadsafe',
+ '--gtest_death_test_style=fast']:
+ self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests,
+ check_exit_0=True, args=[flag])
+ self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests,
+ check_exit_0=True, args=[flag])
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_filter_unittest_.cc b/external/gtest-1.6.0/test/gtest_filter_unittest_.cc
new file mode 100644
index 0000000..ba3f49f
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_filter_unittest_.cc
@@ -0,0 +1,162 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Unit test for Google Test test filters.
+//
+// A user can specify which test(s) in a Google Test program to run via
+// either the GTEST_FILTER environment variable or the --gtest_filter
+// flag. This is used for testing such functionality.
+//
+// The program will be invoked from a Python unit test. Don't run it
+// directly.
+
+#include "gtest/gtest.h"
+
+namespace
+{
+
+// Test case FooTest.
+
+class FooTest : public testing::Test
+{
+};
+
+TEST_F(FooTest, Abc)
+{
+}
+
+TEST_F(FooTest, Xyz)
+{
+ FAIL() << "Expected failure.";
+}
+
+// Test case BarTest.
+
+TEST(BarTest, TestOne)
+{
+}
+
+TEST(BarTest, TestTwo)
+{
+}
+
+TEST(BarTest, TestThree)
+{
+}
+
+TEST(BarTest, DISABLED_TestFour)
+{
+ FAIL() << "Expected failure.";
+}
+
+TEST(BarTest, DISABLED_TestFive)
+{
+ FAIL() << "Expected failure.";
+}
+
+// Test case BazTest.
+
+TEST(BazTest, TestOne)
+{
+ FAIL() << "Expected failure.";
+}
+
+TEST(BazTest, TestA)
+{
+}
+
+TEST(BazTest, TestB)
+{
+}
+
+TEST(BazTest, DISABLED_TestC)
+{
+ FAIL() << "Expected failure.";
+}
+
+// Test case HasDeathTest
+
+TEST(HasDeathTest, Test1)
+{
+ EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*");
+}
+
+// We need at least two death tests to make sure that the all death tests
+// aren't on the first shard.
+TEST(HasDeathTest, Test2)
+{
+ EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*");
+}
+
+// Test case FoobarTest
+
+TEST(DISABLED_FoobarTest, Test1)
+{
+ FAIL() << "Expected failure.";
+}
+
+TEST(DISABLED_FoobarTest, DISABLED_Test2)
+{
+ FAIL() << "Expected failure.";
+}
+
+// Test case FoobarbazTest
+
+TEST(DISABLED_FoobarbazTest, TestA)
+{
+ FAIL() << "Expected failure.";
+}
+
+#if GTEST_HAS_PARAM_TEST
+class ParamTest : public testing::TestWithParam<int>
+{
+};
+
+TEST_P(ParamTest, TestX)
+{
+}
+
+TEST_P(ParamTest, TestY)
+{
+}
+
+INSTANTIATE_TEST_CASE_P(SeqP, ParamTest, testing::Values(1, 2));
+INSTANTIATE_TEST_CASE_P(SeqQ, ParamTest, testing::Values(5, 6));
+#endif // GTEST_HAS_PARAM_TEST
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_help_test.py b/external/gtest-1.6.0/test/gtest_help_test.py
new file mode 100755
index 0000000..093c838
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_help_test.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests the --help flag of Google C++ Testing Framework.
+
+SYNOPSIS
+ gtest_help_test.py --build_dir=BUILD/DIR
+ # where BUILD/DIR contains the built gtest_help_test_ file.
+ gtest_help_test.py
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import re
+import gtest_test_utils
+
+
+IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux'
+IS_WINDOWS = os.name == 'nt'
+
+PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_')
+FLAG_PREFIX = '--gtest_'
+DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style'
+STREAM_RESULT_TO_FLAG = FLAG_PREFIX + 'stream_result_to'
+UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing'
+LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests'
+INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG),
+ re.sub('^--', '/', LIST_TESTS_FLAG),
+ re.sub('_', '-', LIST_TESTS_FLAG)]
+INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing'
+
+SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess(
+ [PROGRAM_PATH, LIST_TESTS_FLAG]).output
+
+# The help message must match this regex.
+HELP_REGEX = re.compile(
+ FLAG_PREFIX + r'list_tests.*' +
+ FLAG_PREFIX + r'filter=.*' +
+ FLAG_PREFIX + r'also_run_disabled_tests.*' +
+ FLAG_PREFIX + r'repeat=.*' +
+ FLAG_PREFIX + r'shuffle.*' +
+ FLAG_PREFIX + r'random_seed=.*' +
+ FLAG_PREFIX + r'color=.*' +
+ FLAG_PREFIX + r'print_time.*' +
+ FLAG_PREFIX + r'output=.*' +
+ FLAG_PREFIX + r'break_on_failure.*' +
+ FLAG_PREFIX + r'throw_on_failure.*' +
+ FLAG_PREFIX + r'catch_exceptions=0.*',
+ re.DOTALL)
+
+
+def RunWithFlag(flag):
+ """Runs gtest_help_test_ with the given flag.
+
+ Returns:
+ the exit code and the text output as a tuple.
+ Args:
+ flag: the command-line flag to pass to gtest_help_test_, or None.
+ """
+
+ if flag is None:
+ command = [PROGRAM_PATH]
+ else:
+ command = [PROGRAM_PATH, flag]
+ child = gtest_test_utils.Subprocess(command)
+ return child.exit_code, child.output
+
+
+class GTestHelpTest(gtest_test_utils.TestCase):
+ """Tests the --help flag and its equivalent forms."""
+
+ def TestHelpFlag(self, flag):
+ """Verifies correct behavior when help flag is specified.
+
+ The right message must be printed and the tests must
+ skipped when the given flag is specified.
+
+ Args:
+ flag: A flag to pass to the binary or None.
+ """
+
+ exit_code, output = RunWithFlag(flag)
+ self.assertEquals(0, exit_code)
+ self.assert_(HELP_REGEX.search(output), output)
+
+ if IS_LINUX:
+ self.assert_(STREAM_RESULT_TO_FLAG in output, output)
+ else:
+ self.assert_(STREAM_RESULT_TO_FLAG not in output, output)
+
+ if SUPPORTS_DEATH_TESTS and not IS_WINDOWS:
+ self.assert_(DEATH_TEST_STYLE_FLAG in output, output)
+ else:
+ self.assert_(DEATH_TEST_STYLE_FLAG not in output, output)
+
+ def TestNonHelpFlag(self, flag):
+ """Verifies correct behavior when no help flag is specified.
+
+ Verifies that when no help flag is specified, the tests are run
+ and the help message is not printed.
+
+ Args:
+ flag: A flag to pass to the binary or None.
+ """
+
+ exit_code, output = RunWithFlag(flag)
+ self.assert_(exit_code != 0)
+ self.assert_(not HELP_REGEX.search(output), output)
+
+ def testPrintsHelpWithFullFlag(self):
+ self.TestHelpFlag('--help')
+
+ def testPrintsHelpWithShortFlag(self):
+ self.TestHelpFlag('-h')
+
+ def testPrintsHelpWithQuestionFlag(self):
+ self.TestHelpFlag('-?')
+
+ def testPrintsHelpWithWindowsStyleQuestionFlag(self):
+ self.TestHelpFlag('/?')
+
+ def testPrintsHelpWithUnrecognizedGoogleTestFlag(self):
+ self.TestHelpFlag(UNKNOWN_FLAG)
+
+ def testPrintsHelpWithIncorrectFlagStyle(self):
+ for incorrect_flag in INCORRECT_FLAG_VARIANTS:
+ self.TestHelpFlag(incorrect_flag)
+
+ def testRunsTestsWithoutHelpFlag(self):
+ """Verifies that when no help flag is specified, the tests are run
+ and the help message is not printed."""
+
+ self.TestNonHelpFlag(None)
+
+ def testRunsTestsWithGtestInternalFlag(self):
+ """Verifies that the tests are run and no help message is printed when
+ a flag starting with Google Test prefix and 'internal_' is supplied."""
+
+ self.TestNonHelpFlag(INTERNAL_FLAG_FOR_TESTING)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_help_test_.cc b/external/gtest-1.6.0/test/gtest_help_test_.cc
new file mode 100644
index 0000000..4476099
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_help_test_.cc
@@ -0,0 +1,47 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// This program is meant to be run by gtest_help_test.py. Do not run
+// it directly.
+
+#include "gtest/gtest.h"
+
+// When a help flag is specified, this program should skip the tests
+// and exit with 0; otherwise the following test will be executed,
+// causing this program to exit with a non-zero code.
+TEST(HelpFlagTest, ShouldNotBeRun)
+{
+ ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified.";
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {}
+#endif
diff --git a/external/gtest-1.6.0/test/gtest_list_tests_unittest.py b/external/gtest-1.6.0/test/gtest_list_tests_unittest.py
new file mode 100755
index 0000000..925b09d
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_list_tests_unittest.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for Google Test's --gtest_list_tests flag.
+
+A user can ask Google Test to list all tests by specifying the
+--gtest_list_tests flag. This script tests such functionality
+by invoking gtest_list_tests_unittest_ (a program written with
+Google Test) the command line flags.
+"""
+
+__author__ = 'phanna at google.com (Patrick Hanna)'
+
+import gtest_test_utils
+import re
+
+
+# Constants.
+
+# The command line flag for enabling/disabling listing all tests.
+LIST_TESTS_FLAG = 'gtest_list_tests'
+
+# Path to the gtest_list_tests_unittest_ program.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath('gtest_list_tests_unittest_')
+
+# The expected output when running gtest_list_tests_unittest_ with
+# --gtest_list_tests
+EXPECTED_OUTPUT_NO_FILTER_RE = re.compile(r"""FooDeathTest\.
+ Test1
+Foo\.
+ Bar1
+ Bar2
+ DISABLED_Bar3
+Abc\.
+ Xyz
+ Def
+FooBar\.
+ Baz
+FooTest\.
+ Test1
+ DISABLED_Test2
+ Test3
+TypedTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\.
+ TestA
+ TestB
+TypedTest/1\. # TypeParam = int\s*\*
+ TestA
+ TestB
+TypedTest/2\. # TypeParam = .*MyArray<bool,\s*42>
+ TestA
+ TestB
+My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\.
+ TestA
+ TestB
+My/TypeParamTest/1\. # TypeParam = int\s*\*
+ TestA
+ TestB
+My/TypeParamTest/2\. # TypeParam = .*MyArray<bool,\s*42>
+ TestA
+ TestB
+MyInstantiation/ValueParamTest\.
+ TestA/0 # GetParam\(\) = one line
+ TestA/1 # GetParam\(\) = two\\nlines
+ TestA/2 # GetParam\(\) = a very\\nlo{241}\.\.\.
+ TestB/0 # GetParam\(\) = one line
+ TestB/1 # GetParam\(\) = two\\nlines
+ TestB/2 # GetParam\(\) = a very\\nlo{241}\.\.\.
+""")
+
+# The expected output when running gtest_list_tests_unittest_ with
+# --gtest_list_tests and --gtest_filter=Foo*.
+EXPECTED_OUTPUT_FILTER_FOO_RE = re.compile(r"""FooDeathTest\.
+ Test1
+Foo\.
+ Bar1
+ Bar2
+ DISABLED_Bar3
+FooBar\.
+ Baz
+FooTest\.
+ Test1
+ DISABLED_Test2
+ Test3
+""")
+
+# Utilities.
+
+
+def Run(args):
+ """Runs gtest_list_tests_unittest_ and returns the list of tests printed."""
+
+ return gtest_test_utils.Subprocess([EXE_PATH] + args,
+ capture_stderr=False).output
+
+
+# The unit test.
+
+class GTestListTestsUnitTest(gtest_test_utils.TestCase):
+ """Tests using the --gtest_list_tests flag to list all tests."""
+
+ def RunAndVerify(self, flag_value, expected_output_re, other_flag):
+ """Runs gtest_list_tests_unittest_ and verifies that it prints
+ the correct tests.
+
+ Args:
+ flag_value: value of the --gtest_list_tests flag;
+ None if the flag should not be present.
+ expected_output_re: regular expression that matches the expected
+ output after running command;
+ other_flag: a different flag to be passed to command
+ along with gtest_list_tests;
+ None if the flag should not be present.
+ """
+
+ if flag_value is None:
+ flag = ''
+ flag_expression = 'not set'
+ elif flag_value == '0':
+ flag = '--%s=0' % LIST_TESTS_FLAG
+ flag_expression = '0'
+ else:
+ flag = '--%s' % LIST_TESTS_FLAG
+ flag_expression = '1'
+
+ args = [flag]
+
+ if other_flag is not None:
+ args += [other_flag]
+
+ output = Run(args)
+
+ if expected_output_re:
+ self.assert_(
+ expected_output_re.match(output),
+ ('when %s is %s, the output of "%s" is "%s",\n'
+ 'which does not match regex "%s"' %
+ (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output,
+ expected_output_re.pattern)))
+ else:
+ self.assert_(
+ not EXPECTED_OUTPUT_NO_FILTER_RE.match(output),
+ ('when %s is %s, the output of "%s" is "%s"'%
+ (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output)))
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of the default mode."""
+
+ self.RunAndVerify(flag_value=None,
+ expected_output_re=None,
+ other_flag=None)
+
+ def testFlag(self):
+ """Tests using the --gtest_list_tests flag."""
+
+ self.RunAndVerify(flag_value='0',
+ expected_output_re=None,
+ other_flag=None)
+ self.RunAndVerify(flag_value='1',
+ expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE,
+ other_flag=None)
+
+ def testOverrideNonFilterFlags(self):
+ """Tests that --gtest_list_tests overrides the non-filter flags."""
+
+ self.RunAndVerify(flag_value='1',
+ expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE,
+ other_flag='--gtest_break_on_failure')
+
+ def testWithFilterFlags(self):
+ """Tests that --gtest_list_tests takes into account the
+ --gtest_filter flag."""
+
+ self.RunAndVerify(flag_value='1',
+ expected_output_re=EXPECTED_OUTPUT_FILTER_FOO_RE,
+ other_flag='--gtest_filter=Foo*')
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_list_tests_unittest_.cc b/external/gtest-1.6.0/test/gtest_list_tests_unittest_.cc
new file mode 100644
index 0000000..07dbbd1
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_list_tests_unittest_.cc
@@ -0,0 +1,182 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: phanna at google.com (Patrick Hanna)
+
+// Unit test for Google Test's --gtest_list_tests flag.
+//
+// A user can ask Google Test to list all tests that will run
+// so that when using a filter, a user will know what
+// tests to look for. The tests will not be run after listing.
+//
+// This program will be invoked from a Python unit test.
+// Don't run it directly.
+
+#include "gtest/gtest.h"
+
+// Several different test cases and tests that will be listed.
+TEST(Foo, Bar1)
+{
+}
+
+TEST(Foo, Bar2)
+{
+}
+
+TEST(Foo, DISABLED_Bar3)
+{
+}
+
+TEST(Abc, Xyz)
+{
+}
+
+TEST(Abc, Def)
+{
+}
+
+TEST(FooBar, Baz)
+{
+}
+
+class FooTest : public testing::Test
+{
+};
+
+TEST_F(FooTest, Test1)
+{
+}
+
+TEST_F(FooTest, DISABLED_Test2)
+{
+}
+
+TEST_F(FooTest, Test3)
+{
+}
+
+TEST(FooDeathTest, Test1)
+{
+}
+
+// A group of value-parameterized tests.
+
+class MyType
+{
+ public:
+ explicit MyType(const std::string& a_value) : value_(a_value) {}
+
+ const std::string& value() const { return value_; }
+
+ private:
+ std::string value_;
+};
+
+// Teaches Google Test how to print a MyType.
+void PrintTo(const MyType& x, std::ostream* os)
+{
+ *os << x.value();
+}
+
+class ValueParamTest : public testing::TestWithParam<MyType>
+{
+};
+
+TEST_P(ValueParamTest, TestA)
+{
+}
+
+TEST_P(ValueParamTest, TestB)
+{
+}
+
+INSTANTIATE_TEST_CASE_P(
+ MyInstantiation, ValueParamTest,
+ testing::Values(MyType("one line"),
+ MyType("two\nlines"),
+ MyType("a very\nloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"))); // NOLINT
+
+// A group of typed tests.
+
+// A deliberately long type name for testing the line-truncating
+// behavior when printing a type parameter.
+class VeryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName // NOLINT
+{
+};
+
+template <typename T>
+class TypedTest : public testing::Test
+{
+};
+
+template <typename T, int kSize>
+class MyArray
+{
+};
+
+typedef testing::Types<VeryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName, // NOLINT
+ int*, MyArray<bool, 42> > MyTypes;
+
+TYPED_TEST_CASE(TypedTest, MyTypes);
+
+TYPED_TEST(TypedTest, TestA)
+{
+}
+
+TYPED_TEST(TypedTest, TestB)
+{
+}
+
+// A group of type-parameterized tests.
+
+template <typename T>
+class TypeParamTest : public testing::Test
+{
+};
+
+TYPED_TEST_CASE_P(TypeParamTest);
+
+TYPED_TEST_P(TypeParamTest, TestA)
+{
+}
+
+TYPED_TEST_P(TypeParamTest, TestB)
+{
+}
+
+REGISTER_TYPED_TEST_CASE_P(TypeParamTest, TestA, TestB);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, TypeParamTest, MyTypes);
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_main_unittest.cc b/external/gtest-1.6.0/test/gtest_main_unittest.cc
new file mode 100644
index 0000000..c426ab0
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_main_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest.h"
+
+// Tests that we don't have to define main() when we link to
+// gtest_main instead of gtest.
+
+namespace
+{
+
+TEST(GTestMainTest, ShouldSucceed)
+{
+}
+
+} // namespace
+
+// We are using the main() function defined in src/gtest_main.cc, so
+// we don't define it here.
diff --git a/external/gtest-1.6.0/test/gtest_no_test_unittest.cc b/external/gtest-1.6.0/test/gtest_no_test_unittest.cc
new file mode 100644
index 0000000..7a99326
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_no_test_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests that a Google Test program that has no test defined can run
+// successfully.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest.h"
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+
+ // An ad-hoc assertion outside of all tests.
+ //
+ // This serves three purposes:
+ //
+ // 1. It verifies that an ad-hoc assertion can be executed even if
+ // no test is defined.
+ // 2. It verifies that a failed ad-hoc assertion causes the test
+ // program to fail.
+ // 3. We had a bug where the XML output won't be generated if an
+ // assertion is executed before RUN_ALL_TESTS() is called, even
+ // though --gtest_output=xml is specified. This makes sure the
+ // bug is fixed and doesn't regress.
+ EXPECT_EQ(1, 2);
+
+ // The above EXPECT_EQ() should cause RUN_ALL_TESTS() to return non-zero.
+ return RUN_ALL_TESTS() ? 0 : 1;
+}
diff --git a/external/gtest-1.6.0/test/gtest_output_test.py b/external/gtest-1.6.0/test/gtest_output_test.py
new file mode 100755
index 0000000..f409e2a
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_output_test.py
@@ -0,0 +1,335 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests the text output of Google C++ Testing Framework.
+
+SYNOPSIS
+ gtest_output_test.py --build_dir=BUILD/DIR --gengolden
+ # where BUILD/DIR contains the built gtest_output_test_ file.
+ gtest_output_test.py --gengolden
+ gtest_output_test.py
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import re
+import sys
+import gtest_test_utils
+
+
+# The flag for generating the golden file
+GENGOLDEN_FLAG = '--gengolden'
+CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS'
+
+IS_WINDOWS = os.name == 'nt'
+
+# TODO(vladl at google.com): remove the _lin suffix.
+GOLDEN_NAME = 'gtest_output_test_golden_lin.txt'
+
+PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_')
+
+# At least one command we exercise must not have the
+# --gtest_internal_skip_environment_and_ad_hoc_tests flag.
+COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests'])
+COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes'])
+COMMAND_WITH_TIME = ({}, [PROGRAM_PATH,
+ '--gtest_print_time',
+ '--gtest_internal_skip_environment_and_ad_hoc_tests',
+ '--gtest_filter=FatalFailureTest.*:LoggingTest.*'])
+COMMAND_WITH_DISABLED = (
+ {}, [PROGRAM_PATH,
+ '--gtest_also_run_disabled_tests',
+ '--gtest_internal_skip_environment_and_ad_hoc_tests',
+ '--gtest_filter=*DISABLED_*'])
+COMMAND_WITH_SHARDING = (
+ {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'},
+ [PROGRAM_PATH,
+ '--gtest_internal_skip_environment_and_ad_hoc_tests',
+ '--gtest_filter=PassingTest.*'])
+
+GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME)
+
+
+def ToUnixLineEnding(s):
+ """Changes all Windows/Mac line endings in s to UNIX line endings."""
+
+ return s.replace('\r\n', '\n').replace('\r', '\n')
+
+
+def RemoveLocations(test_output):
+ """Removes all file location info from a Google Test program's output.
+
+ Args:
+ test_output: the output of a Google Test program.
+
+ Returns:
+ output with all file location info (in the form of
+ 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or
+ 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by
+ 'FILE_NAME:#: '.
+ """
+
+ return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output)
+
+
+def RemoveStackTraceDetails(output):
+ """Removes all stack traces from a Google Test program's output."""
+
+ # *? means "find the shortest string that matches".
+ return re.sub(r'Stack trace:(.|\n)*?\n\n',
+ 'Stack trace: (omitted)\n\n', output)
+
+
+def RemoveStackTraces(output):
+ """Removes all traces of stack traces from a Google Test program's output."""
+
+ # *? means "find the shortest string that matches".
+ return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output)
+
+
+def RemoveTime(output):
+ """Removes all time information from a Google Test program's output."""
+
+ return re.sub(r'\(\d+ ms', '(? ms', output)
+
+
+def RemoveTypeInfoDetails(test_output):
+ """Removes compiler-specific type info from Google Test program's output.
+
+ Args:
+ test_output: the output of a Google Test program.
+
+ Returns:
+ output with type information normalized to canonical form.
+ """
+
+ # some compilers output the name of type 'unsigned int' as 'unsigned'
+ return re.sub(r'unsigned int', 'unsigned', test_output)
+
+
+def NormalizeToCurrentPlatform(test_output):
+ """Normalizes platform specific output details for easier comparison."""
+
+ if IS_WINDOWS:
+ # Removes the color information that is not present on Windows.
+ test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output)
+ # Changes failure message headers into the Windows format.
+ test_output = re.sub(r': Failure\n', r': error: ', test_output)
+ # Changes file(line_number) to file:line_number.
+ test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output)
+
+ return test_output
+
+
+def RemoveTestCounts(output):
+ """Removes test counts from a Google Test program's output."""
+
+ output = re.sub(r'\d+ tests?, listed below',
+ '? tests, listed below', output)
+ output = re.sub(r'\d+ FAILED TESTS',
+ '? FAILED TESTS', output)
+ output = re.sub(r'\d+ tests? from \d+ test cases?',
+ '? tests from ? test cases', output)
+ output = re.sub(r'\d+ tests? from ([a-zA-Z_])',
+ r'? tests from \1', output)
+ return re.sub(r'\d+ tests?\.', '? tests.', output)
+
+
+def RemoveMatchingTests(test_output, pattern):
+ """Removes output of specified tests from a Google Test program's output.
+
+ This function strips not only the beginning and the end of a test but also
+ all output in between.
+
+ Args:
+ test_output: A string containing the test output.
+ pattern: A regex string that matches names of test cases or
+ tests to remove.
+
+ Returns:
+ Contents of test_output with tests whose names match pattern removed.
+ """
+
+ test_output = re.sub(
+ r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % (
+ pattern, pattern),
+ '',
+ test_output)
+ return re.sub(r'.*%s.*\n' % pattern, '', test_output)
+
+
+def NormalizeOutput(output):
+ """Normalizes output (the output of gtest_output_test_.exe)."""
+
+ output = ToUnixLineEnding(output)
+ output = RemoveLocations(output)
+ output = RemoveStackTraceDetails(output)
+ output = RemoveTime(output)
+ return output
+
+
+def GetShellCommandOutput(env_cmd):
+ """Runs a command in a sub-process, and returns its output in a string.
+
+ Args:
+ env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
+ environment variables to set, and element 1 is a string with
+ the command and any flags.
+
+ Returns:
+ A string with the command's combined standard and diagnostic output.
+ """
+
+ # Spawns cmd in a sub-process, and gets its standard I/O file objects.
+ # Set and save the environment properly.
+ environ = os.environ.copy()
+ environ.update(env_cmd[0])
+ p = gtest_test_utils.Subprocess(env_cmd[1], env=environ)
+
+ return p.output
+
+
+def GetCommandOutput(env_cmd):
+ """Runs a command and returns its output with all file location
+ info stripped off.
+
+ Args:
+ env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
+ environment variables to set, and element 1 is a string with
+ the command and any flags.
+ """
+
+ # Disables exception pop-ups on Windows.
+ environ, cmdline = env_cmd
+ environ = dict(environ) # Ensures we are modifying a copy.
+ environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1'
+ return NormalizeOutput(GetShellCommandOutput((environ, cmdline)))
+
+
+def GetOutputOfAllCommands():
+ """Returns concatenated output from several representative commands."""
+
+ return (GetCommandOutput(COMMAND_WITH_COLOR) +
+ GetCommandOutput(COMMAND_WITH_TIME) +
+ GetCommandOutput(COMMAND_WITH_DISABLED) +
+ GetCommandOutput(COMMAND_WITH_SHARDING))
+
+
+test_list = GetShellCommandOutput(COMMAND_LIST_TESTS)
+SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list
+SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list
+SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list
+SUPPORTS_STACK_TRACES = False
+
+CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and
+ SUPPORTS_TYPED_TESTS and
+ SUPPORTS_THREADS)
+
+
+class GTestOutputTest(gtest_test_utils.TestCase):
+ def RemoveUnsupportedTests(self, test_output):
+ if not SUPPORTS_DEATH_TESTS:
+ test_output = RemoveMatchingTests(test_output, 'DeathTest')
+ if not SUPPORTS_TYPED_TESTS:
+ test_output = RemoveMatchingTests(test_output, 'TypedTest')
+ test_output = RemoveMatchingTests(test_output, 'TypedDeathTest')
+ test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest')
+ if not SUPPORTS_THREADS:
+ test_output = RemoveMatchingTests(test_output,
+ 'ExpectFailureWithThreadsTest')
+ test_output = RemoveMatchingTests(test_output,
+ 'ScopedFakeTestPartResultReporterTest')
+ test_output = RemoveMatchingTests(test_output,
+ 'WorksConcurrently')
+ if not SUPPORTS_STACK_TRACES:
+ test_output = RemoveStackTraces(test_output)
+
+ return test_output
+
+ def testOutput(self):
+ output = GetOutputOfAllCommands()
+
+ golden_file = open(GOLDEN_PATH, 'rb')
+ # A mis-configured source control system can cause \r appear in EOL
+ # sequences when we read the golden file irrespective of an operating
+ # system used. Therefore, we need to strip those \r's from newlines
+ # unconditionally.
+ golden = ToUnixLineEnding(golden_file.read())
+ golden_file.close()
+
+ # We want the test to pass regardless of certain features being
+ # supported or not.
+
+ # We still have to remove type name specifics in all cases.
+ normalized_actual = RemoveTypeInfoDetails(output)
+ normalized_golden = RemoveTypeInfoDetails(golden)
+
+ if CAN_GENERATE_GOLDEN_FILE:
+ self.assertEqual(normalized_golden, normalized_actual)
+ else:
+ normalized_actual = NormalizeToCurrentPlatform(
+ RemoveTestCounts(normalized_actual))
+ normalized_golden = NormalizeToCurrentPlatform(
+ RemoveTestCounts(self.RemoveUnsupportedTests(normalized_golden)))
+
+ # This code is very handy when debugging golden file differences:
+ if os.getenv('DEBUG_GTEST_OUTPUT_TEST'):
+ open(os.path.join(
+ gtest_test_utils.GetSourceDir(),
+ '_gtest_output_test_normalized_actual.txt'), 'wb').write(
+ normalized_actual)
+ open(os.path.join(
+ gtest_test_utils.GetSourceDir(),
+ '_gtest_output_test_normalized_golden.txt'), 'wb').write(
+ normalized_golden)
+
+ self.assertEqual(normalized_golden, normalized_actual)
+
+
+if __name__ == '__main__':
+ if sys.argv[1:] == [GENGOLDEN_FLAG]:
+ if CAN_GENERATE_GOLDEN_FILE:
+ output = GetOutputOfAllCommands()
+ golden_file = open(GOLDEN_PATH, 'wb')
+ golden_file.write(output)
+ golden_file.close()
+ else:
+ message = (
+ """Unable to write a golden file when compiled in an environment
+that does not support all the required features (death tests, typed tests,
+and multiple threads). Please generate the golden file using a binary built
+with those features enabled.""")
+
+ sys.stderr.write(message)
+ sys.exit(1)
+ else:
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_output_test_.cc b/external/gtest-1.6.0/test/gtest_output_test_.cc
new file mode 100644
index 0000000..146174d
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_output_test_.cc
@@ -0,0 +1,1117 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The purpose of this file is to generate Google Test output under
+// various conditions. The output will then be verified by
+// gtest_output_test.py to ensure that Google Test generates the
+// desired messages. Therefore, most tests in this file are MEANT TO
+// FAIL.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#include <stdlib.h>
+
+#if GTEST_IS_THREADSAFE
+using testing::ScopedFakeTestPartResultReporter;
+using testing::TestPartResultArray;
+
+using testing::internal::Notification;
+using testing::internal::ThreadWithParam;
+#endif
+
+namespace posix = ::testing::internal::posix;
+using testing::internal::scoped_ptr;
+
+// Tests catching fatal failures.
+
+// A subroutine used by the following test.
+void TestEq1(int x)
+{
+ ASSERT_EQ(1, x);
+}
+
+// This function calls a test subroutine, catches the fatal failure it
+// generates, and then returns early.
+void TryTestSubroutine()
+{
+ // Calls a subrountine that yields a fatal failure.
+ TestEq1(2);
+
+ // Catches the fatal failure and aborts the test.
+ //
+ // The testing::Test:: prefix is necessary when calling
+ // HasFatalFailure() outside of a TEST, TEST_F, or test fixture.
+ if (testing::Test::HasFatalFailure()) return;
+
+ // If we get here, something is wrong.
+ FAIL() << "This should never be reached.";
+}
+
+TEST(PassingTest, PassingTest1)
+{
+}
+
+TEST(PassingTest, PassingTest2)
+{
+}
+
+// Tests that parameters of failing parameterized tests are printed in the
+// failing test summary.
+class FailingParamTest : public testing::TestWithParam<int> {};
+
+TEST_P(FailingParamTest, Fails)
+{
+ EXPECT_EQ(1, GetParam());
+}
+
+// This generates a test which will fail. Google Test is expected to print
+// its parameter when it outputs the list of all failed tests.
+INSTANTIATE_TEST_CASE_P(PrintingFailingParams,
+ FailingParamTest,
+ testing::Values(2));
+
+static const char kGoldenString[] = "\"Line\0 1\"\nLine 2";
+
+TEST(NonfatalFailureTest, EscapesStringOperands)
+{
+ std::string actual = "actual \"string\"";
+ EXPECT_EQ(kGoldenString, actual);
+
+ const char* golden = kGoldenString;
+ EXPECT_EQ(golden, actual);
+}
+
+// Tests catching a fatal failure in a subroutine.
+TEST(FatalFailureTest, FatalFailureInSubroutine)
+{
+ printf("(expecting a failure that x should be 1)\n");
+
+ TryTestSubroutine();
+}
+
+// Tests catching a fatal failure in a nested subroutine.
+TEST(FatalFailureTest, FatalFailureInNestedSubroutine)
+{
+ printf("(expecting a failure that x should be 1)\n");
+
+ // Calls a subrountine that yields a fatal failure.
+ TryTestSubroutine();
+
+ // Catches the fatal failure and aborts the test.
+ //
+ // When calling HasFatalFailure() inside a TEST, TEST_F, or test
+ // fixture, the testing::Test:: prefix is not needed.
+ if (HasFatalFailure()) return;
+
+ // If we get here, something is wrong.
+ FAIL() << "This should never be reached.";
+}
+
+// Tests HasFatalFailure() after a failed EXPECT check.
+TEST(FatalFailureTest, NonfatalFailureInSubroutine)
+{
+ printf("(expecting a failure on false)\n");
+ EXPECT_TRUE(false); // Generates a nonfatal failure
+ ASSERT_FALSE(HasFatalFailure()); // This should succeed.
+}
+
+// Tests interleaving user logging and Google Test assertions.
+TEST(LoggingTest, InterleavingLoggingAndAssertions)
+{
+ static const int a[4] = {
+ 3, 9, 2, 6
+ };
+
+ printf("(expecting 2 failures on (3) >= (a[i]))\n");
+ for (int i = 0; i < static_cast<int>(sizeof(a)/sizeof(*a)); i++) {
+ printf("i == %d\n", i);
+ EXPECT_GE(3, a[i]);
+ }
+}
+
+// Tests the SCOPED_TRACE macro.
+
+// A helper function for testing SCOPED_TRACE.
+void SubWithoutTrace(int n)
+{
+ EXPECT_EQ(1, n);
+ ASSERT_EQ(2, n);
+}
+
+// Another helper function for testing SCOPED_TRACE.
+void SubWithTrace(int n)
+{
+ SCOPED_TRACE(testing::Message() << "n = " << n);
+
+ SubWithoutTrace(n);
+}
+
+// Tests that SCOPED_TRACE() obeys lexical scopes.
+TEST(SCOPED_TRACETest, ObeysScopes)
+{
+ printf("(expected to fail)\n");
+
+ // There should be no trace before SCOPED_TRACE() is invoked.
+ ADD_FAILURE() << "This failure is expected, and shouldn't have a trace.";
+
+ {
+ SCOPED_TRACE("Expected trace");
+ // After SCOPED_TRACE(), a failure in the current scope should contain
+ // the trace.
+ ADD_FAILURE() << "This failure is expected, and should have a trace.";
+ }
+
+ // Once the control leaves the scope of the SCOPED_TRACE(), there
+ // should be no trace again.
+ ADD_FAILURE() << "This failure is expected, and shouldn't have a trace.";
+}
+
+// Tests that SCOPED_TRACE works inside a loop.
+TEST(SCOPED_TRACETest, WorksInLoop)
+{
+ printf("(expected to fail)\n");
+
+ for (int i = 1; i <= 2; i++) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+
+ SubWithoutTrace(i);
+ }
+}
+
+// Tests that SCOPED_TRACE works in a subroutine.
+TEST(SCOPED_TRACETest, WorksInSubroutine)
+{
+ printf("(expected to fail)\n");
+
+ SubWithTrace(1);
+ SubWithTrace(2);
+}
+
+// Tests that SCOPED_TRACE can be nested.
+TEST(SCOPED_TRACETest, CanBeNested)
+{
+ printf("(expected to fail)\n");
+
+ SCOPED_TRACE(""); // A trace without a message.
+
+ SubWithTrace(2);
+}
+
+// Tests that multiple SCOPED_TRACEs can be used in the same scope.
+TEST(SCOPED_TRACETest, CanBeRepeated)
+{
+ printf("(expected to fail)\n");
+
+ SCOPED_TRACE("A");
+ ADD_FAILURE()
+ << "This failure is expected, and should contain trace point A.";
+
+ SCOPED_TRACE("B");
+ ADD_FAILURE()
+ << "This failure is expected, and should contain trace point A and B.";
+
+ {
+ SCOPED_TRACE("C");
+ ADD_FAILURE() << "This failure is expected, and should "
+ << "contain trace point A, B, and C.";
+ }
+
+ SCOPED_TRACE("D");
+ ADD_FAILURE() << "This failure is expected, and should "
+ << "contain trace point A, B, and D.";
+}
+
+#if GTEST_IS_THREADSAFE
+// Tests that SCOPED_TRACE()s can be used concurrently from multiple
+// threads. Namely, an assertion should be affected by
+// SCOPED_TRACE()s in its own thread only.
+
+// Here's the sequence of actions that happen in the test:
+//
+// Thread A (main) | Thread B (spawned)
+// ===============================|================================
+// spawns thread B |
+// -------------------------------+--------------------------------
+// waits for n1 | SCOPED_TRACE("Trace B");
+// | generates failure #1
+// | notifies n1
+// -------------------------------+--------------------------------
+// SCOPED_TRACE("Trace A"); | waits for n2
+// generates failure #2 |
+// notifies n2 |
+// -------------------------------|--------------------------------
+// waits for n3 | generates failure #3
+// | trace B dies
+// | generates failure #4
+// | notifies n3
+// -------------------------------|--------------------------------
+// generates failure #5 | finishes
+// trace A dies |
+// generates failure #6 |
+// -------------------------------|--------------------------------
+// waits for thread B to finish |
+
+struct CheckPoints {
+ Notification n1;
+ Notification n2;
+ Notification n3;
+};
+
+static void ThreadWithScopedTrace(CheckPoints* check_points)
+{
+ {
+ SCOPED_TRACE("Trace B");
+ ADD_FAILURE()
+ << "Expected failure #1 (in thread B, only trace B alive).";
+ check_points->n1.Notify();
+ check_points->n2.WaitForNotification();
+
+ ADD_FAILURE()
+ << "Expected failure #3 (in thread B, trace A & B both alive).";
+ } // Trace B dies here.
+ ADD_FAILURE()
+ << "Expected failure #4 (in thread B, only trace A alive).";
+ check_points->n3.Notify();
+}
+
+TEST(SCOPED_TRACETest, WorksConcurrently)
+{
+ printf("(expecting 6 failures)\n");
+
+ CheckPoints check_points;
+ ThreadWithParam<CheckPoints*> thread(&ThreadWithScopedTrace,
+ &check_points,
+ NULL);
+ check_points.n1.WaitForNotification();
+
+ {
+ SCOPED_TRACE("Trace A");
+ ADD_FAILURE()
+ << "Expected failure #2 (in thread A, trace A & B both alive).";
+ check_points.n2.Notify();
+ check_points.n3.WaitForNotification();
+
+ ADD_FAILURE()
+ << "Expected failure #5 (in thread A, only trace A alive).";
+ } // Trace A dies here.
+ ADD_FAILURE()
+ << "Expected failure #6 (in thread A, no trace alive).";
+ thread.Join();
+}
+#endif // GTEST_IS_THREADSAFE
+
+TEST(DisabledTestsWarningTest,
+ DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning)
+{
+ // This test body is intentionally empty. Its sole purpose is for
+ // verifying that the --gtest_also_run_disabled_tests flag
+ // suppresses the "YOU HAVE 12 DISABLED TESTS" warning at the end of
+ // the test output.
+}
+
+// Tests using assertions outside of TEST and TEST_F.
+//
+// This function creates two failures intentionally.
+void AdHocTest()
+{
+ printf("The non-test part of the code is expected to have 2 failures.\n\n");
+ EXPECT_TRUE(false);
+ EXPECT_EQ(2, 3);
+}
+
+// Runs all TESTs, all TEST_Fs, and the ad hoc test.
+int RunAllTests()
+{
+ AdHocTest();
+ return RUN_ALL_TESTS();
+}
+
+// Tests non-fatal failures in the fixture constructor.
+class NonFatalFailureInFixtureConstructorTest : public testing::Test
+{
+ protected:
+ NonFatalFailureInFixtureConstructorTest() {
+ printf("(expecting 5 failures)\n");
+ ADD_FAILURE() << "Expected failure #1, in the test fixture c'tor.";
+ }
+
+ ~NonFatalFailureInFixtureConstructorTest() {
+ ADD_FAILURE() << "Expected failure #5, in the test fixture d'tor.";
+ }
+
+ virtual void SetUp() {
+ ADD_FAILURE() << "Expected failure #2, in SetUp().";
+ }
+
+ virtual void TearDown() {
+ ADD_FAILURE() << "Expected failure #4, in TearDown.";
+ }
+};
+
+TEST_F(NonFatalFailureInFixtureConstructorTest, FailureInConstructor)
+{
+ ADD_FAILURE() << "Expected failure #3, in the test body.";
+}
+
+// Tests fatal failures in the fixture constructor.
+class FatalFailureInFixtureConstructorTest : public testing::Test
+{
+ protected:
+ FatalFailureInFixtureConstructorTest() {
+ printf("(expecting 2 failures)\n");
+ Init();
+ }
+
+ ~FatalFailureInFixtureConstructorTest() {
+ ADD_FAILURE() << "Expected failure #2, in the test fixture d'tor.";
+ }
+
+ virtual void SetUp() {
+ ADD_FAILURE() << "UNEXPECTED failure in SetUp(). "
+ << "We should never get here, as the test fixture c'tor "
+ << "had a fatal failure.";
+ }
+
+ virtual void TearDown() {
+ ADD_FAILURE() << "UNEXPECTED failure in TearDown(). "
+ << "We should never get here, as the test fixture c'tor "
+ << "had a fatal failure.";
+ }
+
+ private:
+ void Init() {
+ FAIL() << "Expected failure #1, in the test fixture c'tor.";
+ }
+};
+
+TEST_F(FatalFailureInFixtureConstructorTest, FailureInConstructor)
+{
+ ADD_FAILURE() << "UNEXPECTED failure in the test body. "
+ << "We should never get here, as the test fixture c'tor "
+ << "had a fatal failure.";
+}
+
+// Tests non-fatal failures in SetUp().
+class NonFatalFailureInSetUpTest : public testing::Test
+{
+ protected:
+ virtual ~NonFatalFailureInSetUpTest() {
+ Deinit();
+ }
+
+ virtual void SetUp() {
+ printf("(expecting 4 failures)\n");
+ ADD_FAILURE() << "Expected failure #1, in SetUp().";
+ }
+
+ virtual void TearDown() {
+ FAIL() << "Expected failure #3, in TearDown().";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #4, in the test fixture d'tor.";
+ }
+};
+
+TEST_F(NonFatalFailureInSetUpTest, FailureInSetUp)
+{
+ FAIL() << "Expected failure #2, in the test function.";
+}
+
+// Tests fatal failures in SetUp().
+class FatalFailureInSetUpTest : public testing::Test
+{
+ protected:
+ virtual ~FatalFailureInSetUpTest() {
+ Deinit();
+ }
+
+ virtual void SetUp() {
+ printf("(expecting 3 failures)\n");
+ FAIL() << "Expected failure #1, in SetUp().";
+ }
+
+ virtual void TearDown() {
+ FAIL() << "Expected failure #2, in TearDown().";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #3, in the test fixture d'tor.";
+ }
+};
+
+TEST_F(FatalFailureInSetUpTest, FailureInSetUp)
+{
+ FAIL() << "UNEXPECTED failure in the test function. "
+ << "We should never get here, as SetUp() failed.";
+}
+
+TEST(AddFailureAtTest, MessageContainsSpecifiedFileAndLineNumber)
+{
+ ADD_FAILURE_AT("foo.cc", 42) << "Expected failure in foo.cc";
+}
+
+#if GTEST_IS_THREADSAFE
+
+// A unary function that may die.
+void DieIf(bool should_die)
+{
+ GTEST_CHECK_(!should_die) << " - death inside DieIf().";
+}
+
+// Tests running death tests in a multi-threaded context.
+
+// Used for coordination between the main and the spawn thread.
+struct SpawnThreadNotifications {
+ SpawnThreadNotifications() {}
+
+ Notification spawn_thread_started;
+ Notification spawn_thread_ok_to_terminate;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications);
+};
+
+// The function to be executed in the thread spawn by the
+// MultipleThreads test (below).
+static void ThreadRoutine(SpawnThreadNotifications* notifications)
+{
+ // Signals the main thread that this thread has started.
+ notifications->spawn_thread_started.Notify();
+
+ // Waits for permission to finish from the main thread.
+ notifications->spawn_thread_ok_to_terminate.WaitForNotification();
+}
+
+// This is a death-test test, but it's not named with a DeathTest
+// suffix. It starts threads which might interfere with later
+// death tests, so it must run after all other death tests.
+class DeathTestAndMultiThreadsTest : public testing::Test
+{
+ protected:
+ // Starts a thread and waits for it to begin.
+ virtual void SetUp() {
+ thread_.reset(new ThreadWithParam<SpawnThreadNotifications*>(
+ &ThreadRoutine, ¬ifications_, NULL));
+ notifications_.spawn_thread_started.WaitForNotification();
+ }
+ // Tells the thread to finish, and reaps it.
+ // Depending on the version of the thread library in use,
+ // a manager thread might still be left running that will interfere
+ // with later death tests. This is unfortunate, but this class
+ // cleans up after itself as best it can.
+ virtual void TearDown() {
+ notifications_.spawn_thread_ok_to_terminate.Notify();
+ }
+
+ private:
+ SpawnThreadNotifications notifications_;
+ scoped_ptr<ThreadWithParam<SpawnThreadNotifications*> > thread_;
+};
+
+#endif // GTEST_IS_THREADSAFE
+
+// The MixedUpTestCaseTest test case verifies that Google Test will fail a
+// test if it uses a different fixture class than what other tests in
+// the same test case use. It deliberately contains two fixture
+// classes with the same name but defined in different namespaces.
+
+// The MixedUpTestCaseWithSameTestNameTest test case verifies that
+// when the user defines two tests with the same test case name AND
+// same test name (but in different namespaces), the second test will
+// fail.
+
+namespace foo
+{
+
+class MixedUpTestCaseTest : public testing::Test
+{
+};
+
+TEST_F(MixedUpTestCaseTest, FirstTestFromNamespaceFoo) {}
+TEST_F(MixedUpTestCaseTest, SecondTestFromNamespaceFoo) {}
+
+class MixedUpTestCaseWithSameTestNameTest : public testing::Test
+{
+};
+
+TEST_F(MixedUpTestCaseWithSameTestNameTest,
+ TheSecondTestWithThisNameShouldFail) {}
+
+} // namespace foo
+
+namespace bar
+{
+
+class MixedUpTestCaseTest : public testing::Test
+{
+};
+
+// The following two tests are expected to fail. We rely on the
+// golden file to check that Google Test generates the right error message.
+TEST_F(MixedUpTestCaseTest, ThisShouldFail) {}
+TEST_F(MixedUpTestCaseTest, ThisShouldFailToo) {}
+
+class MixedUpTestCaseWithSameTestNameTest : public testing::Test
+{
+};
+
+// Expected to fail. We rely on the golden file to check that Google Test
+// generates the right error message.
+TEST_F(MixedUpTestCaseWithSameTestNameTest,
+ TheSecondTestWithThisNameShouldFail) {}
+
+} // namespace bar
+
+// The following two test cases verify that Google Test catches the user
+// error of mixing TEST and TEST_F in the same test case. The first
+// test case checks the scenario where TEST_F appears before TEST, and
+// the second one checks where TEST appears before TEST_F.
+
+class TEST_F_before_TEST_in_same_test_case : public testing::Test
+{
+};
+
+TEST_F(TEST_F_before_TEST_in_same_test_case, DefinedUsingTEST_F) {}
+
+// Expected to fail. We rely on the golden file to check that Google Test
+// generates the right error message.
+TEST(TEST_F_before_TEST_in_same_test_case, DefinedUsingTESTAndShouldFail) {}
+
+class TEST_before_TEST_F_in_same_test_case : public testing::Test
+{
+};
+
+TEST(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST) {}
+
+// Expected to fail. We rely on the golden file to check that Google Test
+// generates the right error message.
+TEST_F(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST_FAndShouldFail)
+{
+}
+
+// Used for testing EXPECT_NONFATAL_FAILURE() and EXPECT_FATAL_FAILURE().
+int global_integer = 0;
+
+// Tests that EXPECT_NONFATAL_FAILURE() can reference global variables.
+TEST(ExpectNonfatalFailureTest, CanReferenceGlobalVariables)
+{
+ global_integer = 0;
+ EXPECT_NONFATAL_FAILURE({
+ EXPECT_EQ(1, global_integer) << "Expected non-fatal failure.";
+ }, "Expected non-fatal failure.");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() can reference local variables
+// (static or not).
+TEST(ExpectNonfatalFailureTest, CanReferenceLocalVariables)
+{
+ int m = 0;
+ static int n;
+ n = 1;
+ EXPECT_NONFATAL_FAILURE({
+ EXPECT_EQ(m, n) << "Expected non-fatal failure.";
+ }, "Expected non-fatal failure.");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() succeeds when there is exactly
+// one non-fatal failure and no fatal failure.
+TEST(ExpectNonfatalFailureTest, SucceedsWhenThereIsOneNonfatalFailure)
+{
+ EXPECT_NONFATAL_FAILURE({
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }, "Expected non-fatal failure.");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when there is no
+// non-fatal failure.
+TEST(ExpectNonfatalFailureTest, FailsWhenThereIsNoNonfatalFailure)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ }, "");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when there are two
+// non-fatal failures.
+TEST(ExpectNonfatalFailureTest, FailsWhenThereAreTwoNonfatalFailures)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ ADD_FAILURE() << "Expected non-fatal failure 1.";
+ ADD_FAILURE() << "Expected non-fatal failure 2.";
+ }, "");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when there is one fatal
+// failure.
+TEST(ExpectNonfatalFailureTest, FailsWhenThereIsOneFatalFailure)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ FAIL() << "Expected fatal failure.";
+ }, "");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being
+// tested returns.
+TEST(ExpectNonfatalFailureTest, FailsWhenStatementReturns)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ return;
+ }, "");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being
+// tested throws.
+TEST(ExpectNonfatalFailureTest, FailsWhenStatementThrows)
+{
+ printf("(expecting a failure)\n");
+ try {
+ EXPECT_NONFATAL_FAILURE({
+ throw 0;
+ }, "");
+ } catch (int) { // NOLINT
+ }
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Tests that EXPECT_FATAL_FAILURE() can reference global variables.
+TEST(ExpectFatalFailureTest, CanReferenceGlobalVariables)
+{
+ global_integer = 0;
+ EXPECT_FATAL_FAILURE({
+ ASSERT_EQ(1, global_integer) << "Expected fatal failure.";
+ }, "Expected fatal failure.");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() can reference local static
+// variables.
+TEST(ExpectFatalFailureTest, CanReferenceLocalStaticVariables)
+{
+ static int n;
+ n = 1;
+ EXPECT_FATAL_FAILURE({
+ ASSERT_EQ(0, n) << "Expected fatal failure.";
+ }, "Expected fatal failure.");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() succeeds when there is exactly
+// one fatal failure and no non-fatal failure.
+TEST(ExpectFatalFailureTest, SucceedsWhenThereIsOneFatalFailure)
+{
+ EXPECT_FATAL_FAILURE({
+ FAIL() << "Expected fatal failure.";
+ }, "Expected fatal failure.");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when there is no fatal
+// failure.
+TEST(ExpectFatalFailureTest, FailsWhenThereIsNoFatalFailure)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ }, "");
+}
+
+// A helper for generating a fatal failure.
+void FatalFailure()
+{
+ FAIL() << "Expected fatal failure.";
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when there are two
+// fatal failures.
+TEST(ExpectFatalFailureTest, FailsWhenThereAreTwoFatalFailures)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ FatalFailure();
+ FatalFailure();
+ }, "");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when there is one non-fatal
+// failure.
+TEST(ExpectFatalFailureTest, FailsWhenThereIsOneNonfatalFailure)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }, "");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when the statement being
+// tested returns.
+TEST(ExpectFatalFailureTest, FailsWhenStatementReturns)
+{
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ return;
+ }, "");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests that EXPECT_FATAL_FAILURE() fails when the statement being
+// tested throws.
+TEST(ExpectFatalFailureTest, FailsWhenStatementThrows)
+{
+ printf("(expecting a failure)\n");
+ try {
+ EXPECT_FATAL_FAILURE({
+ throw 0;
+ }, "");
+ } catch (int) { // NOLINT
+ }
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// This #ifdef block tests the output of typed tests.
+#if GTEST_HAS_TYPED_TEST
+
+template <typename T>
+class TypedTest : public testing::Test
+{
+};
+
+TYPED_TEST_CASE(TypedTest, testing::Types<int>);
+
+TYPED_TEST(TypedTest, Success)
+{
+ EXPECT_EQ(0, TypeParam());
+}
+
+TYPED_TEST(TypedTest, Failure)
+{
+ EXPECT_EQ(1, TypeParam()) << "Expected failure";
+}
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// This #ifdef block tests the output of type-parameterized tests.
+#if GTEST_HAS_TYPED_TEST_P
+
+template <typename T>
+class TypedTestP : public testing::Test
+{
+};
+
+TYPED_TEST_CASE_P(TypedTestP);
+
+TYPED_TEST_P(TypedTestP, Success)
+{
+ EXPECT_EQ(0U, TypeParam());
+}
+
+TYPED_TEST_P(TypedTestP, Failure)
+{
+ EXPECT_EQ(1U, TypeParam()) << "Expected failure";
+}
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure);
+
+typedef testing::Types<unsigned char, unsigned int> UnsignedTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#if GTEST_HAS_DEATH_TEST
+
+// We rely on the golden file to verify that tests whose test case
+// name ends with DeathTest are run first.
+
+TEST(ADeathTest, ShouldRunFirst)
+{
+}
+
+# if GTEST_HAS_TYPED_TEST
+
+// We rely on the golden file to verify that typed tests whose test
+// case name ends with DeathTest are run first.
+
+template <typename T>
+class ATypedDeathTest : public testing::Test
+{
+};
+
+typedef testing::Types<int, double> NumericTypes;
+TYPED_TEST_CASE(ATypedDeathTest, NumericTypes);
+
+TYPED_TEST(ATypedDeathTest, ShouldRunFirst)
+{
+}
+
+# endif // GTEST_HAS_TYPED_TEST
+
+# if GTEST_HAS_TYPED_TEST_P
+
+
+// We rely on the golden file to verify that type-parameterized tests
+// whose test case name ends with DeathTest are run first.
+
+template <typename T>
+class ATypeParamDeathTest : public testing::Test
+{
+};
+
+TYPED_TEST_CASE_P(ATypeParamDeathTest);
+
+TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst)
+{
+}
+
+REGISTER_TYPED_TEST_CASE_P(ATypeParamDeathTest, ShouldRunFirst);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, ATypeParamDeathTest, NumericTypes);
+
+# endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Tests various failure conditions of
+// EXPECT_{,NON}FATAL_FAILURE{,_ON_ALL_THREADS}.
+class ExpectFailureTest : public testing::Test
+{
+ public: // Must be public and not protected due to a bug in g++ 3.4.2.
+ enum FailureMode {
+ FATAL_FAILURE,
+ NONFATAL_FAILURE
+ };
+ static void AddFailure(FailureMode failure) {
+ if (failure == FATAL_FAILURE) {
+ FAIL() << "Expected fatal failure.";
+ } else {
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }
+ }
+};
+
+TEST_F(ExpectFailureTest, ExpectFatalFailure)
+{
+ // Expected fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE(SUCCEED(), "Expected fatal failure.");
+ // Expected fatal failure, but got a non-fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Expected non-fatal "
+ "failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE(AddFailure(FATAL_FAILURE), "Some other fatal failure "
+ "expected.");
+}
+
+TEST_F(ExpectFailureTest, ExpectNonFatalFailure)
+{
+ // Expected non-fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE(SUCCEED(), "Expected non-fatal failure.");
+ // Expected non-fatal failure, but got a fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE(AddFailure(FATAL_FAILURE), "Expected fatal failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Some other non-fatal "
+ "failure.");
+}
+
+#if GTEST_IS_THREADSAFE
+
+class ExpectFailureWithThreadsTest : public ExpectFailureTest
+{
+ protected:
+ static void AddFailureInOtherThread(FailureMode failure) {
+ ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL);
+ thread.Join();
+ }
+};
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailure)
+{
+ // We only intercept the current thread.
+ printf("(expecting 2 failures)\n");
+ EXPECT_FATAL_FAILURE(AddFailureInOtherThread(FATAL_FAILURE),
+ "Expected fatal failure.");
+}
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailure)
+{
+ // We only intercept the current thread.
+ printf("(expecting 2 failures)\n");
+ EXPECT_NONFATAL_FAILURE(AddFailureInOtherThread(NONFATAL_FAILURE),
+ "Expected non-fatal failure.");
+}
+
+typedef ExpectFailureWithThreadsTest ScopedFakeTestPartResultReporterTest;
+
+// Tests that the ScopedFakeTestPartResultReporter only catches failures from
+// the current thread if it is instantiated with INTERCEPT_ONLY_CURRENT_THREAD.
+TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread)
+{
+ printf("(expecting 2 failures)\n");
+ TestPartResultArray results;
+ {
+ ScopedFakeTestPartResultReporter reporter(
+ ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD,
+ &results);
+ AddFailureInOtherThread(FATAL_FAILURE);
+ AddFailureInOtherThread(NONFATAL_FAILURE);
+ }
+ // The two failures should not have been intercepted.
+ EXPECT_EQ(0, results.size()) << "This shouldn't fail.";
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads)
+{
+ // Expected fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected fatal failure.");
+ // Expected fatal failure, but got a non-fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE),
+ "Expected non-fatal failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE),
+ "Some other fatal failure expected.");
+}
+
+TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads)
+{
+ // Expected non-fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected non-fatal "
+ "failure.");
+ // Expected non-fatal failure, but got a fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE),
+ "Expected fatal failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE),
+ "Some other non-fatal failure.");
+}
+
+
+// Two test environments for testing testing::AddGlobalTestEnvironment().
+
+class FooEnvironment : public testing::Environment
+{
+ public:
+ virtual void SetUp() {
+ printf("%s", "FooEnvironment::SetUp() called.\n");
+ }
+
+ virtual void TearDown() {
+ printf("%s", "FooEnvironment::TearDown() called.\n");
+ FAIL() << "Expected fatal failure.";
+ }
+};
+
+class BarEnvironment : public testing::Environment
+{
+ public:
+ virtual void SetUp() {
+ printf("%s", "BarEnvironment::SetUp() called.\n");
+ }
+
+ virtual void TearDown() {
+ printf("%s", "BarEnvironment::TearDown() called.\n");
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }
+};
+
+bool GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = false;
+
+// The main function.
+//
+// The idea is to use Google Test to run all the tests we have defined (some
+// of them are intended to fail), and then compare the test results
+// with the "golden" file.
+int main(int argc, char** argv)
+{
+ testing::GTEST_FLAG(print_time) = false;
+
+ // We just run the tests, knowing some of them are intended to fail.
+ // We will use a separate Python script to compare the output of
+ // this program with the golden file.
+
+ // It's hard to test InitGoogleTest() directly, as it has many
+ // global side effects. The following line serves as a sanity test
+ // for it.
+ testing::InitGoogleTest(&argc, argv);
+ if (argc >= 2 &&
+ (std::string(argv[1]) ==
+ "--gtest_internal_skip_environment_and_ad_hoc_tests"))
+ GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = true;
+
+#if GTEST_HAS_DEATH_TEST
+ if (testing::internal::GTEST_FLAG(internal_run_death_test) != "") {
+ // Skip the usual output capturing if we're running as the child
+ // process of an threadsafe-style death test.
+# if GTEST_OS_WINDOWS
+ posix::FReopen("nul:", "w", stdout);
+# else
+ posix::FReopen("/dev/null", "w", stdout);
+# endif // GTEST_OS_WINDOWS
+ return RUN_ALL_TESTS();
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ if (GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests))
+ return RUN_ALL_TESTS();
+
+ // Registers two global test environments.
+ // The golden file verifies that they are set up in the order they
+ // are registered, and torn down in the reverse order.
+ testing::AddGlobalTestEnvironment(new FooEnvironment);
+ testing::AddGlobalTestEnvironment(new BarEnvironment);
+
+ return RunAllTests();
+}
diff --git a/external/gtest-1.6.0/test/gtest_output_test_golden_lin.txt b/external/gtest-1.6.0/test/gtest_output_test_golden_lin.txt
new file mode 100644
index 0000000..960eedc
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_output_test_golden_lin.txt
@@ -0,0 +1,720 @@
+The non-test part of the code is expected to have 2 failures.
+
+gtest_output_test_.cc:#: Failure
+Value of: false
+ Actual: false
+Expected: true
+gtest_output_test_.cc:#: Failure
+Value of: 3
+Expected: 2
+[0;32m[==========] [mRunning 63 tests from 28 test cases.
+[0;32m[----------] [mGlobal test environment set-up.
+FooEnvironment::SetUp() called.
+BarEnvironment::SetUp() called.
+[0;32m[----------] [m1 test from ADeathTest
+[0;32m[ RUN ] [mADeathTest.ShouldRunFirst
+[0;32m[ OK ] [mADeathTest.ShouldRunFirst
+[0;32m[----------] [m1 test from ATypedDeathTest/0, where TypeParam = int
+[0;32m[ RUN ] [mATypedDeathTest/0.ShouldRunFirst
+[0;32m[ OK ] [mATypedDeathTest/0.ShouldRunFirst
+[0;32m[----------] [m1 test from ATypedDeathTest/1, where TypeParam = double
+[0;32m[ RUN ] [mATypedDeathTest/1.ShouldRunFirst
+[0;32m[ OK ] [mATypedDeathTest/1.ShouldRunFirst
+[0;32m[----------] [m1 test from My/ATypeParamDeathTest/0, where TypeParam = int
+[0;32m[ RUN ] [mMy/ATypeParamDeathTest/0.ShouldRunFirst
+[0;32m[ OK ] [mMy/ATypeParamDeathTest/0.ShouldRunFirst
+[0;32m[----------] [m1 test from My/ATypeParamDeathTest/1, where TypeParam = double
+[0;32m[ RUN ] [mMy/ATypeParamDeathTest/1.ShouldRunFirst
+[0;32m[ OK ] [mMy/ATypeParamDeathTest/1.ShouldRunFirst
+[0;32m[----------] [m2 tests from PassingTest
+[0;32m[ RUN ] [mPassingTest.PassingTest1
+[0;32m[ OK ] [mPassingTest.PassingTest1
+[0;32m[ RUN ] [mPassingTest.PassingTest2
+[0;32m[ OK ] [mPassingTest.PassingTest2
+[0;32m[----------] [m1 test from NonfatalFailureTest
+[0;32m[ RUN ] [mNonfatalFailureTest.EscapesStringOperands
+gtest_output_test_.cc:#: Failure
+Value of: actual
+ Actual: "actual \"string\""
+Expected: kGoldenString
+Which is: "\"Line"
+gtest_output_test_.cc:#: Failure
+Value of: actual
+ Actual: "actual \"string\""
+Expected: golden
+Which is: "\"Line"
+[0;31m[ FAILED ] [mNonfatalFailureTest.EscapesStringOperands
+[0;32m[----------] [m3 tests from FatalFailureTest
+[0;32m[ RUN ] [mFatalFailureTest.FatalFailureInSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInSubroutine
+[0;32m[ RUN ] [mFatalFailureTest.FatalFailureInNestedSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInNestedSubroutine
+[0;32m[ RUN ] [mFatalFailureTest.NonfatalFailureInSubroutine
+(expecting a failure on false)
+gtest_output_test_.cc:#: Failure
+Value of: false
+ Actual: false
+Expected: true
+[0;31m[ FAILED ] [mFatalFailureTest.NonfatalFailureInSubroutine
+[0;32m[----------] [m1 test from LoggingTest
+[0;32m[ RUN ] [mLoggingTest.InterleavingLoggingAndAssertions
+(expecting 2 failures on (3) >= (a[i]))
+i == 0
+i == 1
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 9
+i == 2
+i == 3
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 6
+[0;31m[ FAILED ] [mLoggingTest.InterleavingLoggingAndAssertions
+[0;32m[----------] [m6 tests from SCOPED_TRACETest
+[0;32m[ RUN ] [mSCOPED_TRACETest.ObeysScopes
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and shouldn't have a trace.
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should have a trace.
+Google Test trace:
+gtest_output_test_.cc:#: Expected trace
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and shouldn't have a trace.
+[0;31m[ FAILED ] [mSCOPED_TRACETest.ObeysScopes
+[0;32m[ RUN ] [mSCOPED_TRACETest.WorksInLoop
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 1
+Expected: 2
+Google Test trace:
+gtest_output_test_.cc:#: i = 1
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: i = 2
+[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksInLoop
+[0;32m[ RUN ] [mSCOPED_TRACETest.WorksInSubroutine
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 1
+Expected: 2
+Google Test trace:
+gtest_output_test_.cc:#: n = 1
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: n = 2
+[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksInSubroutine
+[0;32m[ RUN ] [mSCOPED_TRACETest.CanBeNested
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: n = 2
+gtest_output_test_.cc:#:
+[0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeNested
+[0;32m[ RUN ] [mSCOPED_TRACETest.CanBeRepeated
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A.
+Google Test trace:
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A and B.
+Google Test trace:
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A, B, and C.
+Google Test trace:
+gtest_output_test_.cc:#: C
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A, B, and D.
+Google Test trace:
+gtest_output_test_.cc:#: D
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+[0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeRepeated
+[0;32m[ RUN ] [mSCOPED_TRACETest.WorksConcurrently
+(expecting 6 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1 (in thread B, only trace B alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace B
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2 (in thread A, trace A & B both alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace A
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3 (in thread B, trace A & B both alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace B
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #4 (in thread B, only trace A alive).
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #5 (in thread A, only trace A alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace A
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #6 (in thread A, no trace alive).
+[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksConcurrently
+[0;32m[----------] [m1 test from NonFatalFailureInFixtureConstructorTest
+[0;32m[ RUN ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor
+(expecting 5 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in the test fixture c'tor.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in SetUp().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3, in the test body.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #4, in TearDown.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #5, in the test fixture d'tor.
+[0;31m[ FAILED ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor
+[0;32m[----------] [m1 test from FatalFailureInFixtureConstructorTest
+[0;32m[ RUN ] [mFatalFailureInFixtureConstructorTest.FailureInConstructor
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in the test fixture c'tor.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in the test fixture d'tor.
+[0;31m[ FAILED ] [mFatalFailureInFixtureConstructorTest.FailureInConstructor
+[0;32m[----------] [m1 test from NonFatalFailureInSetUpTest
+[0;32m[ RUN ] [mNonFatalFailureInSetUpTest.FailureInSetUp
+(expecting 4 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in SetUp().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in the test function.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3, in TearDown().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #4, in the test fixture d'tor.
+[0;31m[ FAILED ] [mNonFatalFailureInSetUpTest.FailureInSetUp
+[0;32m[----------] [m1 test from FatalFailureInSetUpTest
+[0;32m[ RUN ] [mFatalFailureInSetUpTest.FailureInSetUp
+(expecting 3 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in SetUp().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in TearDown().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3, in the test fixture d'tor.
+[0;31m[ FAILED ] [mFatalFailureInSetUpTest.FailureInSetUp
+[0;32m[----------] [m1 test from AddFailureAtTest
+[0;32m[ RUN ] [mAddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber
+foo.cc:42: Failure
+Failed
+Expected failure in foo.cc
+[0;31m[ FAILED ] [mAddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber
+[0;32m[----------] [m4 tests from MixedUpTestCaseTest
+[0;32m[ RUN ] [mMixedUpTestCaseTest.FirstTestFromNamespaceFoo
+[0;32m[ OK ] [mMixedUpTestCaseTest.FirstTestFromNamespaceFoo
+[0;32m[ RUN ] [mMixedUpTestCaseTest.SecondTestFromNamespaceFoo
+[0;32m[ OK ] [mMixedUpTestCaseTest.SecondTestFromNamespaceFoo
+[0;32m[ RUN ] [mMixedUpTestCaseTest.ThisShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseTest,
+you defined test FirstTestFromNamespaceFoo and test ThisShouldFail
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[0;31m[ FAILED ] [mMixedUpTestCaseTest.ThisShouldFail
+[0;32m[ RUN ] [mMixedUpTestCaseTest.ThisShouldFailToo
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseTest,
+you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[0;31m[ FAILED ] [mMixedUpTestCaseTest.ThisShouldFailToo
+[0;32m[----------] [m2 tests from MixedUpTestCaseWithSameTestNameTest
+[0;32m[ RUN ] [mMixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[0;32m[ OK ] [mMixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[0;32m[ RUN ] [mMixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseWithSameTestNameTest,
+you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[0;31m[ FAILED ] [mMixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[0;32m[----------] [m2 tests from TEST_F_before_TEST_in_same_test_case
+[0;32m[ RUN ] [mTEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F
+[0;32m[ OK ] [mTEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F
+[0;32m[ RUN ] [mTEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class, so mixing TEST_F and TEST in the same test case is
+illegal. In test case TEST_F_before_TEST_in_same_test_case,
+test DefinedUsingTEST_F is defined using TEST_F but
+test DefinedUsingTESTAndShouldFail is defined using TEST. You probably
+want to change the TEST to TEST_F or move it to another test
+case.
+[0;31m[ FAILED ] [mTEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+[0;32m[----------] [m2 tests from TEST_before_TEST_F_in_same_test_case
+[0;32m[ RUN ] [mTEST_before_TEST_F_in_same_test_case.DefinedUsingTEST
+[0;32m[ OK ] [mTEST_before_TEST_F_in_same_test_case.DefinedUsingTEST
+[0;32m[ RUN ] [mTEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class, so mixing TEST_F and TEST in the same test case is
+illegal. In test case TEST_before_TEST_F_in_same_test_case,
+test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but
+test DefinedUsingTEST is defined using TEST. You probably
+want to change the TEST to TEST_F or move it to another test
+case.
+[0;31m[ FAILED ] [mTEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+[0;32m[----------] [m8 tests from ExpectNonfatalFailureTest
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.CanReferenceGlobalVariables
+[0;32m[ OK ] [mExpectNonfatalFailureTest.CanReferenceGlobalVariables
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.CanReferenceLocalVariables
+[0;32m[ OK ] [mExpectNonfatalFailureTest.CanReferenceLocalVariables
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure
+[0;32m[ OK ] [mExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 2 failures
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure 1.
+
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure 2.
+
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.FailsWhenStatementReturns
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenStatementReturns
+[0;32m[ RUN ] [mExpectNonfatalFailureTest.FailsWhenStatementThrows
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenStatementThrows
+[0;32m[----------] [m8 tests from ExpectFatalFailureTest
+[0;32m[ RUN ] [mExpectFatalFailureTest.CanReferenceGlobalVariables
+[0;32m[ OK ] [mExpectFatalFailureTest.CanReferenceGlobalVariables
+[0;32m[ RUN ] [mExpectFatalFailureTest.CanReferenceLocalStaticVariables
+[0;32m[ OK ] [mExpectFatalFailureTest.CanReferenceLocalStaticVariables
+[0;32m[ RUN ] [mExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure
+[0;32m[ OK ] [mExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure
+[0;32m[ RUN ] [mExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+[0;32m[ RUN ] [mExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 2 failures
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+[0;32m[ RUN ] [mExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+[0;32m[ RUN ] [mExpectFatalFailureTest.FailsWhenStatementReturns
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenStatementReturns
+[0;32m[ RUN ] [mExpectFatalFailureTest.FailsWhenStatementThrows
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenStatementThrows
+[0;32m[----------] [m2 tests from TypedTest/0, where TypeParam = int
+[0;32m[ RUN ] [mTypedTest/0.Success
+[0;32m[ OK ] [mTypedTest/0.Success
+[0;32m[ RUN ] [mTypedTest/0.Failure
+gtest_output_test_.cc:#: Failure
+Value of: TypeParam()
+ Actual: 0
+Expected: 1
+Expected failure
+[0;31m[ FAILED ] [mTypedTest/0.Failure, where TypeParam = int
+[0;32m[----------] [m2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char
+[0;32m[ RUN ] [mUnsigned/TypedTestP/0.Success
+[0;32m[ OK ] [mUnsigned/TypedTestP/0.Success
+[0;32m[ RUN ] [mUnsigned/TypedTestP/0.Failure
+gtest_output_test_.cc:#: Failure
+Value of: TypeParam()
+ Actual: '\0'
+Expected: 1U
+Which is: 1
+Expected failure
+[0;31m[ FAILED ] [mUnsigned/TypedTestP/0.Failure, where TypeParam = unsigned char
+[0;32m[----------] [m2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int
+[0;32m[ RUN ] [mUnsigned/TypedTestP/1.Success
+[0;32m[ OK ] [mUnsigned/TypedTestP/1.Success
+[0;32m[ RUN ] [mUnsigned/TypedTestP/1.Failure
+gtest_output_test_.cc:#: Failure
+Value of: TypeParam()
+ Actual: 0
+Expected: 1U
+Which is: 1
+Expected failure
+[0;31m[ FAILED ] [mUnsigned/TypedTestP/1.Failure, where TypeParam = unsigned int
+[0;32m[----------] [m4 tests from ExpectFailureTest
+[0;32m[ RUN ] [mExpectFailureTest.ExpectFatalFailure
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure containing "Some other fatal failure expected."
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectFatalFailure
+[0;32m[ RUN ] [mExpectFailureTest.ExpectNonFatalFailure
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure containing "Some other non-fatal failure."
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailure
+[0;32m[ RUN ] [mExpectFailureTest.ExpectFatalFailureOnAllThreads
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure containing "Some other fatal failure expected."
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectFatalFailureOnAllThreads
+[0;32m[ RUN ] [mExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure containing "Some other non-fatal failure."
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[0;32m[----------] [m2 tests from ExpectFailureWithThreadsTest
+[0;32m[ RUN ] [mExpectFailureWithThreadsTest.ExpectFatalFailure
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected fatal failure.
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectFatalFailure
+[0;32m[ RUN ] [mExpectFailureWithThreadsTest.ExpectNonFatalFailure
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected non-fatal failure.
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectNonFatalFailure
+[0;32m[----------] [m1 test from ScopedFakeTestPartResultReporterTest
+[0;32m[ RUN ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected fatal failure.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected non-fatal failure.
+[0;31m[ FAILED ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+[0;32m[----------] [m1 test from PrintingFailingParams/FailingParamTest
+[0;32m[ RUN ] [mPrintingFailingParams/FailingParamTest.Fails/0
+gtest_output_test_.cc:#: Failure
+Value of: GetParam()
+ Actual: 2
+Expected: 1
+[0;31m[ FAILED ] [mPrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
+[0;32m[----------] [mGlobal test environment tear-down
+BarEnvironment::TearDown() called.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected non-fatal failure.
+FooEnvironment::TearDown() called.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected fatal failure.
+[0;32m[==========] [m63 tests from 28 test cases ran.
+[0;32m[ PASSED ] [m21 tests.
+[0;31m[ FAILED ] [m42 tests, listed below:
+[0;31m[ FAILED ] [mNonfatalFailureTest.EscapesStringOperands
+[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInSubroutine
+[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInNestedSubroutine
+[0;31m[ FAILED ] [mFatalFailureTest.NonfatalFailureInSubroutine
+[0;31m[ FAILED ] [mLoggingTest.InterleavingLoggingAndAssertions
+[0;31m[ FAILED ] [mSCOPED_TRACETest.ObeysScopes
+[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksInLoop
+[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksInSubroutine
+[0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeNested
+[0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeRepeated
+[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksConcurrently
+[0;31m[ FAILED ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor
+[0;31m[ FAILED ] [mFatalFailureInFixtureConstructorTest.FailureInConstructor
+[0;31m[ FAILED ] [mNonFatalFailureInSetUpTest.FailureInSetUp
+[0;31m[ FAILED ] [mFatalFailureInSetUpTest.FailureInSetUp
+[0;31m[ FAILED ] [mAddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber
+[0;31m[ FAILED ] [mMixedUpTestCaseTest.ThisShouldFail
+[0;31m[ FAILED ] [mMixedUpTestCaseTest.ThisShouldFailToo
+[0;31m[ FAILED ] [mMixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[0;31m[ FAILED ] [mTEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+[0;31m[ FAILED ] [mTEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenStatementReturns
+[0;31m[ FAILED ] [mExpectNonfatalFailureTest.FailsWhenStatementThrows
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenStatementReturns
+[0;31m[ FAILED ] [mExpectFatalFailureTest.FailsWhenStatementThrows
+[0;31m[ FAILED ] [mTypedTest/0.Failure, where TypeParam = int
+[0;31m[ FAILED ] [mUnsigned/TypedTestP/0.Failure, where TypeParam = unsigned char
+[0;31m[ FAILED ] [mUnsigned/TypedTestP/1.Failure, where TypeParam = unsigned int
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectFatalFailure
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailure
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectFatalFailureOnAllThreads
+[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectFatalFailure
+[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectNonFatalFailure
+[0;31m[ FAILED ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+[0;31m[ FAILED ] [mPrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
+
+42 FAILED TESTS
+[0;33m YOU HAVE 1 DISABLED TEST
+
+[mNote: Google Test filter = FatalFailureTest.*:LoggingTest.*
+[==========] Running 4 tests from 2 test cases.
+[----------] Global test environment set-up.
+[----------] 3 tests from FatalFailureTest
+[ RUN ] FatalFailureTest.FatalFailureInSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms)
+[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms)
+[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine
+(expecting a failure on false)
+gtest_output_test_.cc:#: Failure
+Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms)
+[----------] 3 tests from FatalFailureTest (? ms total)
+
+[----------] 1 test from LoggingTest
+[ RUN ] LoggingTest.InterleavingLoggingAndAssertions
+(expecting 2 failures on (3) >= (a[i]))
+i == 0
+i == 1
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 9
+i == 2
+i == 3
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 6
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms)
+[----------] 1 test from LoggingTest (? ms total)
+
+[----------] Global test environment tear-down
+[==========] 4 tests from 2 test cases ran. (? ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 4 tests, listed below:
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+
+ 4 FAILED TESTS
+Note: Google Test filter = *DISABLED_*
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from DisabledTestsWarningTest
+[ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning
+[ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran.
+[ PASSED ] 1 test.
+Note: Google Test filter = PassingTest.*
+Note: This is test shard 2 of 2.
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from PassingTest
+[ RUN ] PassingTest.PassingTest2
+[ OK ] PassingTest.PassingTest2
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran.
+[ PASSED ] 1 test.
diff --git a/external/gtest-1.6.0/test/gtest_pred_impl_unittest.cc b/external/gtest-1.6.0/test/gtest_pred_impl_unittest.cc
new file mode 100644
index 0000000..e07fe5f
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_pred_impl_unittest.cc
@@ -0,0 +1,2613 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+
+// Regression test for gtest_pred_impl.h
+//
+// This file is generated by a script and quite long. If you intend to
+// learn how Google Test works by reading its unit tests, read
+// gtest_unittest.cc instead.
+//
+// This is intended as a regression test for the Google Test predicate
+// assertions. We compile it as part of the gtest_unittest target
+// only to keep the implementation tidy and compact, as it is quite
+// involved to set up the stage for testing Google Test using Google
+// Test itself.
+//
+// Currently, gtest_unittest takes ~11 seconds to run in the testing
+// daemon. In the future, if it grows too large and needs much more
+// time to finish, we should consider separating this file into a
+// stand-alone regression test.
+
+#include <iostream>
+
+#include "gtest/gtest.h"
+#include "gtest/gtest-spi.h"
+
+// A user-defined data type.
+struct Bool {
+ explicit Bool(int val) : value(val != 0) {}
+
+ bool operator>(int n) const { return value > Bool(n).value; }
+
+ Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); }
+
+ bool operator==(const Bool& rhs) const { return value == rhs.value; }
+
+ bool value;
+};
+
+// Enables Bool to be used in assertions.
+std::ostream& operator<<(std::ostream& os, const Bool& x)
+{
+ return os << (x.value ? "true" : "false");
+}
+
+// Sample functions/functors for testing unary predicate assertions.
+
+// A unary predicate function.
+template <typename T1>
+bool PredFunction1(T1 v1)
+{
+ return v1 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction1Int(int v1)
+{
+ return v1 > 0;
+}
+bool PredFunction1Bool(Bool v1)
+{
+ return v1 > 0;
+}
+
+// A unary predicate functor.
+struct PredFunctor1 {
+ template <typename T1>
+ bool operator()(const T1& v1) {
+ return v1 > 0;
+ }
+};
+
+// A unary predicate-formatter function.
+template <typename T1>
+testing::AssertionResult PredFormatFunction1(const char* e1,
+ const T1& v1)
+{
+ if (PredFunction1(v1))
+ return testing::AssertionSuccess();
+
+ return testing::AssertionFailure()
+ << e1
+ << " is expected to be positive, but evaluates to "
+ << v1 << ".";
+}
+
+// A unary predicate-formatter functor.
+struct PredFormatFunctor1 {
+ template <typename T1>
+ testing::AssertionResult operator()(const char* e1,
+ const T1& v1) const {
+ return PredFormatFunction1(e1, v1);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT1.
+
+class Predicate1Test : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+};
+
+bool Predicate1Test::expected_to_finish_;
+bool Predicate1Test::finished_;
+int Predicate1Test::n1_;
+
+typedef Predicate1Test EXPECT_PRED_FORMAT1Test;
+typedef Predicate1Test ASSERT_PRED_FORMAT1Test;
+typedef Predicate1Test EXPECT_PRED1Test;
+typedef Predicate1Test ASSERT_PRED1Test;
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED1(PredFunction1Int,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED1(PredFunction1Bool,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED1(PredFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED1(PredFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunction1Int,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunction1Bool,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED1(PredFunction1Int,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED1(PredFunction1Bool,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED1(PredFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED1(PredFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunction1Int,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunction1Bool,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing binary predicate assertions.
+
+// A binary predicate function.
+template <typename T1, typename T2>
+bool PredFunction2(T1 v1, T2 v2)
+{
+ return v1 + v2 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction2Int(int v1, int v2)
+{
+ return v1 + v2 > 0;
+}
+bool PredFunction2Bool(Bool v1, Bool v2)
+{
+ return v1 + v2 > 0;
+}
+
+// A binary predicate functor.
+struct PredFunctor2 {
+ template <typename T1, typename T2>
+ bool operator()(const T1& v1,
+ const T2& v2) {
+ return v1 + v2 > 0;
+ }
+};
+
+// A binary predicate-formatter function.
+template <typename T1, typename T2>
+testing::AssertionResult PredFormatFunction2(const char* e1,
+ const char* e2,
+ const T1& v1,
+ const T2& v2)
+{
+ if (PredFunction2(v1, v2))
+ return testing::AssertionSuccess();
+
+ return testing::AssertionFailure()
+ << e1 << " + " << e2
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 << ".";
+}
+
+// A binary predicate-formatter functor.
+struct PredFormatFunctor2 {
+ template <typename T1, typename T2>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const T1& v1,
+ const T2& v2) const {
+ return PredFormatFunction2(e1, e2, v1, v2);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT2.
+
+class Predicate2Test : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+};
+
+bool Predicate2Test::expected_to_finish_;
+bool Predicate2Test::finished_;
+int Predicate2Test::n1_;
+int Predicate2Test::n2_;
+
+typedef Predicate2Test EXPECT_PRED_FORMAT2Test;
+typedef Predicate2Test ASSERT_PRED_FORMAT2Test;
+typedef Predicate2Test EXPECT_PRED2Test;
+typedef Predicate2Test ASSERT_PRED2Test;
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED2(PredFunction2Int,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED2(PredFunction2Bool,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED2(PredFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED2(PredFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunction2Int,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunction2Bool,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED2(PredFunction2Int,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED2(PredFunction2Bool,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED2(PredFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED2(PredFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunction2Int,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunction2Bool,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing ternary predicate assertions.
+
+// A ternary predicate function.
+template <typename T1, typename T2, typename T3>
+bool PredFunction3(T1 v1, T2 v2, T3 v3)
+{
+ return v1 + v2 + v3 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction3Int(int v1, int v2, int v3)
+{
+ return v1 + v2 + v3 > 0;
+}
+bool PredFunction3Bool(Bool v1, Bool v2, Bool v3)
+{
+ return v1 + v2 + v3 > 0;
+}
+
+// A ternary predicate functor.
+struct PredFunctor3 {
+ template <typename T1, typename T2, typename T3>
+ bool operator()(const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ return v1 + v2 + v3 > 0;
+ }
+};
+
+// A ternary predicate-formatter function.
+template <typename T1, typename T2, typename T3>
+testing::AssertionResult PredFormatFunction3(const char* e1,
+ const char* e2,
+ const char* e3,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3)
+{
+ if (PredFunction3(v1, v2, v3))
+ return testing::AssertionSuccess();
+
+ return testing::AssertionFailure()
+ << e1 << " + " << e2 << " + " << e3
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 + v3 << ".";
+}
+
+// A ternary predicate-formatter functor.
+struct PredFormatFunctor3 {
+ template <typename T1, typename T2, typename T3>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const char* e3,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) const {
+ return PredFormatFunction3(e1, e2, e3, v1, v2, v3);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT3.
+
+class Predicate3Test : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = n3_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+ EXPECT_EQ(1, n3_) <<
+ "The predicate assertion didn't evaluate argument 4 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+ static int n3_;
+};
+
+bool Predicate3Test::expected_to_finish_;
+bool Predicate3Test::finished_;
+int Predicate3Test::n1_;
+int Predicate3Test::n2_;
+int Predicate3Test::n3_;
+
+typedef Predicate3Test EXPECT_PRED_FORMAT3Test;
+typedef Predicate3Test ASSERT_PRED_FORMAT3Test;
+typedef Predicate3Test EXPECT_PRED3Test;
+typedef Predicate3Test ASSERT_PRED3Test;
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED3(PredFunction3Int,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED3(PredFunction3Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED3(PredFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED3(PredFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunction3Int,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunction3Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED3(PredFunction3Int,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED3(PredFunction3Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED3(PredFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED3(PredFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunction3Int,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunction3Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing 4-ary predicate assertions.
+
+// A 4-ary predicate function.
+template <typename T1, typename T2, typename T3, typename T4>
+bool PredFunction4(T1 v1, T2 v2, T3 v3, T4 v4)
+{
+ return v1 + v2 + v3 + v4 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction4Int(int v1, int v2, int v3, int v4)
+{
+ return v1 + v2 + v3 + v4 > 0;
+}
+bool PredFunction4Bool(Bool v1, Bool v2, Bool v3, Bool v4)
+{
+ return v1 + v2 + v3 + v4 > 0;
+}
+
+// A 4-ary predicate functor.
+struct PredFunctor4 {
+ template <typename T1, typename T2, typename T3, typename T4>
+ bool operator()(const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ return v1 + v2 + v3 + v4 > 0;
+ }
+};
+
+// A 4-ary predicate-formatter function.
+template <typename T1, typename T2, typename T3, typename T4>
+testing::AssertionResult PredFormatFunction4(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4)
+{
+ if (PredFunction4(v1, v2, v3, v4))
+ return testing::AssertionSuccess();
+
+ return testing::AssertionFailure()
+ << e1 << " + " << e2 << " + " << e3 << " + " << e4
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 + v3 + v4 << ".";
+}
+
+// A 4-ary predicate-formatter functor.
+struct PredFormatFunctor4 {
+ template <typename T1, typename T2, typename T3, typename T4>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) const {
+ return PredFormatFunction4(e1, e2, e3, e4, v1, v2, v3, v4);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT4.
+
+class Predicate4Test : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = n3_ = n4_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+ EXPECT_EQ(1, n3_) <<
+ "The predicate assertion didn't evaluate argument 4 "
+ "exactly once.";
+ EXPECT_EQ(1, n4_) <<
+ "The predicate assertion didn't evaluate argument 5 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+ static int n3_;
+ static int n4_;
+};
+
+bool Predicate4Test::expected_to_finish_;
+bool Predicate4Test::finished_;
+int Predicate4Test::n1_;
+int Predicate4Test::n2_;
+int Predicate4Test::n3_;
+int Predicate4Test::n4_;
+
+typedef Predicate4Test EXPECT_PRED_FORMAT4Test;
+typedef Predicate4Test ASSERT_PRED_FORMAT4Test;
+typedef Predicate4Test EXPECT_PRED4Test;
+typedef Predicate4Test ASSERT_PRED4Test;
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED4(PredFunction4Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED4(PredFunction4Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED4(PredFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED4(PredFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunction4Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunction4Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED4(PredFunction4Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED4(PredFunction4Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED4(PredFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED4(PredFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunction4Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunction4Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing 5-ary predicate assertions.
+
+// A 5-ary predicate function.
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+bool PredFunction5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5)
+{
+ return v1 + v2 + v3 + v4 + v5 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction5Int(int v1, int v2, int v3, int v4, int v5)
+{
+ return v1 + v2 + v3 + v4 + v5 > 0;
+}
+bool PredFunction5Bool(Bool v1, Bool v2, Bool v3, Bool v4, Bool v5)
+{
+ return v1 + v2 + v3 + v4 + v5 > 0;
+}
+
+// A 5-ary predicate functor.
+struct PredFunctor5 {
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ bool operator()(const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ return v1 + v2 + v3 + v4 + v5 > 0;
+ }
+};
+
+// A 5-ary predicate-formatter function.
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+testing::AssertionResult PredFormatFunction5(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5)
+{
+ if (PredFunction5(v1, v2, v3, v4, v5))
+ return testing::AssertionSuccess();
+
+ return testing::AssertionFailure()
+ << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 + v3 + v4 + v5 << ".";
+}
+
+// A 5-ary predicate-formatter functor.
+struct PredFormatFunctor5 {
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) const {
+ return PredFormatFunction5(e1, e2, e3, e4, e5, v1, v2, v3, v4, v5);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT5.
+
+class Predicate5Test : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = n3_ = n4_ = n5_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+ EXPECT_EQ(1, n3_) <<
+ "The predicate assertion didn't evaluate argument 4 "
+ "exactly once.";
+ EXPECT_EQ(1, n4_) <<
+ "The predicate assertion didn't evaluate argument 5 "
+ "exactly once.";
+ EXPECT_EQ(1, n5_) <<
+ "The predicate assertion didn't evaluate argument 6 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+ static int n3_;
+ static int n4_;
+ static int n5_;
+};
+
+bool Predicate5Test::expected_to_finish_;
+bool Predicate5Test::finished_;
+int Predicate5Test::n1_;
+int Predicate5Test::n2_;
+int Predicate5Test::n3_;
+int Predicate5Test::n4_;
+int Predicate5Test::n5_;
+
+typedef Predicate5Test EXPECT_PRED_FORMAT5Test;
+typedef Predicate5Test ASSERT_PRED_FORMAT5Test;
+typedef Predicate5Test EXPECT_PRED5Test;
+typedef Predicate5Test ASSERT_PRED5Test;
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED5(PredFunction5Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED5(PredFunction5Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED5(PredFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED5(PredFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunction5Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunction5Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED5(PredFunction5Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED5(PredFunction5Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED5(PredFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED5(PredFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunction5Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunction5Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess)
+{
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess)
+{
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeFailure)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess)
+{
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess)
+{
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeFailure)
+{
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
diff --git a/external/gtest-1.6.0/test/gtest_prod_test.cc b/external/gtest-1.6.0/test/gtest_prod_test.cc
new file mode 100644
index 0000000..c3de881
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_prod_test.cc
@@ -0,0 +1,59 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Unit test for include/gtest/gtest_prod.h.
+
+#include "gtest/gtest.h"
+#include "test/production.h"
+
+// Tests that private members can be accessed from a TEST declared as
+// a friend of the class.
+TEST(PrivateCodeTest, CanAccessPrivateMembers)
+{
+ PrivateCode a;
+ EXPECT_EQ(0, a.x_);
+
+ a.set_x(1);
+ EXPECT_EQ(1, a.x_);
+}
+
+typedef testing::Test PrivateCodeFixtureTest;
+
+// Tests that private members can be accessed from a TEST_F declared
+// as a friend of the class.
+TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers)
+{
+ PrivateCode a;
+ EXPECT_EQ(0, a.x_);
+
+ a.set_x(2);
+ EXPECT_EQ(2, a.x_);
+}
diff --git a/external/gtest-1.6.0/test/gtest_repeat_test.cc b/external/gtest-1.6.0/test/gtest_repeat_test.cc
new file mode 100644
index 0000000..0e1de4f
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_repeat_test.cc
@@ -0,0 +1,268 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Tests the --gtest_repeat=number flag.
+
+#include <stdlib.h>
+#include <iostream>
+#include "gtest/gtest.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+
+GTEST_DECLARE_string_(death_test_style);
+GTEST_DECLARE_string_(filter);
+GTEST_DECLARE_int32_(repeat);
+
+} // namespace testing
+
+using testing::GTEST_FLAG(death_test_style);
+using testing::GTEST_FLAG(filter);
+using testing::GTEST_FLAG(repeat);
+
+namespace
+{
+
+// We need this when we are testing Google Test itself and therefore
+// cannot use Google Test assertions.
+#define GTEST_CHECK_INT_EQ_(expected, actual) \
+ do {\
+ const int expected_val = (expected);\
+ const int actual_val = (actual);\
+ if (::testing::internal::IsTrue(expected_val != actual_val)) {\
+ ::std::cout << "Value of: " #actual "\n"\
+ << " Actual: " << actual_val << "\n"\
+ << "Expected: " #expected "\n"\
+ << "Which is: " << expected_val << "\n";\
+ ::testing::internal::posix::Abort();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+
+// Used for verifying that global environment set-up and tear-down are
+// inside the gtest_repeat loop.
+
+int g_environment_set_up_count = 0;
+int g_environment_tear_down_count = 0;
+
+class MyEnvironment : public testing::Environment
+{
+ public:
+ MyEnvironment() {}
+ virtual void SetUp() { g_environment_set_up_count++; }
+ virtual void TearDown() { g_environment_tear_down_count++; }
+};
+
+// A test that should fail.
+
+int g_should_fail_count = 0;
+
+TEST(FooTest, ShouldFail)
+{
+ g_should_fail_count++;
+ EXPECT_EQ(0, 1) << "Expected failure.";
+}
+
+// A test that should pass.
+
+int g_should_pass_count = 0;
+
+TEST(FooTest, ShouldPass)
+{
+ g_should_pass_count++;
+}
+
+// A test that contains a thread-safe death test and a fast death
+// test. It should pass.
+
+int g_death_test_count = 0;
+
+TEST(BarDeathTest, ThreadSafeAndFast)
+{
+ g_death_test_count++;
+
+ GTEST_FLAG(death_test_style) = "threadsafe";
+ EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), "");
+
+ GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), "");
+}
+
+#if GTEST_HAS_PARAM_TEST
+int g_param_test_count = 0;
+
+const int kNumberOfParamTests = 10;
+
+class MyParamTest : public testing::TestWithParam<int> {};
+
+TEST_P(MyParamTest, ShouldPass)
+{
+ // TODO(vladl at google.com): Make parameter value checking robust
+ // WRT order of tests.
+ GTEST_CHECK_INT_EQ_(g_param_test_count % kNumberOfParamTests, GetParam());
+ g_param_test_count++;
+}
+INSTANTIATE_TEST_CASE_P(MyParamSequence,
+ MyParamTest,
+ testing::Range(0, kNumberOfParamTests));
+#endif // GTEST_HAS_PARAM_TEST
+
+// Resets the count for each test.
+void ResetCounts()
+{
+ g_environment_set_up_count = 0;
+ g_environment_tear_down_count = 0;
+ g_should_fail_count = 0;
+ g_should_pass_count = 0;
+ g_death_test_count = 0;
+#if GTEST_HAS_PARAM_TEST
+ g_param_test_count = 0;
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+// Checks that the count for each test is expected.
+void CheckCounts(int expected)
+{
+ GTEST_CHECK_INT_EQ_(expected, g_environment_set_up_count);
+ GTEST_CHECK_INT_EQ_(expected, g_environment_tear_down_count);
+ GTEST_CHECK_INT_EQ_(expected, g_should_fail_count);
+ GTEST_CHECK_INT_EQ_(expected, g_should_pass_count);
+ GTEST_CHECK_INT_EQ_(expected, g_death_test_count);
+#if GTEST_HAS_PARAM_TEST
+ GTEST_CHECK_INT_EQ_(expected * kNumberOfParamTests, g_param_test_count);
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+// Tests the behavior of Google Test when --gtest_repeat is not specified.
+void TestRepeatUnspecified()
+{
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS());
+ CheckCounts(1);
+}
+
+// Tests the behavior of Google Test when --gtest_repeat has the given value.
+void TestRepeat(int repeat)
+{
+ GTEST_FLAG(repeat) = repeat;
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(repeat > 0 ? 1 : 0, RUN_ALL_TESTS());
+ CheckCounts(repeat);
+}
+
+// Tests using --gtest_repeat when --gtest_filter specifies an empty
+// set of tests.
+void TestRepeatWithEmptyFilter(int repeat)
+{
+ GTEST_FLAG(repeat) = repeat;
+ GTEST_FLAG(filter) = "None";
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS());
+ CheckCounts(0);
+}
+
+// Tests using --gtest_repeat when --gtest_filter specifies a set of
+// successful tests.
+void TestRepeatWithFilterForSuccessfulTests(int repeat)
+{
+ GTEST_FLAG(repeat) = repeat;
+ GTEST_FLAG(filter) = "*-*ShouldFail";
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS());
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count);
+ GTEST_CHECK_INT_EQ_(0, g_should_fail_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_should_pass_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_death_test_count);
+#if GTEST_HAS_PARAM_TEST
+ GTEST_CHECK_INT_EQ_(repeat * kNumberOfParamTests, g_param_test_count);
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+// Tests using --gtest_repeat when --gtest_filter specifies a set of
+// failed tests.
+void TestRepeatWithFilterForFailedTests(int repeat)
+{
+ GTEST_FLAG(repeat) = repeat;
+ GTEST_FLAG(filter) = "*ShouldFail";
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS());
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_should_fail_count);
+ GTEST_CHECK_INT_EQ_(0, g_should_pass_count);
+ GTEST_CHECK_INT_EQ_(0, g_death_test_count);
+#if GTEST_HAS_PARAM_TEST
+ GTEST_CHECK_INT_EQ_(0, g_param_test_count);
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ testing::AddGlobalTestEnvironment(new MyEnvironment);
+
+ TestRepeatUnspecified();
+ TestRepeat(0);
+ TestRepeat(1);
+ TestRepeat(5);
+
+ TestRepeatWithEmptyFilter(2);
+ TestRepeatWithEmptyFilter(3);
+
+ TestRepeatWithFilterForSuccessfulTests(3);
+
+ TestRepeatWithFilterForFailedTests(4);
+
+ // It would be nice to verify that the tests indeed loop forever
+ // when GTEST_FLAG(repeat) is negative, but this test will be quite
+ // complicated to write. Since this flag is for interactive
+ // debugging only and doesn't affect the normal test result, such a
+ // test would be an overkill.
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/external/gtest-1.6.0/test/gtest_shuffle_test.py b/external/gtest-1.6.0/test/gtest_shuffle_test.py
new file mode 100755
index 0000000..30d0303
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_shuffle_test.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that test shuffling works."""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+# Command to run the gtest_shuffle_test_ program.
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_')
+
+# The environment variables for test sharding.
+TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
+SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
+
+TEST_FILTER = 'A*.A:A*.B:C*'
+
+ALL_TESTS = []
+ACTIVE_TESTS = []
+FILTERED_TESTS = []
+SHARDED_TESTS = []
+
+SHUFFLED_ALL_TESTS = []
+SHUFFLED_ACTIVE_TESTS = []
+SHUFFLED_FILTERED_TESTS = []
+SHUFFLED_SHARDED_TESTS = []
+
+
+def AlsoRunDisabledTestsFlag():
+ return '--gtest_also_run_disabled_tests'
+
+
+def FilterFlag(test_filter):
+ return '--gtest_filter=%s' % (test_filter,)
+
+
+def RepeatFlag(n):
+ return '--gtest_repeat=%s' % (n,)
+
+
+def ShuffleFlag():
+ return '--gtest_shuffle'
+
+
+def RandomSeedFlag(n):
+ return '--gtest_random_seed=%s' % (n,)
+
+
+def RunAndReturnOutput(extra_env, args):
+ """Runs the test program and returns its output."""
+
+ environ_copy = os.environ.copy()
+ environ_copy.update(extra_env)
+
+ return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output
+
+
+def GetTestsForAllIterations(extra_env, args):
+ """Runs the test program and returns a list of test lists.
+
+ Args:
+ extra_env: a map from environment variables to their values
+ args: command line flags to pass to gtest_shuffle_test_
+
+ Returns:
+ A list where the i-th element is the list of tests run in the i-th
+ test iteration.
+ """
+
+ test_iterations = []
+ for line in RunAndReturnOutput(extra_env, args).split('\n'):
+ if line.startswith('----'):
+ tests = []
+ test_iterations.append(tests)
+ elif line.strip():
+ tests.append(line.strip()) # 'TestCaseName.TestName'
+
+ return test_iterations
+
+
+def GetTestCases(tests):
+ """Returns a list of test cases in the given full test names.
+
+ Args:
+ tests: a list of full test names
+
+ Returns:
+ A list of test cases from 'tests', in their original order.
+ Consecutive duplicates are removed.
+ """
+
+ test_cases = []
+ for test in tests:
+ test_case = test.split('.')[0]
+ if not test_case in test_cases:
+ test_cases.append(test_case)
+
+ return test_cases
+
+
+def CalculateTestLists():
+ """Calculates the list of tests run under different flags."""
+
+ if not ALL_TESTS:
+ ALL_TESTS.extend(
+ GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0])
+
+ if not ACTIVE_TESTS:
+ ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0])
+
+ if not FILTERED_TESTS:
+ FILTERED_TESTS.extend(
+ GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0])
+
+ if not SHARDED_TESTS:
+ SHARDED_TESTS.extend(
+ GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '1'},
+ [])[0])
+
+ if not SHUFFLED_ALL_TESTS:
+ SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations(
+ {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0])
+
+ if not SHUFFLED_ACTIVE_TESTS:
+ SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1)])[0])
+
+ if not SHUFFLED_FILTERED_TESTS:
+ SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0])
+
+ if not SHUFFLED_SHARDED_TESTS:
+ SHUFFLED_SHARDED_TESTS.extend(
+ GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '1'},
+ [ShuffleFlag(), RandomSeedFlag(1)])[0])
+
+
+class GTestShuffleUnitTest(gtest_test_utils.TestCase):
+ """Tests test shuffling."""
+
+ def setUp(self):
+ CalculateTestLists()
+
+ def testShufflePreservesNumberOfTests(self):
+ self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS))
+ self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS))
+ self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS))
+ self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS))
+
+ def testShuffleChangesTestOrder(self):
+ self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS)
+ self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS)
+ self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS,
+ SHUFFLED_FILTERED_TESTS)
+ self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS,
+ SHUFFLED_SHARDED_TESTS)
+
+ def testShuffleChangesTestCaseOrder(self):
+ self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS),
+ GetTestCases(SHUFFLED_ALL_TESTS))
+ self.assert_(
+ GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS),
+ GetTestCases(SHUFFLED_ACTIVE_TESTS))
+ self.assert_(
+ GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS),
+ GetTestCases(SHUFFLED_FILTERED_TESTS))
+ self.assert_(
+ GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS),
+ GetTestCases(SHUFFLED_SHARDED_TESTS))
+
+ def testShuffleDoesNotRepeatTest(self):
+ for test in SHUFFLED_ALL_TESTS:
+ self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test),
+ '%s appears more than once' % (test,))
+ for test in SHUFFLED_ACTIVE_TESTS:
+ self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test),
+ '%s appears more than once' % (test,))
+ for test in SHUFFLED_FILTERED_TESTS:
+ self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test),
+ '%s appears more than once' % (test,))
+ for test in SHUFFLED_SHARDED_TESTS:
+ self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test),
+ '%s appears more than once' % (test,))
+
+ def testShuffleDoesNotCreateNewTest(self):
+ for test in SHUFFLED_ALL_TESTS:
+ self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,))
+ for test in SHUFFLED_ACTIVE_TESTS:
+ self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,))
+ for test in SHUFFLED_FILTERED_TESTS:
+ self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,))
+ for test in SHUFFLED_SHARDED_TESTS:
+ self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,))
+
+ def testShuffleIncludesAllTests(self):
+ for test in ALL_TESTS:
+ self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,))
+ for test in ACTIVE_TESTS:
+ self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,))
+ for test in FILTERED_TESTS:
+ self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,))
+ for test in SHARDED_TESTS:
+ self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,))
+
+ def testShuffleLeavesDeathTestsAtFront(self):
+ non_death_test_found = False
+ for test in SHUFFLED_ACTIVE_TESTS:
+ if 'DeathTest.' in test:
+ self.assert_(not non_death_test_found,
+ '%s appears after a non-death test' % (test,))
+ else:
+ non_death_test_found = True
+
+ def _VerifyTestCasesDoNotInterleave(self, tests):
+ test_cases = []
+ for test in tests:
+ [test_case, _] = test.split('.')
+ if test_cases and test_cases[-1] != test_case:
+ test_cases.append(test_case)
+ self.assertEqual(1, test_cases.count(test_case),
+ 'Test case %s is not grouped together in %s' %
+ (test_case, tests))
+
+ def testShuffleDoesNotInterleaveTestCases(self):
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS)
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS)
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS)
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS)
+
+ def testShuffleRestoresOrderAfterEachIteration(self):
+ # Get the test lists in all 3 iterations, using random seed 1, 2,
+ # and 3 respectively. Google Test picks a different seed in each
+ # iteration, and this test depends on the current implementation
+ # picking successive numbers. This dependency is not ideal, but
+ # makes the test much easier to write.
+ [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
+ GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
+
+ # Make sure running the tests with random seed 1 gets the same
+ # order as in iteration 1 above.
+ [tests_with_seed1] = GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1)])
+ self.assertEqual(tests_in_iteration1, tests_with_seed1)
+
+ # Make sure running the tests with random seed 2 gets the same
+ # order as in iteration 2 above. Success means that Google Test
+ # correctly restores the test order before re-shuffling at the
+ # beginning of iteration 2.
+ [tests_with_seed2] = GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(2)])
+ self.assertEqual(tests_in_iteration2, tests_with_seed2)
+
+ # Make sure running the tests with random seed 3 gets the same
+ # order as in iteration 3 above. Success means that Google Test
+ # correctly restores the test order before re-shuffling at the
+ # beginning of iteration 3.
+ [tests_with_seed3] = GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(3)])
+ self.assertEqual(tests_in_iteration3, tests_with_seed3)
+
+ def testShuffleGeneratesNewOrderInEachIteration(self):
+ [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
+ GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
+
+ self.assert_(tests_in_iteration1 != tests_in_iteration2,
+ tests_in_iteration1)
+ self.assert_(tests_in_iteration1 != tests_in_iteration3,
+ tests_in_iteration1)
+ self.assert_(tests_in_iteration2 != tests_in_iteration3,
+ tests_in_iteration2)
+
+ def testShuffleShardedTestsPreservesPartition(self):
+ # If we run M tests on N shards, the same M tests should be run in
+ # total, regardless of the random seeds used by the shards.
+ [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '0'},
+ [ShuffleFlag(), RandomSeedFlag(1)])
+ [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '1'},
+ [ShuffleFlag(), RandomSeedFlag(20)])
+ [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '2'},
+ [ShuffleFlag(), RandomSeedFlag(25)])
+ sorted_sharded_tests = tests1 + tests2 + tests3
+ sorted_sharded_tests.sort()
+ sorted_active_tests = []
+ sorted_active_tests.extend(ACTIVE_TESTS)
+ sorted_active_tests.sort()
+ self.assertEqual(sorted_active_tests, sorted_sharded_tests)
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_shuffle_test_.cc b/external/gtest-1.6.0/test/gtest_shuffle_test_.cc
new file mode 100644
index 0000000..e5d81ed
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_shuffle_test_.cc
@@ -0,0 +1,106 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Verifies that test shuffling works.
+
+#include "gtest/gtest.h"
+
+namespace
+{
+
+using ::testing::EmptyTestEventListener;
+using ::testing::InitGoogleTest;
+using ::testing::Message;
+using ::testing::Test;
+using ::testing::TestEventListeners;
+using ::testing::TestInfo;
+using ::testing::UnitTest;
+using ::testing::internal::scoped_ptr;
+
+// The test methods are empty, as the sole purpose of this program is
+// to print the test names before/after shuffling.
+
+class A : public Test {};
+TEST_F(A, A) {}
+TEST_F(A, B) {}
+
+TEST(ADeathTest, A) {}
+TEST(ADeathTest, B) {}
+TEST(ADeathTest, C) {}
+
+TEST(B, A) {}
+TEST(B, B) {}
+TEST(B, C) {}
+TEST(B, DISABLED_D) {}
+TEST(B, DISABLED_E) {}
+
+TEST(BDeathTest, A) {}
+TEST(BDeathTest, B) {}
+
+TEST(C, A) {}
+TEST(C, B) {}
+TEST(C, C) {}
+TEST(C, DISABLED_D) {}
+
+TEST(CDeathTest, A) {}
+
+TEST(DISABLED_D, A) {}
+TEST(DISABLED_D, DISABLED_B) {}
+
+// This printer prints the full test names only, starting each test
+// iteration with a "----" marker.
+class TestNamePrinter : public EmptyTestEventListener
+{
+ public:
+ virtual void OnTestIterationStart(const UnitTest& /* unit_test */,
+ int /* iteration */) {
+ printf("----\n");
+ }
+
+ virtual void OnTestStart(const TestInfo& test_info) {
+ printf("%s.%s\n", test_info.test_case_name(), test_info.name());
+ }
+};
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ InitGoogleTest(&argc, argv);
+
+ // Replaces the default printer with TestNamePrinter, which prints
+ // the test name only.
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+ listeners.Append(new TestNamePrinter);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_sole_header_test.cc b/external/gtest-1.6.0/test/gtest_sole_header_test.cc
new file mode 100644
index 0000000..799e571
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_sole_header_test.cc
@@ -0,0 +1,61 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule at google.com (Markus Heule)
+//
+// This test verifies that it's possible to use Google Test by including
+// the gtest.h header file alone.
+
+#include "gtest/gtest.h"
+
+namespace
+{
+
+void Subroutine()
+{
+ EXPECT_EQ(42, 42);
+}
+
+TEST(NoFatalFailureTest, ExpectNoFatalFailure)
+{
+ EXPECT_NO_FATAL_FAILURE(;);
+ EXPECT_NO_FATAL_FAILURE(SUCCEED());
+ EXPECT_NO_FATAL_FAILURE(Subroutine());
+ EXPECT_NO_FATAL_FAILURE({ SUCCEED(); });
+}
+
+TEST(NoFatalFailureTest, AssertNoFatalFailure)
+{
+ ASSERT_NO_FATAL_FAILURE(;);
+ ASSERT_NO_FATAL_FAILURE(SUCCEED());
+ ASSERT_NO_FATAL_FAILURE(Subroutine());
+ ASSERT_NO_FATAL_FAILURE({ SUCCEED(); });
+}
+
+} // namespace
diff --git a/external/gtest-1.6.0/test/gtest_stress_test.cc b/external/gtest-1.6.0/test/gtest_stress_test.cc
new file mode 100644
index 0000000..ac0f3c9
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_stress_test.cc
@@ -0,0 +1,276 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Tests that SCOPED_TRACE() and various Google Test assertions can be
+// used in a large number of threads concurrently.
+
+#include "gtest/gtest.h"
+
+#include <iostream>
+#include <vector>
+
+// We must define this macro in order to #include
+// gtest-internal-inl.h. This is how Google Test prevents a user from
+// accidentally depending on its internal implementation.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_IS_THREADSAFE
+
+namespace testing
+{
+namespace
+{
+
+using internal::Notification;
+using internal::TestPropertyKeyIs;
+using internal::ThreadWithParam;
+using internal::scoped_ptr;
+
+// In order to run tests in this file, for platforms where Google Test is
+// thread safe, implement ThreadWithParam. See the description of its API
+// in gtest-port.h, where it is defined for already supported platforms.
+
+// How many threads to create?
+const int kThreadCount = 50;
+
+std::string IdToKey(int id, const char* suffix)
+{
+ Message key;
+ key << "key_" << id << "_" << suffix;
+ return key.GetString();
+}
+
+std::string IdToString(int id)
+{
+ Message id_message;
+ id_message << id;
+ return id_message.GetString();
+}
+
+void ExpectKeyAndValueWereRecordedForId(
+ const std::vector<TestProperty>& properties,
+ int id, const char* suffix)
+{
+ TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str());
+ const std::vector<TestProperty>::const_iterator property =
+ std::find_if(properties.begin(), properties.end(), matches_key);
+ ASSERT_TRUE(property != properties.end())
+ << "expecting " << suffix << " value for id " << id;
+ EXPECT_STREQ(IdToString(id).c_str(), property->value());
+}
+
+// Calls a large number of Google Test assertions, where exactly one of them
+// will fail.
+void ManyAsserts(int id)
+{
+ GTEST_LOG_(INFO) << "Thread #" << id << " running...";
+
+ SCOPED_TRACE(Message() << "Thread #" << id);
+
+ for (int i = 0; i < kThreadCount; i++) {
+ SCOPED_TRACE(Message() << "Iteration #" << i);
+
+ // A bunch of assertions that should succeed.
+ EXPECT_TRUE(true);
+ ASSERT_FALSE(false) << "This shouldn't fail.";
+ EXPECT_STREQ("a", "a");
+ ASSERT_LE(5, 6);
+ EXPECT_EQ(i, i) << "This shouldn't fail.";
+
+ // RecordProperty() should interact safely with other threads as well.
+ // The shared_key forces property updates.
+ Test::RecordProperty(IdToKey(id, "string").c_str(), IdToString(id).c_str());
+ Test::RecordProperty(IdToKey(id, "int").c_str(), id);
+ Test::RecordProperty("shared_key", IdToString(id).c_str());
+
+ // This assertion should fail kThreadCount times per thread. It
+ // is for testing whether Google Test can handle failed assertions in a
+ // multi-threaded context.
+ EXPECT_LT(i, 0) << "This should always fail.";
+ }
+}
+
+void CheckTestFailureCount(int expected_failures)
+{
+ const TestInfo* const info = UnitTest::GetInstance()->current_test_info();
+ const TestResult* const result = info->result();
+ GTEST_CHECK_(expected_failures == result->total_part_count())
+ << "Logged " << result->total_part_count() << " failures "
+ << " vs. " << expected_failures << " expected";
+}
+
+// Tests using SCOPED_TRACE() and Google Test assertions in many threads
+// concurrently.
+TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads)
+{
+ {
+ scoped_ptr<ThreadWithParam<int> > threads[kThreadCount];
+ Notification threads_can_start;
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i].reset(new ThreadWithParam<int>(&ManyAsserts,
+ i,
+ &threads_can_start));
+
+ threads_can_start.Notify();
+
+ // Blocks until all the threads are done.
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i]->Join();
+ }
+
+ // Ensures that kThreadCount*kThreadCount failures have been reported.
+ const TestInfo* const info = UnitTest::GetInstance()->current_test_info();
+ const TestResult* const result = info->result();
+
+ std::vector<TestProperty> properties;
+ // We have no access to the TestResult's list of properties but we can
+ // copy them one by one.
+ for (int i = 0; i < result->test_property_count(); ++i)
+ properties.push_back(result->GetTestProperty(i));
+
+ EXPECT_EQ(kThreadCount * 2 + 1, result->test_property_count())
+ << "String and int values recorded on each thread, "
+ << "as well as one shared_key";
+ for (int i = 0; i < kThreadCount; ++i) {
+ ExpectKeyAndValueWereRecordedForId(properties, i, "string");
+ ExpectKeyAndValueWereRecordedForId(properties, i, "int");
+ }
+ CheckTestFailureCount(kThreadCount*kThreadCount);
+}
+
+void FailingThread(bool is_fatal)
+{
+ if (is_fatal)
+ FAIL() << "Fatal failure in some other thread. "
+ << "(This failure is expected.)";
+ else
+ ADD_FAILURE() << "Non-fatal failure in some other thread. "
+ << "(This failure is expected.)";
+}
+
+void GenerateFatalFailureInAnotherThread(bool is_fatal)
+{
+ ThreadWithParam<bool> thread(&FailingThread, is_fatal, NULL);
+ thread.Join();
+}
+
+TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads)
+{
+ EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true));
+ // We should only have one failure (the one from
+ // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
+ // should succeed.
+ CheckTestFailureCount(1);
+}
+
+void AssertNoFatalFailureIgnoresFailuresInOtherThreads()
+{
+ ASSERT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true));
+}
+TEST(NoFatalFailureTest, AssertNoFatalFailureIgnoresFailuresInOtherThreads)
+{
+ // Using a subroutine, to make sure, that the test continues.
+ AssertNoFatalFailureIgnoresFailuresInOtherThreads();
+ // We should only have one failure (the one from
+ // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
+ // should succeed.
+ CheckTestFailureCount(1);
+}
+
+TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads)
+{
+ // This statement should fail, since the current thread doesn't generate a
+ // fatal failure, only another one does.
+ EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected");
+ CheckTestFailureCount(2);
+}
+
+TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads)
+{
+ // This statement should succeed, because failures in all threads are
+ // considered.
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(
+ GenerateFatalFailureInAnotherThread(true), "expected");
+ CheckTestFailureCount(0);
+ // We need to add a failure, because main() checks that there are failures.
+ // But when only this test is run, we shouldn't have any failures.
+ ADD_FAILURE() << "This is an expected non-fatal failure.";
+}
+
+TEST(NonFatalFailureTest, ExpectNonFatalFailureIgnoresFailuresInOtherThreads)
+{
+ // This statement should fail, since the current thread doesn't generate a
+ // fatal failure, only another one does.
+ EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false),
+ "expected");
+ CheckTestFailureCount(2);
+}
+
+TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads)
+{
+ // This statement should succeed, because failures in all threads are
+ // considered.
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(
+ GenerateFatalFailureInAnotherThread(false), "expected");
+ CheckTestFailureCount(0);
+ // We need to add a failure, because main() checks that there are failures,
+ // But when only this test is run, we shouldn't have any failures.
+ ADD_FAILURE() << "This is an expected non-fatal failure.";
+}
+
+} // namespace
+} // namespace testing
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+
+ const int result = RUN_ALL_TESTS(); // Expected to fail.
+ GTEST_CHECK_(result == 1) << "RUN_ALL_TESTS() did not fail as expected";
+
+ printf("\nPASS\n");
+ return 0;
+}
+
+#else
+TEST(StressTest,
+ DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe)
+{
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif // GTEST_IS_THREADSAFE
diff --git a/external/gtest-1.6.0/test/gtest_test_utils.py b/external/gtest-1.6.0/test/gtest_test_utils.py
new file mode 100755
index 0000000..6dd8db4
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_test_utils.py
@@ -0,0 +1,305 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test utilities for Google C++ Testing Framework."""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import atexit
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+_test_module = unittest
+
+# Suppresses the 'Import not at the top of the file' lint complaint.
+# pylint: disable-msg=C6204
+try:
+ import subprocess
+ _SUBPROCESS_MODULE_AVAILABLE = True
+except:
+ import popen2
+ _SUBPROCESS_MODULE_AVAILABLE = False
+# pylint: enable-msg=C6204
+
+GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
+
+IS_WINDOWS = os.name == 'nt'
+IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
+
+# Here we expose a class from a particular module, depending on the
+# environment. The comment suppresses the 'Invalid variable name' lint
+# complaint.
+TestCase = _test_module.TestCase # pylint: disable-msg=C6409
+
+# Initially maps a flag to its default value. After
+# _ParseAndStripGTestFlags() is called, maps a flag to its actual value.
+_flag_map = {'source_dir': os.path.dirname(sys.argv[0]),
+ 'build_dir': os.path.dirname(sys.argv[0])}
+_gtest_flags_are_parsed = False
+
+
+def _ParseAndStripGTestFlags(argv):
+ """Parses and strips Google Test flags from argv. This is idempotent."""
+
+ # Suppresses the lint complaint about a global variable since we need it
+ # here to maintain module-wide state.
+ global _gtest_flags_are_parsed # pylint: disable-msg=W0603
+ if _gtest_flags_are_parsed:
+ return
+
+ _gtest_flags_are_parsed = True
+ for flag in _flag_map:
+ # The environment variable overrides the default value.
+ if flag.upper() in os.environ:
+ _flag_map[flag] = os.environ[flag.upper()]
+
+ # The command line flag overrides the environment variable.
+ i = 1 # Skips the program name.
+ while i < len(argv):
+ prefix = '--' + flag + '='
+ if argv[i].startswith(prefix):
+ _flag_map[flag] = argv[i][len(prefix):]
+ del argv[i]
+ break
+ else:
+ # We don't increment i in case we just found a --gtest_* flag
+ # and removed it from argv.
+ i += 1
+
+
+def GetFlag(flag):
+ """Returns the value of the given flag."""
+
+ # In case GetFlag() is called before Main(), we always call
+ # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags
+ # are parsed.
+ _ParseAndStripGTestFlags(sys.argv)
+
+ return _flag_map[flag]
+
+
+def GetSourceDir():
+ """Returns the absolute path of the directory where the .py files are."""
+
+ return os.path.abspath(GetFlag('source_dir'))
+
+
+def GetBuildDir():
+ """Returns the absolute path of the directory where the test binaries are."""
+
+ return os.path.abspath(GetFlag('build_dir'))
+
+
+_temp_dir = None
+
+def _RemoveTempDir():
+ if _temp_dir:
+ shutil.rmtree(_temp_dir, ignore_errors=True)
+
+atexit.register(_RemoveTempDir)
+
+
+def GetTempDir():
+ """Returns a directory for temporary files."""
+
+ global _temp_dir
+ if not _temp_dir:
+ _temp_dir = tempfile.mkdtemp()
+ return _temp_dir
+
+
+def GetTestExecutablePath(executable_name, build_dir=None):
+ """Returns the absolute path of the test binary given its name.
+
+ The function will print a message and abort the program if the resulting file
+ doesn't exist.
+
+ Args:
+ executable_name: name of the test binary that the test script runs.
+ build_dir: directory where to look for executables, by default
+ the result of GetBuildDir().
+
+ Returns:
+ The absolute path of the test binary.
+ """
+
+ path = os.path.abspath(os.path.join(build_dir or GetBuildDir(),
+ executable_name))
+ if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'):
+ path += '.exe'
+
+ if not os.path.exists(path):
+ message = (
+ 'Unable to find the test binary. Please make sure to provide path\n'
+ 'to the binary via the --build_dir flag or the BUILD_DIR\n'
+ 'environment variable.')
+ print >> sys.stderr, message
+ sys.exit(1)
+
+ return path
+
+
+def GetExitStatus(exit_code):
+ """Returns the argument to exit(), or -1 if exit() wasn't called.
+
+ Args:
+ exit_code: the result value of os.system(command).
+ """
+
+ if os.name == 'nt':
+ # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns
+ # the argument to exit() directly.
+ return exit_code
+ else:
+ # On Unix, os.WEXITSTATUS() must be used to extract the exit status
+ # from the result of os.system().
+ if os.WIFEXITED(exit_code):
+ return os.WEXITSTATUS(exit_code)
+ else:
+ return -1
+
+
+class Subprocess:
+ def __init__(self, command, working_dir=None, capture_stderr=True, env=None):
+ """Changes into a specified directory, if provided, and executes a command.
+
+ Restores the old directory afterwards.
+
+ Args:
+ command: The command to run, in the form of sys.argv.
+ working_dir: The directory to change into.
+ capture_stderr: Determines whether to capture stderr in the output member
+ or to discard it.
+ env: Dictionary with environment to pass to the subprocess.
+
+ Returns:
+ An object that represents outcome of the executed process. It has the
+ following attributes:
+ terminated_by_signal True iff the child process has been terminated
+ by a signal.
+ signal Sygnal that terminated the child process.
+ exited True iff the child process exited normally.
+ exit_code The code with which the child process exited.
+ output Child process's stdout and stderr output
+ combined in a string.
+ """
+
+ # The subprocess module is the preferrable way of running programs
+ # since it is available and behaves consistently on all platforms,
+ # including Windows. But it is only available starting in python 2.4.
+ # In earlier python versions, we revert to the popen2 module, which is
+ # available in python 2.0 and later but doesn't provide required
+ # functionality (Popen4) under Windows. This allows us to support Mac
+ # OS X 10.4 Tiger, which has python 2.3 installed.
+ if _SUBPROCESS_MODULE_AVAILABLE:
+ if capture_stderr:
+ stderr = subprocess.STDOUT
+ else:
+ stderr = subprocess.PIPE
+
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=stderr,
+ cwd=working_dir, universal_newlines=True, env=env)
+ # communicate returns a tuple with the file obect for the child's
+ # output.
+ self.output = p.communicate()[0]
+ self._return_code = p.returncode
+ else:
+ old_dir = os.getcwd()
+
+ def _ReplaceEnvDict(dest, src):
+ # Changes made by os.environ.clear are not inheritable by child
+ # processes until Python 2.6. To produce inheritable changes we have
+ # to delete environment items with the del statement.
+ for key in dest.keys():
+ del dest[key]
+ dest.update(src)
+
+ # When 'env' is not None, backup the environment variables and replace
+ # them with the passed 'env'. When 'env' is None, we simply use the
+ # current 'os.environ' for compatibility with the subprocess.Popen
+ # semantics used above.
+ if env is not None:
+ old_environ = os.environ.copy()
+ _ReplaceEnvDict(os.environ, env)
+
+ try:
+ if working_dir is not None:
+ os.chdir(working_dir)
+ if capture_stderr:
+ p = popen2.Popen4(command)
+ else:
+ p = popen2.Popen3(command)
+ p.tochild.close()
+ self.output = p.fromchild.read()
+ ret_code = p.wait()
+ finally:
+ os.chdir(old_dir)
+
+ # Restore the old environment variables
+ # if they were replaced.
+ if env is not None:
+ _ReplaceEnvDict(os.environ, old_environ)
+
+ # Converts ret_code to match the semantics of
+ # subprocess.Popen.returncode.
+ if os.WIFSIGNALED(ret_code):
+ self._return_code = -os.WTERMSIG(ret_code)
+ else: # os.WIFEXITED(ret_code) should return True here.
+ self._return_code = os.WEXITSTATUS(ret_code)
+
+ if self._return_code < 0:
+ self.terminated_by_signal = True
+ self.exited = False
+ self.signal = -self._return_code
+ else:
+ self.terminated_by_signal = False
+ self.exited = True
+ self.exit_code = self._return_code
+
+
+def Main():
+ """Runs the unit test."""
+
+ # We must call _ParseAndStripGTestFlags() before calling
+ # unittest.main(). Otherwise the latter will be confused by the
+ # --gtest_* flags.
+ _ParseAndStripGTestFlags(sys.argv)
+ # The tested binaries should not be writing XML output files unless the
+ # script explicitly instructs them to.
+ # TODO(vladl at google.com): Move this into Subprocess when we implement
+ # passing environment into it as a parameter.
+ if GTEST_OUTPUT_VAR_NAME in os.environ:
+ del os.environ[GTEST_OUTPUT_VAR_NAME]
+
+ _test_module.main()
diff --git a/external/gtest-1.6.0/test/gtest_throw_on_failure_ex_test.cc b/external/gtest-1.6.0/test/gtest_throw_on_failure_ex_test.cc
new file mode 100644
index 0000000..c2e6288
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_throw_on_failure_ex_test.cc
@@ -0,0 +1,95 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Tests Google Test's throw-on-failure mode with exceptions enabled.
+
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdexcept>
+
+// Prints the given failure message and exits the program with
+// non-zero. We use this instead of a Google Test assertion to
+// indicate a failure, as the latter is been tested and cannot be
+// relied on.
+void Fail(const char* msg)
+{
+ printf("FAILURE: %s\n", msg);
+ fflush(stdout);
+ exit(1);
+}
+
+// Tests that an assertion failure throws a subclass of
+// std::runtime_error.
+void TestFailureThrowsRuntimeError()
+{
+ testing::GTEST_FLAG(throw_on_failure) = true;
+
+ // A successful assertion shouldn't throw.
+ try {
+ EXPECT_EQ(3, 3);
+ } catch (...) {
+ Fail("A successful assertion wrongfully threw.");
+ }
+
+ // A failed assertion should throw a subclass of std::runtime_error.
+ try {
+ EXPECT_EQ(2, 3) << "Expected failure";
+ } catch (const std::runtime_error& e) {
+ if (strstr(e.what(), "Expected failure") != NULL)
+ return;
+
+ printf("%s",
+ "A failed assertion did throw an exception of the right type, "
+ "but the message is incorrect. Instead of containing \"Expected "
+ "failure\", it is:\n");
+ Fail(e.what());
+ } catch (...) {
+ Fail("A failed assertion threw the wrong type of exception.");
+ }
+ Fail("A failed assertion should've thrown but didn't.");
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+
+ // We want to ensure that people can use Google Test assertions in
+ // other testing frameworks, as long as they initialize Google Test
+ // properly and set the thrown-on-failure mode. Therefore, we don't
+ // use Google Test's constructs for defining and running tests
+ // (e.g. TEST and RUN_ALL_TESTS) here.
+
+ TestFailureThrowsRuntimeError();
+ return 0;
+}
diff --git a/external/gtest-1.6.0/test/gtest_throw_on_failure_test.py b/external/gtest-1.6.0/test/gtest_throw_on_failure_test.py
new file mode 100755
index 0000000..5678ffe
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_throw_on_failure_test.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Google Test's throw-on-failure mode with exceptions disabled.
+
+This script invokes gtest_throw_on_failure_test_ (a program written with
+Google Test) with different environments and command line flags.
+"""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+
+# Constants.
+
+# The command line flag for enabling/disabling the throw-on-failure mode.
+THROW_ON_FAILURE = 'gtest_throw_on_failure'
+
+# Path to the gtest_throw_on_failure_test_ program, compiled with
+# exceptions disabled.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_throw_on_failure_test_')
+
+
+# Utilities.
+
+
+def SetEnvVar(env_var, value):
+ """Sets an environment variable to a given value; unsets it when the
+ given value is None.
+ """
+
+ env_var = env_var.upper()
+ if value is not None:
+ os.environ[env_var] = value
+ elif env_var in os.environ:
+ del os.environ[env_var]
+
+
+def Run(command):
+ """Runs a command; returns True/False if its exit code is/isn't 0."""
+
+ print 'Running "%s". . .' % ' '.join(command)
+ p = gtest_test_utils.Subprocess(command)
+ return p.exited and p.exit_code == 0
+
+
+# The tests. TODO(wan at google.com): refactor the class to share common
+# logic with code in gtest_break_on_failure_unittest.py.
+class ThrowOnFailureTest(gtest_test_utils.TestCase):
+ """Tests the throw-on-failure mode."""
+
+ def RunAndVerify(self, env_var_value, flag_value, should_fail):
+ """Runs gtest_throw_on_failure_test_ and verifies that it does
+ (or does not) exit with a non-zero code.
+
+ Args:
+ env_var_value: value of the GTEST_BREAK_ON_FAILURE environment
+ variable; None if the variable should be unset.
+ flag_value: value of the --gtest_break_on_failure flag;
+ None if the flag should not be present.
+ should_fail: True iff the program is expected to fail.
+ """
+
+ SetEnvVar(THROW_ON_FAILURE, env_var_value)
+
+ if env_var_value is None:
+ env_var_value_msg = ' is not set'
+ else:
+ env_var_value_msg = '=' + env_var_value
+
+ if flag_value is None:
+ flag = ''
+ elif flag_value == '0':
+ flag = '--%s=0' % THROW_ON_FAILURE
+ else:
+ flag = '--%s' % THROW_ON_FAILURE
+
+ command = [EXE_PATH]
+ if flag:
+ command.append(flag)
+
+ if should_fail:
+ should_or_not = 'should'
+ else:
+ should_or_not = 'should not'
+
+ failed = not Run(command)
+
+ SetEnvVar(THROW_ON_FAILURE, None)
+
+ msg = ('when %s%s, an assertion failure in "%s" %s cause a non-zero '
+ 'exit code.' %
+ (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command),
+ should_or_not))
+ self.assert_(failed == should_fail, msg)
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of the default mode."""
+
+ self.RunAndVerify(env_var_value=None, flag_value=None, should_fail=False)
+
+ def testThrowOnFailureEnvVar(self):
+ """Tests using the GTEST_THROW_ON_FAILURE environment variable."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value=None,
+ should_fail=False)
+ self.RunAndVerify(env_var_value='1',
+ flag_value=None,
+ should_fail=True)
+
+ def testThrowOnFailureFlag(self):
+ """Tests using the --gtest_throw_on_failure flag."""
+
+ self.RunAndVerify(env_var_value=None,
+ flag_value='0',
+ should_fail=False)
+ self.RunAndVerify(env_var_value=None,
+ flag_value='1',
+ should_fail=True)
+
+ def testThrowOnFailureFlagOverridesEnvVar(self):
+ """Tests that --gtest_throw_on_failure overrides GTEST_THROW_ON_FAILURE."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value='0',
+ should_fail=False)
+ self.RunAndVerify(env_var_value='0',
+ flag_value='1',
+ should_fail=True)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='0',
+ should_fail=False)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='1',
+ should_fail=True)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_throw_on_failure_test_.cc b/external/gtest-1.6.0/test/gtest_throw_on_failure_test_.cc
new file mode 100644
index 0000000..af4d1f9
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_throw_on_failure_test_.cc
@@ -0,0 +1,74 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+// Tests Google Test's throw-on-failure mode with exceptions disabled.
+//
+// This program must be compiled with exceptions disabled. It will be
+// invoked by gtest_throw_on_failure_test.py, and is expected to exit
+// with non-zero in the throw-on-failure mode or 0 otherwise.
+
+#include "gtest/gtest.h"
+
+#include <stdio.h> // for fflush, fprintf, NULL, etc.
+#include <stdlib.h> // for exit
+#include <exception> // for set_terminate
+
+// This terminate handler aborts the program using exit() rather than abort().
+// This avoids showing pop-ups on Windows systems and core dumps on Unix-like
+// ones.
+void TerminateHandler()
+{
+ fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program.");
+ fflush(NULL);
+ exit(1);
+}
+
+int main(int argc, char** argv)
+{
+#if GTEST_HAS_EXCEPTIONS
+ std::set_terminate(&TerminateHandler);
+#endif
+ testing::InitGoogleTest(&argc, argv);
+
+ // We want to ensure that people can use Google Test assertions in
+ // other testing frameworks, as long as they initialize Google Test
+ // properly and set the throw-on-failure mode. Therefore, we don't
+ // use Google Test's constructs for defining and running tests
+ // (e.g. TEST and RUN_ALL_TESTS) here.
+
+ // In the throw-on-failure mode with exceptions disabled, this
+ // assertion will cause the program to exit with a non-zero code.
+ EXPECT_EQ(2, 3);
+
+ // When not in the throw-on-failure mode, the control will reach
+ // here.
+ return 0;
+}
diff --git a/external/gtest-1.6.0/test/gtest_uninitialized_test.py b/external/gtest-1.6.0/test/gtest_uninitialized_test.py
new file mode 100755
index 0000000..6ae57ee
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_uninitialized_test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that Google Test warns the user when not initialized properly."""
+
+__author__ = 'wan at google.com (Zhanyong Wan)'
+
+import gtest_test_utils
+
+
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_uninitialized_test_')
+
+
+def Assert(condition):
+ if not condition:
+ raise AssertionError
+
+
+def AssertEq(expected, actual):
+ if expected != actual:
+ print 'Expected: %s' % (expected,)
+ print ' Actual: %s' % (actual,)
+ raise AssertionError
+
+
+def TestExitCodeAndOutput(command):
+ """Runs the given command and verifies its exit code and output."""
+
+ # Verifies that 'command' exits with code 1.
+ p = gtest_test_utils.Subprocess(command)
+ Assert(p.exited)
+ AssertEq(1, p.exit_code)
+ Assert('InitGoogleTest' in p.output)
+
+
+class GTestUninitializedTest(gtest_test_utils.TestCase):
+ def testExitCodeAndOutput(self):
+ TestExitCodeAndOutput(COMMAND)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_uninitialized_test_.cc b/external/gtest-1.6.0/test/gtest_uninitialized_test_.cc
new file mode 100644
index 0000000..597f0b5
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_uninitialized_test_.cc
@@ -0,0 +1,45 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest.h"
+
+TEST(DummyTest, Dummy)
+{
+ // This test doesn't verify anything. We just need it to create a
+ // realistic stage for testing the behavior of Google Test when
+ // RUN_ALL_TESTS() is called without testing::InitGoogleTest() being
+ // called first.
+}
+
+int main()
+{
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_unittest.cc b/external/gtest-1.6.0/test/gtest_unittest.cc
new file mode 100644
index 0000000..5ec8fd3
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_unittest.cc
@@ -0,0 +1,7951 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// Tests for Google Test itself. This verifies that the basic constructs of
+// Google Test work.
+
+#include "gtest/gtest.h"
+
+// Verifies that the command line flag variables can be accessed
+// in code once <gtest/gtest.h> has been #included.
+// Do not move it after other #includes.
+TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded)
+{
+ bool dummy = testing::GTEST_FLAG(also_run_disabled_tests)
+ || testing::GTEST_FLAG(break_on_failure)
+ || testing::GTEST_FLAG(catch_exceptions)
+ || testing::GTEST_FLAG(color) != "unknown"
+ || testing::GTEST_FLAG(filter) != "unknown"
+ || testing::GTEST_FLAG(list_tests)
+ || testing::GTEST_FLAG(output) != "unknown"
+ || testing::GTEST_FLAG(print_time)
+ || testing::GTEST_FLAG(random_seed)
+ || testing::GTEST_FLAG(repeat) > 0
+ || testing::GTEST_FLAG(show_internal_stack_frames)
+ || testing::GTEST_FLAG(shuffle)
+ || testing::GTEST_FLAG(stack_trace_depth) > 0
+ || testing::GTEST_FLAG(stream_result_to) != "unknown"
+ || testing::GTEST_FLAG(throw_on_failure);
+ EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused.
+}
+
+#include <limits.h> // For INT_MAX.
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <map>
+#include <vector>
+#include <ostream>
+
+#include "gtest/gtest-spi.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing
+{
+namespace internal
+{
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+class StreamingListenerTest : public Test
+{
+ public:
+ class FakeSocketWriter : public StreamingListener::AbstractSocketWriter
+ {
+ public:
+ // Sends a string to the socket.
+ virtual void Send(const string& message) { output_ += message; }
+
+ string output_;
+ };
+
+ StreamingListenerTest()
+ : fake_sock_writer_(new FakeSocketWriter),
+ streamer_(fake_sock_writer_),
+ test_info_obj_("FooTest", "Bar", NULL, NULL, 0, NULL) {}
+
+ protected:
+ string* output() { return &(fake_sock_writer_->output_); }
+
+ FakeSocketWriter* const fake_sock_writer_;
+ StreamingListener streamer_;
+ UnitTest unit_test_;
+ TestInfo test_info_obj_; // The name test_info_ was taken by testing::Test.
+};
+
+TEST_F(StreamingListenerTest, OnTestProgramEnd)
+{
+ *output() = "";
+ streamer_.OnTestProgramEnd(unit_test_);
+ EXPECT_EQ("event=TestProgramEnd&passed=1\n", *output());
+}
+
+TEST_F(StreamingListenerTest, OnTestIterationEnd)
+{
+ *output() = "";
+ streamer_.OnTestIterationEnd(unit_test_, 42);
+ EXPECT_EQ("event=TestIterationEnd&passed=1&elapsed_time=0ms\n", *output());
+}
+
+TEST_F(StreamingListenerTest, OnTestCaseStart)
+{
+ *output() = "";
+ streamer_.OnTestCaseStart(TestCase("FooTest", "Bar", NULL, NULL));
+ EXPECT_EQ("event=TestCaseStart&name=FooTest\n", *output());
+}
+
+TEST_F(StreamingListenerTest, OnTestCaseEnd)
+{
+ *output() = "";
+ streamer_.OnTestCaseEnd(TestCase("FooTest", "Bar", NULL, NULL));
+ EXPECT_EQ("event=TestCaseEnd&passed=1&elapsed_time=0ms\n", *output());
+}
+
+TEST_F(StreamingListenerTest, OnTestStart)
+{
+ *output() = "";
+ streamer_.OnTestStart(test_info_obj_);
+ EXPECT_EQ("event=TestStart&name=Bar\n", *output());
+}
+
+TEST_F(StreamingListenerTest, OnTestEnd)
+{
+ *output() = "";
+ streamer_.OnTestEnd(test_info_obj_);
+ EXPECT_EQ("event=TestEnd&passed=1&elapsed_time=0ms\n", *output());
+}
+
+TEST_F(StreamingListenerTest, OnTestPartResult)
+{
+ *output() = "";
+ streamer_.OnTestPartResult(TestPartResult(
+ TestPartResult::kFatalFailure, "foo.cc", 42, "failed=\n&%"));
+
+ // Meta characters in the failure message should be properly escaped.
+ EXPECT_EQ(
+ "event=TestPartResult&file=foo.cc&line=42&message=failed%3D%0A%26%25\n",
+ *output());
+}
+
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+// Provides access to otherwise private parts of the TestEventListeners class
+// that are needed to test it.
+class TestEventListenersAccessor
+{
+ public:
+ static TestEventListener* GetRepeater(TestEventListeners* listeners) {
+ return listeners->repeater();
+ }
+
+ static void SetDefaultResultPrinter(TestEventListeners* listeners,
+ TestEventListener* listener) {
+ listeners->SetDefaultResultPrinter(listener);
+ }
+ static void SetDefaultXmlGenerator(TestEventListeners* listeners,
+ TestEventListener* listener) {
+ listeners->SetDefaultXmlGenerator(listener);
+ }
+
+ static bool EventForwardingEnabled(const TestEventListeners& listeners) {
+ return listeners.EventForwardingEnabled();
+ }
+
+ static void SuppressEventForwarding(TestEventListeners* listeners) {
+ listeners->SuppressEventForwarding();
+ }
+};
+
+class UnitTestRecordPropertyTestHelper : public Test
+{
+ protected:
+ UnitTestRecordPropertyTestHelper() {}
+
+ // Forwards to UnitTest::RecordProperty() to bypass access controls.
+ void UnitTestRecordProperty(const char* key, const std::string& value) {
+ unit_test_.RecordProperty(key, value);
+ }
+
+ UnitTest unit_test_;
+};
+
+} // namespace internal
+} // namespace testing
+
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+using testing::DoubleLE;
+using testing::EmptyTestEventListener;
+using testing::Environment;
+using testing::FloatLE;
+using testing::GTEST_FLAG(also_run_disabled_tests);
+using testing::GTEST_FLAG(break_on_failure);
+using testing::GTEST_FLAG(catch_exceptions);
+using testing::GTEST_FLAG(color);
+using testing::GTEST_FLAG(death_test_use_fork);
+using testing::GTEST_FLAG(filter);
+using testing::GTEST_FLAG(list_tests);
+using testing::GTEST_FLAG(output);
+using testing::GTEST_FLAG(print_time);
+using testing::GTEST_FLAG(random_seed);
+using testing::GTEST_FLAG(repeat);
+using testing::GTEST_FLAG(show_internal_stack_frames);
+using testing::GTEST_FLAG(shuffle);
+using testing::GTEST_FLAG(stack_trace_depth);
+using testing::GTEST_FLAG(stream_result_to);
+using testing::GTEST_FLAG(throw_on_failure);
+using testing::IsNotSubstring;
+using testing::IsSubstring;
+using testing::Message;
+using testing::ScopedFakeTestPartResultReporter;
+using testing::StaticAssertTypeEq;
+using testing::Test;
+using testing::TestCase;
+using testing::TestEventListeners;
+using testing::TestInfo;
+using testing::TestPartResult;
+using testing::TestPartResultArray;
+using testing::TestProperty;
+using testing::TestResult;
+using testing::TimeInMillis;
+using testing::UnitTest;
+using testing::kMaxStackTraceDepth;
+using testing::internal::AddReference;
+using testing::internal::AlwaysFalse;
+using testing::internal::AlwaysTrue;
+using testing::internal::AppendUserMessage;
+using testing::internal::ArrayAwareFind;
+using testing::internal::ArrayEq;
+using testing::internal::CodePointToUtf8;
+using testing::internal::CompileAssertTypesEqual;
+using testing::internal::CopyArray;
+using testing::internal::CountIf;
+using testing::internal::EqFailure;
+using testing::internal::FloatingPoint;
+using testing::internal::ForEach;
+using testing::internal::FormatEpochTimeInMillisAsIso8601;
+using testing::internal::FormatTimeInMillisAsSeconds;
+using testing::internal::GTestFlagSaver;
+using testing::internal::GetCurrentOsStackTraceExceptTop;
+using testing::internal::GetElementOr;
+using testing::internal::GetNextRandomSeed;
+using testing::internal::GetRandomSeedFromFlag;
+using testing::internal::GetTestTypeId;
+using testing::internal::GetTimeInMillis;
+using testing::internal::GetTypeId;
+using testing::internal::GetUnitTestImpl;
+using testing::internal::ImplicitlyConvertible;
+using testing::internal::Int32;
+using testing::internal::Int32FromEnvOrDie;
+using testing::internal::IsAProtocolMessage;
+using testing::internal::IsContainer;
+using testing::internal::IsContainerTest;
+using testing::internal::IsNotContainer;
+using testing::internal::NativeArray;
+using testing::internal::ParseInt32Flag;
+using testing::internal::RemoveConst;
+using testing::internal::RemoveReference;
+using testing::internal::ShouldRunTestOnShard;
+using testing::internal::ShouldShard;
+using testing::internal::ShouldUseColor;
+using testing::internal::Shuffle;
+using testing::internal::ShuffleRange;
+using testing::internal::SkipPrefix;
+using testing::internal::StreamableToString;
+using testing::internal::String;
+using testing::internal::TestEventListenersAccessor;
+using testing::internal::TestResultAccessor;
+using testing::internal::UInt32;
+using testing::internal::WideStringToUtf8;
+using testing::internal::kCopy;
+using testing::internal::kMaxRandomSeed;
+using testing::internal::kReference;
+using testing::internal::kTestTypeIdInGoogleTest;
+using testing::internal::scoped_ptr;
+
+#if GTEST_HAS_STREAM_REDIRECTION
+using testing::internal::CaptureStdout;
+using testing::internal::GetCapturedStdout;
+#endif
+
+#if GTEST_IS_THREADSAFE
+using testing::internal::ThreadWithParam;
+#endif
+
+class TestingVector : public std::vector<int>
+{
+};
+
+::std::ostream& operator<<(::std::ostream& os,
+ const TestingVector& vector)
+{
+ os << "{ ";
+ for (size_t i = 0; i < vector.size(); i++) {
+ os << vector[i] << " ";
+ }
+ os << "}";
+ return os;
+}
+
+// This line tests that we can define tests in an unnamed namespace.
+namespace
+{
+
+TEST(GetRandomSeedFromFlagTest, HandlesZero)
+{
+ const int seed = GetRandomSeedFromFlag(0);
+ EXPECT_LE(1, seed);
+ EXPECT_LE(seed, static_cast<int>(kMaxRandomSeed));
+}
+
+TEST(GetRandomSeedFromFlagTest, PreservesValidSeed)
+{
+ EXPECT_EQ(1, GetRandomSeedFromFlag(1));
+ EXPECT_EQ(2, GetRandomSeedFromFlag(2));
+ EXPECT_EQ(kMaxRandomSeed - 1, GetRandomSeedFromFlag(kMaxRandomSeed - 1));
+ EXPECT_EQ(static_cast<int>(kMaxRandomSeed),
+ GetRandomSeedFromFlag(kMaxRandomSeed));
+}
+
+TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed)
+{
+ const int seed1 = GetRandomSeedFromFlag(-1);
+ EXPECT_LE(1, seed1);
+ EXPECT_LE(seed1, static_cast<int>(kMaxRandomSeed));
+
+ const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1);
+ EXPECT_LE(1, seed2);
+ EXPECT_LE(seed2, static_cast<int>(kMaxRandomSeed));
+}
+
+TEST(GetNextRandomSeedTest, WorksForValidInput)
+{
+ EXPECT_EQ(2, GetNextRandomSeed(1));
+ EXPECT_EQ(3, GetNextRandomSeed(2));
+ EXPECT_EQ(static_cast<int>(kMaxRandomSeed),
+ GetNextRandomSeed(kMaxRandomSeed - 1));
+ EXPECT_EQ(1, GetNextRandomSeed(kMaxRandomSeed));
+
+ // We deliberately don't test GetNextRandomSeed() with invalid
+ // inputs, as that requires death tests, which are expensive. This
+ // is fine as GetNextRandomSeed() is internal and has a
+ // straightforward definition.
+}
+
+static void ClearCurrentTestPartResults()
+{
+ TestResultAccessor::ClearTestPartResults(
+ GetUnitTestImpl()->current_test_result());
+}
+
+// Tests GetTypeId.
+
+TEST(GetTypeIdTest, ReturnsSameValueForSameType)
+{
+ EXPECT_EQ(GetTypeId<int>(), GetTypeId<int>());
+ EXPECT_EQ(GetTypeId<Test>(), GetTypeId<Test>());
+}
+
+class SubClassOfTest : public Test {};
+class AnotherSubClassOfTest : public Test {};
+
+TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes)
+{
+ EXPECT_NE(GetTypeId<int>(), GetTypeId<const int>());
+ EXPECT_NE(GetTypeId<int>(), GetTypeId<char>());
+ EXPECT_NE(GetTypeId<int>(), GetTestTypeId());
+ EXPECT_NE(GetTypeId<SubClassOfTest>(), GetTestTypeId());
+ EXPECT_NE(GetTypeId<AnotherSubClassOfTest>(), GetTestTypeId());
+ EXPECT_NE(GetTypeId<AnotherSubClassOfTest>(), GetTypeId<SubClassOfTest>());
+}
+
+// Verifies that GetTestTypeId() returns the same value, no matter it
+// is called from inside Google Test or outside of it.
+TEST(GetTestTypeIdTest, ReturnsTheSameValueInsideOrOutsideOfGoogleTest)
+{
+ EXPECT_EQ(kTestTypeIdInGoogleTest, GetTestTypeId());
+}
+
+// Tests FormatTimeInMillisAsSeconds().
+
+TEST(FormatTimeInMillisAsSecondsTest, FormatsZero)
+{
+ EXPECT_EQ("0", FormatTimeInMillisAsSeconds(0));
+}
+
+TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber)
+{
+ EXPECT_EQ("0.003", FormatTimeInMillisAsSeconds(3));
+ EXPECT_EQ("0.01", FormatTimeInMillisAsSeconds(10));
+ EXPECT_EQ("0.2", FormatTimeInMillisAsSeconds(200));
+ EXPECT_EQ("1.2", FormatTimeInMillisAsSeconds(1200));
+ EXPECT_EQ("3", FormatTimeInMillisAsSeconds(3000));
+}
+
+TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber)
+{
+ EXPECT_EQ("-0.003", FormatTimeInMillisAsSeconds(-3));
+ EXPECT_EQ("-0.01", FormatTimeInMillisAsSeconds(-10));
+ EXPECT_EQ("-0.2", FormatTimeInMillisAsSeconds(-200));
+ EXPECT_EQ("-1.2", FormatTimeInMillisAsSeconds(-1200));
+ EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000));
+}
+
+// Tests FormatEpochTimeInMillisAsIso8601(). The correctness of conversion
+// for particular dates below was verified in Python using
+// datetime.datetime.fromutctimestamp(<timetamp>/1000).
+
+// FormatEpochTimeInMillisAsIso8601 depends on the current timezone, so we
+// have to set up a particular timezone to obtain predictable results.
+class FormatEpochTimeInMillisAsIso8601Test : public Test
+{
+ public:
+ // On Cygwin, GCC doesn't allow unqualified integer literals to exceed
+ // 32 bits, even when 64-bit integer types are available. We have to
+ // force the constants to have a 64-bit type here.
+ static const TimeInMillis kMillisPerSec = 1000;
+
+ private:
+ virtual void SetUp() {
+ saved_tz_ = NULL;
+#if _MSC_VER
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4996) // Temporarily disables warning 4996
+ // (function or variable may be unsafe
+ // for getenv, function is deprecated for
+ // strdup).
+ if (getenv("TZ"))
+ saved_tz_ = strdup(getenv("TZ"));
+# pragma warning(pop) // Restores the warning state again.
+#else
+ if (getenv("TZ"))
+ saved_tz_ = strdup(getenv("TZ"));
+#endif
+
+ // Set up the time zone for FormatEpochTimeInMillisAsIso8601 to use. We
+ // cannot use the local time zone because the function's output depends
+ // on the time zone.
+ SetTimeZone("UTC+00");
+ }
+
+ virtual void TearDown() {
+ SetTimeZone(saved_tz_);
+ free(const_cast<char*>(saved_tz_));
+ saved_tz_ = NULL;
+ }
+
+ static void SetTimeZone(const char* time_zone) {
+ // tzset() distinguishes between the TZ variable being present and empty
+ // and not being present, so we have to consider the case of time_zone
+ // being NULL.
+#if _MSC_VER
+ // ...Unless it's MSVC, whose standard library's _putenv doesn't
+ // distinguish between an empty and a missing variable.
+ const std::string env_var =
+ std::string("TZ=") + (time_zone ? time_zone : "");
+ _putenv(env_var.c_str());
+# pragma warning(push) // Saves the current warning state.
+# pragma warning(disable:4996) // Temporarily disables warning 4996
+ // (function is deprecated).
+ tzset();
+# pragma warning(pop) // Restores the warning state again.
+#else
+ if (time_zone) {
+ setenv(("TZ"), time_zone, 1);
+ } else {
+ unsetenv("TZ");
+ }
+ tzset();
+#endif
+ }
+
+ const char* saved_tz_;
+};
+
+const TimeInMillis FormatEpochTimeInMillisAsIso8601Test::kMillisPerSec;
+
+TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsTwoDigitSegments)
+{
+ EXPECT_EQ("2011-10-31T18:52:42",
+ FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec));
+}
+
+TEST_F(FormatEpochTimeInMillisAsIso8601Test, MillisecondsDoNotAffectResult)
+{
+ EXPECT_EQ(
+ "2011-10-31T18:52:42",
+ FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec + 234));
+}
+
+TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsLeadingZeroes)
+{
+ EXPECT_EQ("2011-09-03T05:07:02",
+ FormatEpochTimeInMillisAsIso8601(1315026422 * kMillisPerSec));
+}
+
+TEST_F(FormatEpochTimeInMillisAsIso8601Test, Prints24HourTime)
+{
+ EXPECT_EQ("2011-09-28T17:08:22",
+ FormatEpochTimeInMillisAsIso8601(1317229702 * kMillisPerSec));
+}
+
+TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart)
+{
+ EXPECT_EQ("1970-01-01T00:00:00", FormatEpochTimeInMillisAsIso8601(0));
+}
+
+#if GTEST_CAN_COMPARE_NULL
+
+# ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+# pragma option push -w-ccc -w-rch
+# endif
+
+// Tests that GTEST_IS_NULL_LITERAL_(x) is true when x is a null
+// pointer literal.
+TEST(NullLiteralTest, IsTrueForNullLiterals)
+{
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(NULL));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0U));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0L));
+}
+
+// Tests that GTEST_IS_NULL_LITERAL_(x) is false when x is not a null
+// pointer literal.
+TEST(NullLiteralTest, IsFalseForNonNullLiterals)
+{
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(1));
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(0.0));
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_('a'));
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(static_cast<void*>(NULL)));
+}
+
+# ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" suppressed them.
+# pragma option pop
+# endif
+
+#endif // GTEST_CAN_COMPARE_NULL
+//
+// Tests CodePointToUtf8().
+
+// Tests that the NUL character L'\0' is encoded correctly.
+TEST(CodePointToUtf8Test, CanEncodeNul)
+{
+ EXPECT_EQ("", CodePointToUtf8(L'\0'));
+}
+
+// Tests that ASCII characters are encoded correctly.
+TEST(CodePointToUtf8Test, CanEncodeAscii)
+{
+ EXPECT_EQ("a", CodePointToUtf8(L'a'));
+ EXPECT_EQ("Z", CodePointToUtf8(L'Z'));
+ EXPECT_EQ("&", CodePointToUtf8(L'&'));
+ EXPECT_EQ("\x7F", CodePointToUtf8(L'\x7F'));
+}
+
+// Tests that Unicode code-points that have 8 to 11 bits are encoded
+// as 110xxxxx 10xxxxxx.
+TEST(CodePointToUtf8Test, CanEncode8To11Bits)
+{
+ // 000 1101 0011 => 110-00011 10-010011
+ EXPECT_EQ("\xC3\x93", CodePointToUtf8(L'\xD3'));
+
+ // 101 0111 0110 => 110-10101 10-110110
+ // Some compilers (e.g., GCC on MinGW) cannot handle non-ASCII codepoints
+ // in wide strings and wide chars. In order to accomodate them, we have to
+ // introduce such character constants as integers.
+ EXPECT_EQ("\xD5\xB6",
+ CodePointToUtf8(static_cast<wchar_t>(0x576)));
+}
+
+// Tests that Unicode code-points that have 12 to 16 bits are encoded
+// as 1110xxxx 10xxxxxx 10xxxxxx.
+TEST(CodePointToUtf8Test, CanEncode12To16Bits)
+{
+ // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011
+ EXPECT_EQ("\xE0\xA3\x93",
+ CodePointToUtf8(static_cast<wchar_t>(0x8D3)));
+
+ // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101
+ EXPECT_EQ("\xEC\x9D\x8D",
+ CodePointToUtf8(static_cast<wchar_t>(0xC74D)));
+}
+
+#if !GTEST_WIDE_STRING_USES_UTF16_
+// Tests in this group require a wchar_t to hold > 16 bits, and thus
+// are skipped on Windows, Cygwin, and Symbian, where a wchar_t is
+// 16-bit wide. This code may not compile on those systems.
+
+// Tests that Unicode code-points that have 17 to 21 bits are encoded
+// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx.
+TEST(CodePointToUtf8Test, CanEncode17To21Bits)
+{
+ // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011
+ EXPECT_EQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3'));
+
+ // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000
+ EXPECT_EQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400'));
+
+ // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100
+ EXPECT_EQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634'));
+}
+
+// Tests that encoding an invalid code-point generates the expected result.
+TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint)
+{
+ EXPECT_EQ("(Invalid Unicode 0x1234ABCD)", CodePointToUtf8(L'\x1234ABCD'));
+}
+
+#endif // !GTEST_WIDE_STRING_USES_UTF16_
+
+// Tests WideStringToUtf8().
+
+// Tests that the NUL character L'\0' is encoded correctly.
+TEST(WideStringToUtf8Test, CanEncodeNul)
+{
+ EXPECT_STREQ("", WideStringToUtf8(L"", 0).c_str());
+ EXPECT_STREQ("", WideStringToUtf8(L"", -1).c_str());
+}
+
+// Tests that ASCII strings are encoded correctly.
+TEST(WideStringToUtf8Test, CanEncodeAscii)
+{
+ EXPECT_STREQ("a", WideStringToUtf8(L"a", 1).c_str());
+ EXPECT_STREQ("ab", WideStringToUtf8(L"ab", 2).c_str());
+ EXPECT_STREQ("a", WideStringToUtf8(L"a", -1).c_str());
+ EXPECT_STREQ("ab", WideStringToUtf8(L"ab", -1).c_str());
+}
+
+// Tests that Unicode code-points that have 8 to 11 bits are encoded
+// as 110xxxxx 10xxxxxx.
+TEST(WideStringToUtf8Test, CanEncode8To11Bits)
+{
+ // 000 1101 0011 => 110-00011 10-010011
+ EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", 1).c_str());
+ EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", -1).c_str());
+
+ // 101 0111 0110 => 110-10101 10-110110
+ const wchar_t s[] = { 0x576, '\0' };
+ EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, 1).c_str());
+ EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, -1).c_str());
+}
+
+// Tests that Unicode code-points that have 12 to 16 bits are encoded
+// as 1110xxxx 10xxxxxx 10xxxxxx.
+TEST(WideStringToUtf8Test, CanEncode12To16Bits)
+{
+ // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011
+ const wchar_t s1[] = { 0x8D3, '\0' };
+ EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, 1).c_str());
+ EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, -1).c_str());
+
+ // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101
+ const wchar_t s2[] = { 0xC74D, '\0' };
+ EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, 1).c_str());
+ EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, -1).c_str());
+}
+
+// Tests that the conversion stops when the function encounters \0 character.
+TEST(WideStringToUtf8Test, StopsOnNulCharacter)
+{
+ EXPECT_STREQ("ABC", WideStringToUtf8(L"ABC\0XYZ", 100).c_str());
+}
+
+// Tests that the conversion stops when the function reaches the limit
+// specified by the 'length' parameter.
+TEST(WideStringToUtf8Test, StopsWhenLengthLimitReached)
+{
+ EXPECT_STREQ("ABC", WideStringToUtf8(L"ABCDEF", 3).c_str());
+}
+
+#if !GTEST_WIDE_STRING_USES_UTF16_
+// Tests that Unicode code-points that have 17 to 21 bits are encoded
+// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. This code may not compile
+// on the systems using UTF-16 encoding.
+TEST(WideStringToUtf8Test, CanEncode17To21Bits)
+{
+ // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011
+ EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", 1).c_str());
+ EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", -1).c_str());
+
+ // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100
+ EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", 1).c_str());
+ EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", -1).c_str());
+}
+
+// Tests that encoding an invalid code-point generates the expected result.
+TEST(WideStringToUtf8Test, CanEncodeInvalidCodePoint)
+{
+ EXPECT_STREQ("(Invalid Unicode 0xABCDFF)",
+ WideStringToUtf8(L"\xABCDFF", -1).c_str());
+}
+#else // !GTEST_WIDE_STRING_USES_UTF16_
+// Tests that surrogate pairs are encoded correctly on the systems using
+// UTF-16 encoding in the wide strings.
+TEST(WideStringToUtf8Test, CanEncodeValidUtf16SUrrogatePairs)
+{
+ const wchar_t s[] = { 0xD801, 0xDC00, '\0' };
+ EXPECT_STREQ("\xF0\x90\x90\x80", WideStringToUtf8(s, -1).c_str());
+}
+
+// Tests that encoding an invalid UTF-16 surrogate pair
+// generates the expected result.
+TEST(WideStringToUtf8Test, CanEncodeInvalidUtf16SurrogatePair)
+{
+ // Leading surrogate is at the end of the string.
+ const wchar_t s1[] = { 0xD800, '\0' };
+ EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(s1, -1).c_str());
+ // Leading surrogate is not followed by the trailing surrogate.
+ const wchar_t s2[] = { 0xD800, 'M', '\0' };
+ EXPECT_STREQ("\xED\xA0\x80M", WideStringToUtf8(s2, -1).c_str());
+ // Trailing surrogate appearas without a leading surrogate.
+ const wchar_t s3[] = { 0xDC00, 'P', 'Q', 'R', '\0' };
+ EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(s3, -1).c_str());
+}
+#endif // !GTEST_WIDE_STRING_USES_UTF16_
+
+// Tests that codepoint concatenation works correctly.
+#if !GTEST_WIDE_STRING_USES_UTF16_
+TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly)
+{
+ const wchar_t s[] = { 0x108634, 0xC74D, '\n', 0x576, 0x8D3, 0x108634, '\0'};
+ EXPECT_STREQ(
+ "\xF4\x88\x98\xB4"
+ "\xEC\x9D\x8D"
+ "\n"
+ "\xD5\xB6"
+ "\xE0\xA3\x93"
+ "\xF4\x88\x98\xB4",
+ WideStringToUtf8(s, -1).c_str());
+}
+#else
+TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly)
+{
+ const wchar_t s[] = { 0xC74D, '\n', 0x576, 0x8D3, '\0'};
+ EXPECT_STREQ(
+ "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93",
+ WideStringToUtf8(s, -1).c_str());
+}
+#endif // !GTEST_WIDE_STRING_USES_UTF16_
+
+// Tests the Random class.
+
+TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange)
+{
+ testing::internal::Random random(42);
+ EXPECT_DEATH_IF_SUPPORTED(
+ random.Generate(0),
+ "Cannot generate a number in the range \\[0, 0\\)");
+ EXPECT_DEATH_IF_SUPPORTED(
+ random.Generate(testing::internal::Random::kMaxRange + 1),
+ "Generation of a number in \\[0, 2147483649\\) was requested, "
+ "but this can only generate numbers in \\[0, 2147483648\\)");
+}
+
+TEST(RandomTest, GeneratesNumbersWithinRange)
+{
+ const UInt32 kRange = 10000;
+ testing::internal::Random random(12345);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i;
+ }
+
+ testing::internal::Random random2(testing::internal::Random::kMaxRange);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i;
+ }
+}
+
+TEST(RandomTest, RepeatsWhenReseeded)
+{
+ const int kSeed = 123;
+ const int kArraySize = 10;
+ const UInt32 kRange = 10000;
+ UInt32 values[kArraySize];
+
+ testing::internal::Random random(kSeed);
+ for (int i = 0; i < kArraySize; i++) {
+ values[i] = random.Generate(kRange);
+ }
+
+ random.Reseed(kSeed);
+ for (int i = 0; i < kArraySize; i++) {
+ EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i;
+ }
+}
+
+// Tests STL container utilities.
+
+// Tests CountIf().
+
+static bool IsPositive(int n) { return n > 0; }
+
+TEST(ContainerUtilityTest, CountIf)
+{
+ std::vector<int> v;
+ EXPECT_EQ(0, CountIf(v, IsPositive)); // Works for an empty container.
+
+ v.push_back(-1);
+ v.push_back(0);
+ EXPECT_EQ(0, CountIf(v, IsPositive)); // Works when no value satisfies.
+
+ v.push_back(2);
+ v.push_back(-10);
+ v.push_back(10);
+ EXPECT_EQ(2, CountIf(v, IsPositive));
+}
+
+// Tests ForEach().
+
+static int g_sum = 0;
+static void Accumulate(int n) { g_sum += n; }
+
+TEST(ContainerUtilityTest, ForEach)
+{
+ std::vector<int> v;
+ g_sum = 0;
+ ForEach(v, Accumulate);
+ EXPECT_EQ(0, g_sum); // Works for an empty container;
+
+ g_sum = 0;
+ v.push_back(1);
+ ForEach(v, Accumulate);
+ EXPECT_EQ(1, g_sum); // Works for a container with one element.
+
+ g_sum = 0;
+ v.push_back(20);
+ v.push_back(300);
+ ForEach(v, Accumulate);
+ EXPECT_EQ(321, g_sum);
+}
+
+// Tests GetElementOr().
+TEST(ContainerUtilityTest, GetElementOr)
+{
+ std::vector<char> a;
+ EXPECT_EQ('x', GetElementOr(a, 0, 'x'));
+
+ a.push_back('a');
+ a.push_back('b');
+ EXPECT_EQ('a', GetElementOr(a, 0, 'x'));
+ EXPECT_EQ('b', GetElementOr(a, 1, 'x'));
+ EXPECT_EQ('x', GetElementOr(a, -2, 'x'));
+ EXPECT_EQ('x', GetElementOr(a, 2, 'x'));
+}
+
+TEST(ContainerUtilityDeathTest, ShuffleRange)
+{
+ std::vector<int> a;
+ a.push_back(0);
+ a.push_back(1);
+ a.push_back(2);
+ testing::internal::Random random(1);
+
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, -1, 1, &a),
+ "Invalid shuffle range start -1: must be in range \\[0, 3\\]");
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, 4, 4, &a),
+ "Invalid shuffle range start 4: must be in range \\[0, 3\\]");
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, 3, 2, &a),
+ "Invalid shuffle range finish 2: must be in range \\[3, 3\\]");
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, 3, 4, &a),
+ "Invalid shuffle range finish 4: must be in range \\[3, 3\\]");
+}
+
+class VectorShuffleTest : public Test
+{
+ protected:
+ static const int kVectorSize = 20;
+
+ VectorShuffleTest() : random_(1) {
+ for (int i = 0; i < kVectorSize; i++) {
+ vector_.push_back(i);
+ }
+ }
+
+ static bool VectorIsCorrupt(const TestingVector& vector) {
+ if (kVectorSize != static_cast<int>(vector.size())) {
+ return true;
+ }
+
+ bool found_in_vector[kVectorSize] = { false };
+ for (size_t i = 0; i < vector.size(); i++) {
+ const int e = vector[i];
+ if (e < 0 || e >= kVectorSize || found_in_vector[e]) {
+ return true;
+ }
+ found_in_vector[e] = true;
+ }
+
+ // Vector size is correct, elements' range is correct, no
+ // duplicate elements. Therefore no corruption has occurred.
+ return false;
+ }
+
+ static bool VectorIsNotCorrupt(const TestingVector& vector) {
+ return !VectorIsCorrupt(vector);
+ }
+
+ static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) {
+ for (int i = begin; i < end; i++) {
+ if (i != vector[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static bool RangeIsUnshuffled(
+ const TestingVector& vector, int begin, int end) {
+ return !RangeIsShuffled(vector, begin, end);
+ }
+
+ static bool VectorIsShuffled(const TestingVector& vector) {
+ return RangeIsShuffled(vector, 0, static_cast<int>(vector.size()));
+ }
+
+ static bool VectorIsUnshuffled(const TestingVector& vector) {
+ return !VectorIsShuffled(vector);
+ }
+
+ testing::internal::Random random_;
+ TestingVector vector_;
+}; // class VectorShuffleTest
+
+const int VectorShuffleTest::kVectorSize;
+
+TEST_F(VectorShuffleTest, HandlesEmptyRange)
+{
+ // Tests an empty range at the beginning...
+ ShuffleRange(&random_, 0, 0, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...in the middle...
+ ShuffleRange(&random_, kVectorSize/2, kVectorSize/2, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...at the end...
+ ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...and past the end.
+ ShuffleRange(&random_, kVectorSize, kVectorSize, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+}
+
+TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne)
+{
+ // Tests a size one range at the beginning...
+ ShuffleRange(&random_, 0, 1, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...in the middle...
+ ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...and at the end.
+ ShuffleRange(&random_, kVectorSize - 1, kVectorSize, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+}
+
+// Because we use our own random number generator and a fixed seed,
+// we can guarantee that the following "random" tests will succeed.
+
+TEST_F(VectorShuffleTest, ShufflesEntireVector)
+{
+ Shuffle(&random_, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_;
+
+ // Tests the first and last elements in particular to ensure that
+ // there are no off-by-one problems in our shuffle algorithm.
+ EXPECT_NE(0, vector_[0]);
+ EXPECT_NE(kVectorSize - 1, vector_[kVectorSize - 1]);
+}
+
+TEST_F(VectorShuffleTest, ShufflesStartOfVector)
+{
+ const int kRangeSize = kVectorSize/2;
+
+ ShuffleRange(&random_, 0, kRangeSize, &vector_);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, kVectorSize);
+}
+
+TEST_F(VectorShuffleTest, ShufflesEndOfVector)
+{
+ const int kRangeSize = kVectorSize / 2;
+ ShuffleRange(&random_, kRangeSize, kVectorSize, &vector_);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize);
+ EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, kVectorSize);
+}
+
+TEST_F(VectorShuffleTest, ShufflesMiddleOfVector)
+{
+ int kRangeSize = kVectorSize/3;
+ ShuffleRange(&random_, kRangeSize, 2*kRangeSize, &vector_);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize);
+ EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, 2*kRangeSize, kVectorSize);
+}
+
+TEST_F(VectorShuffleTest, ShufflesRepeatably)
+{
+ TestingVector vector2;
+ for (int i = 0; i < kVectorSize; i++) {
+ vector2.push_back(i);
+ }
+
+ random_.Reseed(1234);
+ Shuffle(&random_, &vector_);
+ random_.Reseed(1234);
+ Shuffle(&random_, &vector2);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector2);
+
+ for (int i = 0; i < kVectorSize; i++) {
+ EXPECT_EQ(vector_[i], vector2[i]) << " where i is " << i;
+ }
+}
+
+// Tests the size of the AssertHelper class.
+
+TEST(AssertHelperTest, AssertHelperIsSmall)
+{
+ // To avoid breaking clients that use lots of assertions in one
+ // function, we cannot grow the size of AssertHelper.
+ EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*));
+}
+
+// Tests String::EndsWithCaseInsensitive().
+TEST(StringTest, EndsWithCaseInsensitive)
+{
+ EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "BAR"));
+ EXPECT_TRUE(String::EndsWithCaseInsensitive("foobaR", "bar"));
+ EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", ""));
+ EXPECT_TRUE(String::EndsWithCaseInsensitive("", ""));
+
+ EXPECT_FALSE(String::EndsWithCaseInsensitive("Foobar", "foo"));
+ EXPECT_FALSE(String::EndsWithCaseInsensitive("foobar", "Foo"));
+ EXPECT_FALSE(String::EndsWithCaseInsensitive("", "foo"));
+}
+
+// C++Builder's preprocessor is buggy; it fails to expand macros that
+// appear in macro parameters after wide char literals. Provide an alias
+// for NULL as a workaround.
+static const wchar_t* const kNull = NULL;
+
+// Tests String::CaseInsensitiveWideCStringEquals
+TEST(StringTest, CaseInsensitiveWideCStringEquals)
+{
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(NULL, NULL));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L""));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", kNull));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"foobar"));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", kNull));
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar"));
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR"));
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar"));
+}
+
+#if GTEST_OS_WINDOWS
+
+// Tests String::ShowWideCString().
+TEST(StringTest, ShowWideCString)
+{
+ EXPECT_STREQ("(null)",
+ String::ShowWideCString(NULL).c_str());
+ EXPECT_STREQ("", String::ShowWideCString(L"").c_str());
+ EXPECT_STREQ("foo", String::ShowWideCString(L"foo").c_str());
+}
+
+# if GTEST_OS_WINDOWS_MOBILE
+TEST(StringTest, AnsiAndUtf16Null)
+{
+ EXPECT_EQ(NULL, String::AnsiToUtf16(NULL));
+ EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL));
+}
+
+TEST(StringTest, AnsiAndUtf16ConvertBasic)
+{
+ const char* ansi = String::Utf16ToAnsi(L"str");
+ EXPECT_STREQ("str", ansi);
+ delete [] ansi;
+ const WCHAR* utf16 = String::AnsiToUtf16("str");
+ EXPECT_EQ(0, wcsncmp(L"str", utf16, 3));
+ delete [] utf16;
+}
+
+TEST(StringTest, AnsiAndUtf16ConvertPathChars)
+{
+ const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?");
+ EXPECT_STREQ(".:\\ \"*?", ansi);
+ delete [] ansi;
+ const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?");
+ EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3));
+ delete [] utf16;
+}
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+#endif // GTEST_OS_WINDOWS
+
+// Tests TestProperty construction.
+TEST(TestPropertyTest, StringValue)
+{
+ TestProperty property("key", "1");
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("1", property.value());
+}
+
+// Tests TestProperty replacing a value.
+TEST(TestPropertyTest, ReplaceStringValue)
+{
+ TestProperty property("key", "1");
+ EXPECT_STREQ("1", property.value());
+ property.SetValue("2");
+ EXPECT_STREQ("2", property.value());
+}
+
+// AddFatalFailure() and AddNonfatalFailure() must be stand-alone
+// functions (i.e. their definitions cannot be inlined at the call
+// sites), or C++Builder won't compile the code.
+static void AddFatalFailure()
+{
+ FAIL() << "Expected fatal failure.";
+}
+
+static void AddNonfatalFailure()
+{
+ ADD_FAILURE() << "Expected non-fatal failure.";
+}
+
+class ScopedFakeTestPartResultReporterTest : public Test
+{
+ public: // Must be public and not protected due to a bug in g++ 3.4.2.
+ enum FailureMode {
+ FATAL_FAILURE,
+ NONFATAL_FAILURE
+ };
+ static void AddFailure(FailureMode failure) {
+ if (failure == FATAL_FAILURE) {
+ AddFatalFailure();
+ } else {
+ AddNonfatalFailure();
+ }
+ }
+};
+
+// Tests that ScopedFakeTestPartResultReporter intercepts test
+// failures.
+TEST_F(ScopedFakeTestPartResultReporterTest, InterceptsTestFailures)
+{
+ TestPartResultArray results;
+ {
+ ScopedFakeTestPartResultReporter reporter(
+ ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD,
+ &results);
+ AddFailure(NONFATAL_FAILURE);
+ AddFailure(FATAL_FAILURE);
+ }
+
+ EXPECT_EQ(2, results.size());
+ EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed());
+}
+
+TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor)
+{
+ TestPartResultArray results;
+ {
+ // Tests, that the deprecated constructor still works.
+ ScopedFakeTestPartResultReporter reporter(&results);
+ AddFailure(NONFATAL_FAILURE);
+ }
+ EXPECT_EQ(1, results.size());
+}
+
+#if GTEST_IS_THREADSAFE
+
+class ScopedFakeTestPartResultReporterWithThreadsTest
+ : public ScopedFakeTestPartResultReporterTest
+{
+ protected:
+ static void AddFailureInOtherThread(FailureMode failure) {
+ ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL);
+ thread.Join();
+ }
+};
+
+TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest,
+ InterceptsTestFailuresInAllThreads)
+{
+ TestPartResultArray results;
+ {
+ ScopedFakeTestPartResultReporter reporter(
+ ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, &results);
+ AddFailure(NONFATAL_FAILURE);
+ AddFailure(FATAL_FAILURE);
+ AddFailureInOtherThread(NONFATAL_FAILURE);
+ AddFailureInOtherThread(FATAL_FAILURE);
+ }
+
+ EXPECT_EQ(4, results.size());
+ EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(2).nonfatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed());
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+// Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they
+// work even if the failure is generated in a called function rather than
+// the current context.
+
+typedef ScopedFakeTestPartResultReporterTest ExpectFatalFailureTest;
+
+TEST_F(ExpectFatalFailureTest, CatchesFatalFaliure)
+{
+ EXPECT_FATAL_FAILURE(AddFatalFailure(), "Expected fatal failure.");
+}
+
+#if GTEST_HAS_GLOBAL_STRING
+TEST_F(ExpectFatalFailureTest, AcceptsStringObject)
+{
+ EXPECT_FATAL_FAILURE(AddFatalFailure(), ::string("Expected fatal failure."));
+}
+#endif
+
+TEST_F(ExpectFatalFailureTest, AcceptsStdStringObject)
+{
+ EXPECT_FATAL_FAILURE(AddFatalFailure(),
+ ::std::string("Expected fatal failure."));
+}
+
+TEST_F(ExpectFatalFailureTest, CatchesFatalFailureOnAllThreads)
+{
+ // We have another test below to verify that the macro catches fatal
+ // failures generated on another thread.
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFatalFailure(),
+ "Expected fatal failure.");
+}
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true"
+# pragma option push -w-ccc
+#endif
+
+// Tests that EXPECT_FATAL_FAILURE() can be used in a non-void
+// function even when the statement in it contains ASSERT_*.
+
+int NonVoidFunction()
+{
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), "");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), "");
+ return 0;
+}
+
+TEST_F(ExpectFatalFailureTest, CanBeUsedInNonVoidFunction)
+{
+ NonVoidFunction();
+}
+
+// Tests that EXPECT_FATAL_FAILURE(statement, ...) doesn't abort the
+// current function even though 'statement' generates a fatal failure.
+
+void DoesNotAbortHelper(bool* aborted)
+{
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), "");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), "");
+
+ *aborted = false;
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" suppressed them.
+# pragma option pop
+#endif
+
+TEST_F(ExpectFatalFailureTest, DoesNotAbort)
+{
+ bool aborted = true;
+ DoesNotAbortHelper(&aborted);
+ EXPECT_FALSE(aborted);
+}
+
+// Tests that the EXPECT_FATAL_FAILURE{,_ON_ALL_THREADS} accepts a
+// statement that contains a macro which expands to code containing an
+// unprotected comma.
+
+static int global_var = 0;
+#define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++
+
+TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma)
+{
+#ifndef __BORLANDC__
+ // ICE's in C++Builder.
+ EXPECT_FATAL_FAILURE({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddFatalFailure();
+ }, "");
+#endif
+
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddFatalFailure();
+ }, "");
+}
+
+// Tests EXPECT_NONFATAL_FAILURE{,ON_ALL_THREADS}.
+
+typedef ScopedFakeTestPartResultReporterTest ExpectNonfatalFailureTest;
+
+TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailure)
+{
+ EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(),
+ "Expected non-fatal failure.");
+}
+
+#if GTEST_HAS_GLOBAL_STRING
+TEST_F(ExpectNonfatalFailureTest, AcceptsStringObject)
+{
+ EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(),
+ ::string("Expected non-fatal failure."));
+}
+#endif
+
+TEST_F(ExpectNonfatalFailureTest, AcceptsStdStringObject)
+{
+ EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(),
+ ::std::string("Expected non-fatal failure."));
+}
+
+TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailureOnAllThreads)
+{
+ // We have another test below to verify that the macro catches
+ // non-fatal failures generated on another thread.
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddNonfatalFailure(),
+ "Expected non-fatal failure.");
+}
+
+// Tests that the EXPECT_NONFATAL_FAILURE{,_ON_ALL_THREADS} accepts a
+// statement that contains a macro which expands to code containing an
+// unprotected comma.
+TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma)
+{
+ EXPECT_NONFATAL_FAILURE({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddNonfatalFailure();
+ }, "");
+
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddNonfatalFailure();
+ }, "");
+}
+
+#if GTEST_IS_THREADSAFE
+
+typedef ScopedFakeTestPartResultReporterWithThreadsTest
+ExpectFailureWithThreadsTest;
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailureOnAllThreads)
+{
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailureInOtherThread(FATAL_FAILURE),
+ "Expected fatal failure.");
+}
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads)
+{
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(
+ AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure.");
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+// Tests the TestProperty class.
+
+TEST(TestPropertyTest, ConstructorWorks)
+{
+ const TestProperty property("key", "value");
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("value", property.value());
+}
+
+TEST(TestPropertyTest, SetValue)
+{
+ TestProperty property("key", "value_1");
+ EXPECT_STREQ("key", property.key());
+ property.SetValue("value_2");
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("value_2", property.value());
+}
+
+// Tests the TestResult class
+
+// The test fixture for testing TestResult.
+class TestResultTest : public Test
+{
+ protected:
+ typedef std::vector<TestPartResult> TPRVector;
+
+ // We make use of 2 TestPartResult objects,
+ TestPartResult* pr1, * pr2;
+
+ // ... and 3 TestResult objects.
+ TestResult* r0, * r1, * r2;
+
+ virtual void SetUp() {
+ // pr1 is for success.
+ pr1 = new TestPartResult(TestPartResult::kSuccess,
+ "foo/bar.cc",
+ 10,
+ "Success!");
+
+ // pr2 is for fatal failure.
+ pr2 = new TestPartResult(TestPartResult::kFatalFailure,
+ "foo/bar.cc",
+ -1, // This line number means "unknown"
+ "Failure!");
+
+ // Creates the TestResult objects.
+ r0 = new TestResult();
+ r1 = new TestResult();
+ r2 = new TestResult();
+
+ // In order to test TestResult, we need to modify its internal
+ // state, in particular the TestPartResult vector it holds.
+ // test_part_results() returns a const reference to this vector.
+ // We cast it to a non-const object s.t. it can be modified (yes,
+ // this is a hack).
+ TPRVector* results1 = const_cast<TPRVector*>(
+ &TestResultAccessor::test_part_results(*r1));
+ TPRVector* results2 = const_cast<TPRVector*>(
+ &TestResultAccessor::test_part_results(*r2));
+
+ // r0 is an empty TestResult.
+
+ // r1 contains a single SUCCESS TestPartResult.
+ results1->push_back(*pr1);
+
+ // r2 contains a SUCCESS, and a FAILURE.
+ results2->push_back(*pr1);
+ results2->push_back(*pr2);
+ }
+
+ virtual void TearDown() {
+ delete pr1;
+ delete pr2;
+
+ delete r0;
+ delete r1;
+ delete r2;
+ }
+
+ // Helper that compares two two TestPartResults.
+ static void CompareTestPartResult(const TestPartResult& expected,
+ const TestPartResult& actual) {
+ EXPECT_EQ(expected.type(), actual.type());
+ EXPECT_STREQ(expected.file_name(), actual.file_name());
+ EXPECT_EQ(expected.line_number(), actual.line_number());
+ EXPECT_STREQ(expected.summary(), actual.summary());
+ EXPECT_STREQ(expected.message(), actual.message());
+ EXPECT_EQ(expected.passed(), actual.passed());
+ EXPECT_EQ(expected.failed(), actual.failed());
+ EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed());
+ EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed());
+ }
+};
+
+// Tests TestResult::total_part_count().
+TEST_F(TestResultTest, total_part_count)
+{
+ ASSERT_EQ(0, r0->total_part_count());
+ ASSERT_EQ(1, r1->total_part_count());
+ ASSERT_EQ(2, r2->total_part_count());
+}
+
+// Tests TestResult::Passed().
+TEST_F(TestResultTest, Passed)
+{
+ ASSERT_TRUE(r0->Passed());
+ ASSERT_TRUE(r1->Passed());
+ ASSERT_FALSE(r2->Passed());
+}
+
+// Tests TestResult::Failed().
+TEST_F(TestResultTest, Failed)
+{
+ ASSERT_FALSE(r0->Failed());
+ ASSERT_FALSE(r1->Failed());
+ ASSERT_TRUE(r2->Failed());
+}
+
+// Tests TestResult::GetTestPartResult().
+
+typedef TestResultTest TestResultDeathTest;
+
+TEST_F(TestResultDeathTest, GetTestPartResult)
+{
+ CompareTestPartResult(*pr1, r2->GetTestPartResult(0));
+ CompareTestPartResult(*pr2, r2->GetTestPartResult(1));
+ EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(2), "");
+ EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(-1), "");
+}
+
+// Tests TestResult has no properties when none are added.
+TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded)
+{
+ TestResult test_result;
+ ASSERT_EQ(0, test_result.test_property_count());
+}
+
+// Tests TestResult has the expected property when added.
+TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded)
+{
+ TestResult test_result;
+ TestProperty property("key_1", "1");
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property);
+ ASSERT_EQ(1, test_result.test_property_count());
+ const TestProperty& actual_property = test_result.GetTestProperty(0);
+ EXPECT_STREQ("key_1", actual_property.key());
+ EXPECT_STREQ("1", actual_property.value());
+}
+
+// Tests TestResult has multiple properties when added.
+TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded)
+{
+ TestResult test_result;
+ TestProperty property_1("key_1", "1");
+ TestProperty property_2("key_2", "2");
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_1);
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_2);
+ ASSERT_EQ(2, test_result.test_property_count());
+ const TestProperty& actual_property_1 = test_result.GetTestProperty(0);
+ EXPECT_STREQ("key_1", actual_property_1.key());
+ EXPECT_STREQ("1", actual_property_1.value());
+
+ const TestProperty& actual_property_2 = test_result.GetTestProperty(1);
+ EXPECT_STREQ("key_2", actual_property_2.key());
+ EXPECT_STREQ("2", actual_property_2.value());
+}
+
+// Tests TestResult::RecordProperty() overrides values for duplicate keys.
+TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys)
+{
+ TestResult test_result;
+ TestProperty property_1_1("key_1", "1");
+ TestProperty property_2_1("key_2", "2");
+ TestProperty property_1_2("key_1", "12");
+ TestProperty property_2_2("key_2", "22");
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_1);
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_1);
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_2);
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_2);
+
+ ASSERT_EQ(2, test_result.test_property_count());
+ const TestProperty& actual_property_1 = test_result.GetTestProperty(0);
+ EXPECT_STREQ("key_1", actual_property_1.key());
+ EXPECT_STREQ("12", actual_property_1.value());
+
+ const TestProperty& actual_property_2 = test_result.GetTestProperty(1);
+ EXPECT_STREQ("key_2", actual_property_2.key());
+ EXPECT_STREQ("22", actual_property_2.value());
+}
+
+// Tests TestResult::GetTestProperty().
+TEST(TestResultPropertyTest, GetTestProperty)
+{
+ TestResult test_result;
+ TestProperty property_1("key_1", "1");
+ TestProperty property_2("key_2", "2");
+ TestProperty property_3("key_3", "3");
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_1);
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_2);
+ TestResultAccessor::RecordProperty(&test_result, "testcase", property_3);
+
+ const TestProperty& fetched_property_1 = test_result.GetTestProperty(0);
+ const TestProperty& fetched_property_2 = test_result.GetTestProperty(1);
+ const TestProperty& fetched_property_3 = test_result.GetTestProperty(2);
+
+ EXPECT_STREQ("key_1", fetched_property_1.key());
+ EXPECT_STREQ("1", fetched_property_1.value());
+
+ EXPECT_STREQ("key_2", fetched_property_2.key());
+ EXPECT_STREQ("2", fetched_property_2.value());
+
+ EXPECT_STREQ("key_3", fetched_property_3.key());
+ EXPECT_STREQ("3", fetched_property_3.value());
+
+ EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(3), "");
+ EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(-1), "");
+}
+
+// Tests that GTestFlagSaver works on Windows and Mac.
+
+class GTestFlagSaverTest : public Test
+{
+ protected:
+ // Saves the Google Test flags such that we can restore them later, and
+ // then sets them to their default values. This will be called
+ // before the first test in this test case is run.
+ static void SetUpTestCase() {
+ saver_ = new GTestFlagSaver;
+
+ GTEST_FLAG(also_run_disabled_tests) = false;
+ GTEST_FLAG(break_on_failure) = false;
+ GTEST_FLAG(catch_exceptions) = false;
+ GTEST_FLAG(death_test_use_fork) = false;
+ GTEST_FLAG(color) = "auto";
+ GTEST_FLAG(filter) = "";
+ GTEST_FLAG(list_tests) = false;
+ GTEST_FLAG(output) = "";
+ GTEST_FLAG(print_time) = true;
+ GTEST_FLAG(random_seed) = 0;
+ GTEST_FLAG(repeat) = 1;
+ GTEST_FLAG(shuffle) = false;
+ GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth;
+ GTEST_FLAG(stream_result_to) = "";
+ GTEST_FLAG(throw_on_failure) = false;
+ }
+
+ // Restores the Google Test flags that the tests have modified. This will
+ // be called after the last test in this test case is run.
+ static void TearDownTestCase() {
+ delete saver_;
+ saver_ = NULL;
+ }
+
+ // Verifies that the Google Test flags have their default values, and then
+ // modifies each of them.
+ void VerifyAndModifyFlags() {
+ EXPECT_FALSE(GTEST_FLAG(also_run_disabled_tests));
+ EXPECT_FALSE(GTEST_FLAG(break_on_failure));
+ EXPECT_FALSE(GTEST_FLAG(catch_exceptions));
+ EXPECT_STREQ("auto", GTEST_FLAG(color).c_str());
+ EXPECT_FALSE(GTEST_FLAG(death_test_use_fork));
+ EXPECT_STREQ("", GTEST_FLAG(filter).c_str());
+ EXPECT_FALSE(GTEST_FLAG(list_tests));
+ EXPECT_STREQ("", GTEST_FLAG(output).c_str());
+ EXPECT_TRUE(GTEST_FLAG(print_time));
+ EXPECT_EQ(0, GTEST_FLAG(random_seed));
+ EXPECT_EQ(1, GTEST_FLAG(repeat));
+ EXPECT_FALSE(GTEST_FLAG(shuffle));
+ EXPECT_EQ(kMaxStackTraceDepth, GTEST_FLAG(stack_trace_depth));
+ EXPECT_STREQ("", GTEST_FLAG(stream_result_to).c_str());
+ EXPECT_FALSE(GTEST_FLAG(throw_on_failure));
+
+ GTEST_FLAG(also_run_disabled_tests) = true;
+ GTEST_FLAG(break_on_failure) = true;
+ GTEST_FLAG(catch_exceptions) = true;
+ GTEST_FLAG(color) = "no";
+ GTEST_FLAG(death_test_use_fork) = true;
+ GTEST_FLAG(filter) = "abc";
+ GTEST_FLAG(list_tests) = true;
+ GTEST_FLAG(output) = "xml:foo.xml";
+ GTEST_FLAG(print_time) = false;
+ GTEST_FLAG(random_seed) = 1;
+ GTEST_FLAG(repeat) = 100;
+ GTEST_FLAG(shuffle) = true;
+ GTEST_FLAG(stack_trace_depth) = 1;
+ GTEST_FLAG(stream_result_to) = "localhost:1234";
+ GTEST_FLAG(throw_on_failure) = true;
+ }
+
+ private:
+ // For saving Google Test flags during this test case.
+ static GTestFlagSaver* saver_;
+};
+
+GTestFlagSaver* GTestFlagSaverTest::saver_ = NULL;
+
+// Google Test doesn't guarantee the order of tests. The following two
+// tests are designed to work regardless of their order.
+
+// Modifies the Google Test flags in the test body.
+TEST_F(GTestFlagSaverTest, ModifyGTestFlags)
+{
+ VerifyAndModifyFlags();
+}
+
+// Verifies that the Google Test flags in the body of the previous test were
+// restored to their original values.
+TEST_F(GTestFlagSaverTest, VerifyGTestFlags)
+{
+ VerifyAndModifyFlags();
+}
+
+// Sets an environment variable with the given name to the given
+// value. If the value argument is "", unsets the environment
+// variable. The caller must ensure that both arguments are not NULL.
+static void SetEnv(const char* name, const char* value)
+{
+#if GTEST_OS_WINDOWS_MOBILE
+ // Environment variables are not supported on Windows CE.
+ return;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+ // C++Builder's putenv only stores a pointer to its parameter; we have to
+ // ensure that the string remains valid as long as it might be needed.
+ // We use an std::map to do so.
+ static std::map<std::string, std::string*> added_env;
+
+ // Because putenv stores a pointer to the string buffer, we can't delete the
+ // previous string (if present) until after it's replaced.
+ std::string* prev_env = NULL;
+ if (added_env.find(name) != added_env.end()) {
+ prev_env = added_env[name];
+ }
+ added_env[name] = new std::string(
+ (Message() << name << "=" << value).GetString());
+
+ // The standard signature of putenv accepts a 'char*' argument. Other
+ // implementations, like C++Builder's, accept a 'const char*'.
+ // We cast away the 'const' since that would work for both variants.
+ putenv(const_cast<char*>(added_env[name]->c_str()));
+ delete prev_env;
+#elif GTEST_OS_WINDOWS // If we are on Windows proper.
+ _putenv((Message() << name << "=" << value).GetString().c_str());
+#else
+ if (*value == '\0') {
+ unsetenv(name);
+ } else {
+ setenv(name, value, 1);
+ }
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+#if !GTEST_OS_WINDOWS_MOBILE
+// Environment variables are not supported on Windows CE.
+
+using testing::internal::Int32FromGTestEnv;
+
+// Tests Int32FromGTestEnv().
+
+// Tests that Int32FromGTestEnv() returns the default value when the
+// environment variable is not set.
+TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenVariableIsNotSet)
+{
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "");
+ EXPECT_EQ(10, Int32FromGTestEnv("temp", 10));
+}
+
+// Tests that Int32FromGTestEnv() returns the default value when the
+// environment variable overflows as an Int32.
+TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueOverflows)
+{
+ printf("(expecting 2 warnings)\n");
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12345678987654321");
+ EXPECT_EQ(20, Int32FromGTestEnv("temp", 20));
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-12345678987654321");
+ EXPECT_EQ(30, Int32FromGTestEnv("temp", 30));
+}
+
+// Tests that Int32FromGTestEnv() returns the default value when the
+// environment variable does not represent a valid decimal integer.
+TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueIsInvalid)
+{
+ printf("(expecting 2 warnings)\n");
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "A1");
+ EXPECT_EQ(40, Int32FromGTestEnv("temp", 40));
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12X");
+ EXPECT_EQ(50, Int32FromGTestEnv("temp", 50));
+}
+
+// Tests that Int32FromGTestEnv() parses and returns the value of the
+// environment variable when it represents a valid decimal integer in
+// the range of an Int32.
+TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue)
+{
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "123");
+ EXPECT_EQ(123, Int32FromGTestEnv("temp", 0));
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321");
+ EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0));
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Tests ParseInt32Flag().
+
+// Tests that ParseInt32Flag() returns false and doesn't change the
+// output value when the flag has wrong format
+TEST(ParseInt32FlagTest, ReturnsFalseForInvalidFlag)
+{
+ Int32 value = 123;
+ EXPECT_FALSE(ParseInt32Flag("--a=100", "b", &value));
+ EXPECT_EQ(123, value);
+
+ EXPECT_FALSE(ParseInt32Flag("a=100", "a", &value));
+ EXPECT_EQ(123, value);
+}
+
+// Tests that ParseInt32Flag() returns false and doesn't change the
+// output value when the flag overflows as an Int32.
+TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueOverflows)
+{
+ printf("(expecting 2 warnings)\n");
+
+ Int32 value = 123;
+ EXPECT_FALSE(ParseInt32Flag("--abc=12345678987654321", "abc", &value));
+ EXPECT_EQ(123, value);
+
+ EXPECT_FALSE(ParseInt32Flag("--abc=-12345678987654321", "abc", &value));
+ EXPECT_EQ(123, value);
+}
+
+// Tests that ParseInt32Flag() returns false and doesn't change the
+// output value when the flag does not represent a valid decimal
+// integer.
+TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueIsInvalid)
+{
+ printf("(expecting 2 warnings)\n");
+
+ Int32 value = 123;
+ EXPECT_FALSE(ParseInt32Flag("--abc=A1", "abc", &value));
+ EXPECT_EQ(123, value);
+
+ EXPECT_FALSE(ParseInt32Flag("--abc=12X", "abc", &value));
+ EXPECT_EQ(123, value);
+}
+
+// Tests that ParseInt32Flag() parses the value of the flag and
+// returns true when the flag represents a valid decimal integer in
+// the range of an Int32.
+TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue)
+{
+ Int32 value = 123;
+ EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=456", "abc", &value));
+ EXPECT_EQ(456, value);
+
+ EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=-789",
+ "abc", &value));
+ EXPECT_EQ(-789, value);
+}
+
+// Tests that Int32FromEnvOrDie() parses the value of the var or
+// returns the correct default.
+// Environment variables are not supported on Windows CE.
+#if !GTEST_OS_WINDOWS_MOBILE
+TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue)
+{
+ EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333));
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123");
+ EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333));
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123");
+ EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333));
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Tests that Int32FromEnvOrDie() aborts with an error message
+// if the variable is not an Int32.
+TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure)
+{
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx");
+ EXPECT_DEATH_IF_SUPPORTED(
+ Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123),
+ ".*");
+}
+
+// Tests that Int32FromEnvOrDie() aborts with an error message
+// if the variable cannot be represnted by an Int32.
+TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow)
+{
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234");
+ EXPECT_DEATH_IF_SUPPORTED(
+ Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123),
+ ".*");
+}
+
+// Tests that ShouldRunTestOnShard() selects all tests
+// where there is 1 shard.
+TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard)
+{
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4));
+}
+
+class ShouldShardTest : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ index_var_ = GTEST_FLAG_PREFIX_UPPER_ "INDEX";
+ total_var_ = GTEST_FLAG_PREFIX_UPPER_ "TOTAL";
+ }
+
+ virtual void TearDown() {
+ SetEnv(index_var_, "");
+ SetEnv(total_var_, "");
+ }
+
+ const char* index_var_;
+ const char* total_var_;
+};
+
+// Tests that sharding is disabled if neither of the environment variables
+// are set.
+TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet)
+{
+ SetEnv(index_var_, "");
+ SetEnv(total_var_, "");
+
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+}
+
+// Tests that sharding is not enabled if total_shards == 1.
+TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne)
+{
+ SetEnv(index_var_, "0");
+ SetEnv(total_var_, "1");
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+}
+
+// Tests that sharding is enabled if total_shards > 1 and
+// we are not in a death test subprocess.
+// Environment variables are not supported on Windows CE.
+#if !GTEST_OS_WINDOWS_MOBILE
+TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid)
+{
+ SetEnv(index_var_, "4");
+ SetEnv(total_var_, "22");
+ EXPECT_TRUE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+
+ SetEnv(index_var_, "8");
+ SetEnv(total_var_, "9");
+ EXPECT_TRUE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+
+ SetEnv(index_var_, "0");
+ SetEnv(total_var_, "9");
+ EXPECT_TRUE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Tests that we exit in error if the sharding values are not valid.
+
+typedef ShouldShardTest ShouldShardDeathTest;
+
+TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid)
+{
+ SetEnv(index_var_, "4");
+ SetEnv(total_var_, "4");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+
+ SetEnv(index_var_, "4");
+ SetEnv(total_var_, "-2");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+
+ SetEnv(index_var_, "5");
+ SetEnv(total_var_, "");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+
+ SetEnv(index_var_, "");
+ SetEnv(total_var_, "5");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+}
+
+// Tests that ShouldRunTestOnShard is a partition when 5
+// shards are used.
+TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards)
+{
+ // Choose an arbitrary number of tests and shards.
+ const int num_tests = 17;
+ const int num_shards = 5;
+
+ // Check partitioning: each test should be on exactly 1 shard.
+ for (int test_id = 0; test_id < num_tests; test_id++) {
+ int prev_selected_shard_index = -1;
+ for (int shard_index = 0; shard_index < num_shards; shard_index++) {
+ if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) {
+ if (prev_selected_shard_index < 0) {
+ prev_selected_shard_index = shard_index;
+ } else {
+ ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and "
+ << shard_index << " are both selected to run test " << test_id;
+ }
+ }
+ }
+ }
+
+ // Check balance: This is not required by the sharding protocol, but is a
+ // desirable property for performance.
+ for (int shard_index = 0; shard_index < num_shards; shard_index++) {
+ int num_tests_on_shard = 0;
+ for (int test_id = 0; test_id < num_tests; test_id++) {
+ num_tests_on_shard +=
+ ShouldRunTestOnShard(num_shards, shard_index, test_id);
+ }
+ EXPECT_GE(num_tests_on_shard, num_tests / num_shards);
+ }
+}
+
+// For the same reason we are not explicitly testing everything in the
+// Test class, there are no separate tests for the following classes
+// (except for some trivial cases):
+//
+// TestCase, UnitTest, UnitTestResultPrinter.
+//
+// Similarly, there are no separate tests for the following macros:
+//
+// TEST, TEST_F, RUN_ALL_TESTS
+
+TEST(UnitTestTest, CanGetOriginalWorkingDir)
+{
+ ASSERT_TRUE(UnitTest::GetInstance()->original_working_dir() != NULL);
+ EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), "");
+}
+
+TEST(UnitTestTest, ReturnsPlausibleTimestamp)
+{
+ EXPECT_LT(0, UnitTest::GetInstance()->start_timestamp());
+ EXPECT_LE(UnitTest::GetInstance()->start_timestamp(), GetTimeInMillis());
+}
+
+// When a property using a reserved key is supplied to this function, it
+// tests that a non-fatal failure is added, a fatal failure is not added,
+// and that the property is not recorded.
+void ExpectNonFatalFailureRecordingPropertyWithReservedKey(
+ const TestResult& test_result, const char* key)
+{
+ EXPECT_NONFATAL_FAILURE(Test::RecordProperty(key, "1"), "Reserved key");
+ ASSERT_EQ(0, test_result.test_property_count()) << "Property for key '" << key
+ << "' recorded unexpectedly.";
+}
+
+void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ const char* key)
+{
+ const TestInfo* test_info = UnitTest::GetInstance()->current_test_info();
+ ASSERT_TRUE(test_info != NULL);
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey(*test_info->result(),
+ key);
+}
+
+void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ const char* key)
+{
+ const TestCase* test_case = UnitTest::GetInstance()->current_test_case();
+ ASSERT_TRUE(test_case != NULL);
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey(
+ test_case->ad_hoc_test_result(), key);
+}
+
+void ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ const char* key)
+{
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey(
+ UnitTest::GetInstance()->ad_hoc_test_result(), key);
+}
+
+// Tests that property recording functions in UnitTest outside of tests
+// functions correcly. Creating a separate instance of UnitTest ensures it
+// is in a state similar to the UnitTest's singleton's between tests.
+class UnitTestRecordPropertyTest :
+ public testing::internal::UnitTestRecordPropertyTestHelper
+{
+ public:
+ static void SetUpTestCase() {
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ "disabled");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ "errors");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ "failures");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ "name");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ "tests");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase(
+ "time");
+
+ Test::RecordProperty("test_case_key_1", "1");
+ const TestCase* test_case = UnitTest::GetInstance()->current_test_case();
+ ASSERT_TRUE(test_case != NULL);
+
+ ASSERT_EQ(1, test_case->ad_hoc_test_result().test_property_count());
+ EXPECT_STREQ("test_case_key_1",
+ test_case->ad_hoc_test_result().GetTestProperty(0).key());
+ EXPECT_STREQ("1",
+ test_case->ad_hoc_test_result().GetTestProperty(0).value());
+ }
+};
+
+// Tests TestResult has the expected property when added.
+TEST_F(UnitTestRecordPropertyTest, OnePropertyFoundWhenAdded)
+{
+ UnitTestRecordProperty("key_1", "1");
+
+ ASSERT_EQ(1, unit_test_.ad_hoc_test_result().test_property_count());
+
+ EXPECT_STREQ("key_1",
+ unit_test_.ad_hoc_test_result().GetTestProperty(0).key());
+ EXPECT_STREQ("1",
+ unit_test_.ad_hoc_test_result().GetTestProperty(0).value());
+}
+
+// Tests TestResult has multiple properties when added.
+TEST_F(UnitTestRecordPropertyTest, MultiplePropertiesFoundWhenAdded)
+{
+ UnitTestRecordProperty("key_1", "1");
+ UnitTestRecordProperty("key_2", "2");
+
+ ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count());
+
+ EXPECT_STREQ("key_1",
+ unit_test_.ad_hoc_test_result().GetTestProperty(0).key());
+ EXPECT_STREQ("1", unit_test_.ad_hoc_test_result().GetTestProperty(0).value());
+
+ EXPECT_STREQ("key_2",
+ unit_test_.ad_hoc_test_result().GetTestProperty(1).key());
+ EXPECT_STREQ("2", unit_test_.ad_hoc_test_result().GetTestProperty(1).value());
+}
+
+// Tests TestResult::RecordProperty() overrides values for duplicate keys.
+TEST_F(UnitTestRecordPropertyTest, OverridesValuesForDuplicateKeys)
+{
+ UnitTestRecordProperty("key_1", "1");
+ UnitTestRecordProperty("key_2", "2");
+ UnitTestRecordProperty("key_1", "12");
+ UnitTestRecordProperty("key_2", "22");
+
+ ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count());
+
+ EXPECT_STREQ("key_1",
+ unit_test_.ad_hoc_test_result().GetTestProperty(0).key());
+ EXPECT_STREQ("12",
+ unit_test_.ad_hoc_test_result().GetTestProperty(0).value());
+
+ EXPECT_STREQ("key_2",
+ unit_test_.ad_hoc_test_result().GetTestProperty(1).key());
+ EXPECT_STREQ("22",
+ unit_test_.ad_hoc_test_result().GetTestProperty(1).value());
+}
+
+TEST_F(UnitTestRecordPropertyTest,
+ AddFailureInsideTestsWhenUsingTestCaseReservedKeys)
+{
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ "name");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ "value_param");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ "type_param");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ "status");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ "time");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest(
+ "classname");
+}
+
+TEST_F(UnitTestRecordPropertyTest,
+ AddRecordWithReservedKeysGeneratesCorrectPropertyList)
+{
+ EXPECT_NONFATAL_FAILURE(
+ Test::RecordProperty("name", "1"),
+ "'classname', 'name', 'status', 'time', 'type_param', and 'value_param'"
+ " are reserved");
+}
+
+class UnitTestRecordPropertyTestEnvironment : public Environment
+{
+ public:
+ virtual void TearDown() {
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "tests");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "failures");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "disabled");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "errors");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "name");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "timestamp");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "time");
+ ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase(
+ "random_seed");
+ }
+};
+
+// This will test property recording outside of any test or test case.
+static Environment* record_property_env =
+ AddGlobalTestEnvironment(new UnitTestRecordPropertyTestEnvironment);
+
+// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
+// of various arities. They do not attempt to be exhaustive. Rather,
+// view them as smoke tests that can be easily reviewed and verified.
+// A more complete set of tests for predicate assertions can be found
+// in gtest_pred_impl_unittest.cc.
+
+// First, some predicates and predicate-formatters needed by the tests.
+
+// Returns true iff the argument is an even number.
+bool IsEven(int n)
+{
+ return (n % 2) == 0;
+}
+
+// A functor that returns true iff the argument is an even number.
+struct IsEvenFunctor {
+ bool operator()(int n) { return IsEven(n); }
+};
+
+// A predicate-formatter function that asserts the argument is an even
+// number.
+AssertionResult AssertIsEven(const char* expr, int n)
+{
+ if (IsEven(n)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << expr << " evaluates to " << n << ", which is not even.";
+ return AssertionFailure(msg);
+}
+
+// A predicate function that returns AssertionResult for use in
+// EXPECT/ASSERT_TRUE/FALSE.
+AssertionResult ResultIsEven(int n)
+{
+ if (IsEven(n))
+ return AssertionSuccess() << n << " is even";
+ else
+ return AssertionFailure() << n << " is odd";
+}
+
+// A predicate function that returns AssertionResult but gives no
+// explanation why it succeeds. Needed for testing that
+// EXPECT/ASSERT_FALSE handles such functions correctly.
+AssertionResult ResultIsEvenNoExplanation(int n)
+{
+ if (IsEven(n))
+ return AssertionSuccess();
+ else
+ return AssertionFailure() << n << " is odd";
+}
+
+// A predicate-formatter functor that asserts the argument is an even
+// number.
+struct AssertIsEvenFunctor {
+ AssertionResult operator()(const char* expr, int n) {
+ return AssertIsEven(expr, n);
+ }
+};
+
+// Returns true iff the sum of the arguments is an even number.
+bool SumIsEven2(int n1, int n2)
+{
+ return IsEven(n1 + n2);
+}
+
+// A functor that returns true iff the sum of the arguments is an even
+// number.
+struct SumIsEven3Functor {
+ bool operator()(int n1, int n2, int n3) {
+ return IsEven(n1 + n2 + n3);
+ }
+};
+
+// A predicate-formatter function that asserts the sum of the
+// arguments is an even number.
+AssertionResult AssertSumIsEven4(
+ const char* e1, const char* e2, const char* e3, const char* e4,
+ int n1, int n2, int n3, int n4)
+{
+ const int sum = n1 + n2 + n3 + n4;
+ if (IsEven(sum)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << e1 << " + " << e2 << " + " << e3 << " + " << e4
+ << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4
+ << ") evaluates to " << sum << ", which is not even.";
+ return AssertionFailure(msg);
+}
+
+// A predicate-formatter functor that asserts the sum of the arguments
+// is an even number.
+struct AssertSumIsEven5Functor {
+ AssertionResult operator()(
+ const char* e1, const char* e2, const char* e3, const char* e4,
+ const char* e5, int n1, int n2, int n3, int n4, int n5) {
+ const int sum = n1 + n2 + n3 + n4 + n5;
+ if (IsEven(sum)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5
+ << " ("
+ << n1 << " + " << n2 << " + " << n3 << " + " << n4 << " + " << n5
+ << ") evaluates to " << sum << ", which is not even.";
+ return AssertionFailure(msg);
+ }
+};
+
+
+// Tests unary predicate assertions.
+
+// Tests unary predicate assertions that don't use a custom formatter.
+TEST(Pred1Test, WithoutFormat)
+{
+ // Success cases.
+ EXPECT_PRED1(IsEvenFunctor(), 2) << "This failure is UNEXPECTED!";
+ ASSERT_PRED1(IsEven, 4);
+
+ // Failure cases.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(IsEven, 5) << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_FATAL_FAILURE(ASSERT_PRED1(IsEvenFunctor(), 5),
+ "evaluates to false");
+}
+
+// Tests unary predicate assertions that use a custom formatter.
+TEST(Pred1Test, WithFormat)
+{
+ // Success cases.
+ EXPECT_PRED_FORMAT1(AssertIsEven, 2);
+ ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), 4)
+ << "This failure is UNEXPECTED!";
+
+ // Failure cases.
+ const int n = 5;
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT1(AssertIsEvenFunctor(), n),
+ "n evaluates to 5, which is not even.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(AssertIsEven, 5) << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+// Tests that unary predicate assertions evaluates their arguments
+// exactly once.
+TEST(Pred1Test, SingleEvaluationOnFailure)
+{
+ // A success case.
+ static int n = 0;
+ EXPECT_PRED1(IsEven, n++);
+ EXPECT_EQ(1, n) << "The argument is not evaluated exactly once.";
+
+ // A failure case.
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), n++)
+ << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_EQ(2, n) << "The argument is not evaluated exactly once.";
+}
+
+
+// Tests predicate assertions whose arity is >= 2.
+
+// Tests predicate assertions that don't use a custom formatter.
+TEST(PredTest, WithoutFormat)
+{
+ // Success cases.
+ ASSERT_PRED2(SumIsEven2, 2, 4) << "This failure is UNEXPECTED!";
+ EXPECT_PRED3(SumIsEven3Functor(), 4, 6, 8);
+
+ // Failure cases.
+ const int n1 = 1;
+ const int n2 = 2;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(SumIsEven2, n1, n2) << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(SumIsEven3Functor(), 1, 2, 4);
+ }, "evaluates to false");
+}
+
+// Tests predicate assertions that use a custom formatter.
+TEST(PredTest, WithFormat)
+{
+ // Success cases.
+ ASSERT_PRED_FORMAT4(AssertSumIsEven4, 4, 6, 8, 10) <<
+ "This failure is UNEXPECTED!";
+ EXPECT_PRED_FORMAT5(AssertSumIsEven5Functor(), 2, 4, 6, 8, 10);
+
+ // Failure cases.
+ const int n1 = 1;
+ const int n2 = 2;
+ const int n3 = 4;
+ const int n4 = 6;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(AssertSumIsEven4, n1, n2, n3, n4);
+ }, "evaluates to 13, which is not even.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), 1, 2, 4, 6, 8)
+ << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+// Tests that predicate assertions evaluates their arguments
+// exactly once.
+TEST(PredTest, SingleEvaluationOnFailure)
+{
+ // A success case.
+ int n1 = 0;
+ int n2 = 0;
+ EXPECT_PRED2(SumIsEven2, n1++, n2++);
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+
+ // Another success case.
+ n1 = n2 = 0;
+ int n3 = 0;
+ int n4 = 0;
+ int n5 = 0;
+ ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(),
+ n1++, n2++, n3++, n4++, n5++)
+ << "This failure is UNEXPECTED!";
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+ EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once.";
+ EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once.";
+ EXPECT_EQ(1, n5) << "Argument 5 is not evaluated exactly once.";
+
+ // A failure case.
+ n1 = n2 = n3 = 0;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(SumIsEven3Functor(), ++n1, n2++, n3++)
+ << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+ EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once.";
+
+ // Another failure case.
+ n1 = n2 = n3 = n4 = 0;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(AssertSumIsEven4, ++n1, n2++, n3++, n4++);
+ }, "evaluates to 1, which is not even.");
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+ EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once.";
+ EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once.";
+}
+
+
+// Some helper functions for testing using overloaded/template
+// functions with ASSERT_PREDn and EXPECT_PREDn.
+
+bool IsPositive(double x)
+{
+ return x > 0;
+}
+
+template <typename T>
+bool IsNegative(T x)
+{
+ return x < 0;
+}
+
+template <typename T1, typename T2>
+bool GreaterThan(T1 x1, T2 x2)
+{
+ return x1 > x2;
+}
+
+// Tests that overloaded functions can be used in *_PRED* as long as
+// their types are explicitly specified.
+TEST(PredicateAssertionTest, AcceptsOverloadedFunction)
+{
+ // C++Builder requires C-style casts rather than static_cast.
+ EXPECT_PRED1((bool (*)(int))(IsPositive), 5); // NOLINT
+ ASSERT_PRED1((bool (*)(double))(IsPositive), 6.0); // NOLINT
+}
+
+// Tests that template functions can be used in *_PRED* as long as
+// their types are explicitly specified.
+TEST(PredicateAssertionTest, AcceptsTemplateFunction)
+{
+ EXPECT_PRED1(IsNegative<int>, -5);
+ // Makes sure that we can handle templates with more than one
+ // parameter.
+ ASSERT_PRED2((GreaterThan<int, int>), 5, 0);
+}
+
+
+// Some helper functions for testing using overloaded/template
+// functions with ASSERT_PRED_FORMATn and EXPECT_PRED_FORMATn.
+
+AssertionResult IsPositiveFormat(const char* /* expr */, int n)
+{
+ return n > 0 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+AssertionResult IsPositiveFormat(const char* /* expr */, double x)
+{
+ return x > 0 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+template <typename T>
+AssertionResult IsNegativeFormat(const char* /* expr */, T x)
+{
+ return x < 0 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+template <typename T1, typename T2>
+AssertionResult EqualsFormat(const char* /* expr1 */, const char* /* expr2 */,
+ const T1& x1, const T2& x2)
+{
+ return x1 == x2 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+// Tests that overloaded functions can be used in *_PRED_FORMAT*
+// without explicitly specifying their types.
+TEST(PredicateFormatAssertionTest, AcceptsOverloadedFunction)
+{
+ EXPECT_PRED_FORMAT1(IsPositiveFormat, 5);
+ ASSERT_PRED_FORMAT1(IsPositiveFormat, 6.0);
+}
+
+// Tests that template functions can be used in *_PRED_FORMAT* without
+// explicitly specifying their types.
+TEST(PredicateFormatAssertionTest, AcceptsTemplateFunction)
+{
+ EXPECT_PRED_FORMAT1(IsNegativeFormat, -5);
+ ASSERT_PRED_FORMAT2(EqualsFormat, 3, 3);
+}
+
+
+// Tests string assertions.
+
+// Tests ASSERT_STREQ with non-NULL arguments.
+TEST(StringAssertionTest, ASSERT_STREQ)
+{
+ const char* const p1 = "good";
+ ASSERT_STREQ(p1, p1);
+
+ // Let p2 have the same content as p1, but be at a different address.
+ const char p2[] = "good";
+ ASSERT_STREQ(p1, p2);
+
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ("bad", "good"),
+ "Expected: \"bad\"");
+}
+
+// Tests ASSERT_STREQ with NULL arguments.
+TEST(StringAssertionTest, ASSERT_STREQ_Null)
+{
+ ASSERT_STREQ(static_cast<const char*>(NULL), NULL);
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ(NULL, "non-null"),
+ "non-null");
+}
+
+// Tests ASSERT_STREQ with NULL arguments.
+TEST(StringAssertionTest, ASSERT_STREQ_Null2)
+{
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ("non-null", NULL),
+ "non-null");
+}
+
+// Tests ASSERT_STRNE.
+TEST(StringAssertionTest, ASSERT_STRNE)
+{
+ ASSERT_STRNE("hi", "Hi");
+ ASSERT_STRNE("Hi", NULL);
+ ASSERT_STRNE(NULL, "Hi");
+ ASSERT_STRNE("", NULL);
+ ASSERT_STRNE(NULL, "");
+ ASSERT_STRNE("", "Hi");
+ ASSERT_STRNE("Hi", "");
+ EXPECT_FATAL_FAILURE(ASSERT_STRNE("Hi", "Hi"),
+ "\"Hi\" vs \"Hi\"");
+}
+
+// Tests ASSERT_STRCASEEQ.
+TEST(StringAssertionTest, ASSERT_STRCASEEQ)
+{
+ ASSERT_STRCASEEQ("hi", "Hi");
+ ASSERT_STRCASEEQ(static_cast<const char*>(NULL), NULL);
+
+ ASSERT_STRCASEEQ("", "");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("Hi", "hi2"),
+ "(ignoring case)");
+}
+
+// Tests ASSERT_STRCASENE.
+TEST(StringAssertionTest, ASSERT_STRCASENE)
+{
+ ASSERT_STRCASENE("hi1", "Hi2");
+ ASSERT_STRCASENE("Hi", NULL);
+ ASSERT_STRCASENE(NULL, "Hi");
+ ASSERT_STRCASENE("", NULL);
+ ASSERT_STRCASENE(NULL, "");
+ ASSERT_STRCASENE("", "Hi");
+ ASSERT_STRCASENE("Hi", "");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("Hi", "hi"),
+ "(ignoring case)");
+}
+
+// Tests *_STREQ on wide strings.
+TEST(StringAssertionTest, STREQ_Wide)
+{
+ // NULL strings.
+ ASSERT_STREQ(static_cast<const wchar_t*>(NULL), NULL);
+
+ // Empty strings.
+ ASSERT_STREQ(L"", L"");
+
+ // Non-null vs NULL.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"non-null", NULL),
+ "non-null");
+
+ // Equal strings.
+ EXPECT_STREQ(L"Hi", L"Hi");
+
+ // Unequal strings.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc", L"Abc"),
+ "Abc");
+
+ // Strings containing wide characters.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc\x8119", L"abc\x8120"),
+ "abc");
+
+ // The streaming variation.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_STREQ(L"abc\x8119", L"abc\x8121") << "Expected failure";
+ }, "Expected failure");
+}
+
+// Tests *_STRNE on wide strings.
+TEST(StringAssertionTest, STRNE_Wide)
+{
+ // NULL strings.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_STRNE(static_cast<const wchar_t*>(NULL), NULL);
+ }, "");
+
+ // Empty strings.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"", L""),
+ "L\"\"");
+
+ // Non-null vs NULL.
+ ASSERT_STRNE(L"non-null", NULL);
+
+ // Equal strings.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"Hi", L"Hi"),
+ "L\"Hi\"");
+
+ // Unequal strings.
+ EXPECT_STRNE(L"abc", L"Abc");
+
+ // Strings containing wide characters.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"abc\x8119", L"abc\x8119"),
+ "abc");
+
+ // The streaming variation.
+ ASSERT_STRNE(L"abc\x8119", L"abc\x8120") << "This shouldn't happen";
+}
+
+// Tests for ::testing::IsSubstring().
+
+// Tests that IsSubstring() returns the correct result when the input
+// argument type is const char*.
+TEST(IsSubstringTest, ReturnsCorrectResultForCString)
+{
+ EXPECT_FALSE(IsSubstring("", "", NULL, "a"));
+ EXPECT_FALSE(IsSubstring("", "", "b", NULL));
+ EXPECT_FALSE(IsSubstring("", "", "needle", "haystack"));
+
+ EXPECT_TRUE(IsSubstring("", "", static_cast<const char*>(NULL), NULL));
+ EXPECT_TRUE(IsSubstring("", "", "needle", "two needles"));
+}
+
+// Tests that IsSubstring() returns the correct result when the input
+// argument type is const wchar_t*.
+TEST(IsSubstringTest, ReturnsCorrectResultForWideCString)
+{
+ EXPECT_FALSE(IsSubstring("", "", kNull, L"a"));
+ EXPECT_FALSE(IsSubstring("", "", L"b", kNull));
+ EXPECT_FALSE(IsSubstring("", "", L"needle", L"haystack"));
+
+ EXPECT_TRUE(IsSubstring("", "", static_cast<const wchar_t*>(NULL), NULL));
+ EXPECT_TRUE(IsSubstring("", "", L"needle", L"two needles"));
+}
+
+// Tests that IsSubstring() generates the correct message when the input
+// argument type is const char*.
+TEST(IsSubstringTest, GeneratesCorrectMessageForCString)
+{
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: \"needle\"\n"
+ "Expected: a substring of haystack_expr\n"
+ "Which is: \"haystack\"",
+ IsSubstring("needle_expr", "haystack_expr",
+ "needle", "haystack").failure_message());
+}
+
+// Tests that IsSubstring returns the correct result when the input
+// argument type is ::std::string.
+TEST(IsSubstringTest, ReturnsCorrectResultsForStdString)
+{
+ EXPECT_TRUE(IsSubstring("", "", std::string("hello"), "ahellob"));
+ EXPECT_FALSE(IsSubstring("", "", "hello", std::string("world")));
+}
+
+#if GTEST_HAS_STD_WSTRING
+// Tests that IsSubstring returns the correct result when the input
+// argument type is ::std::wstring.
+TEST(IsSubstringTest, ReturnsCorrectResultForStdWstring)
+{
+ EXPECT_TRUE(IsSubstring("", "", ::std::wstring(L"needle"), L"two needles"));
+ EXPECT_FALSE(IsSubstring("", "", L"needle", ::std::wstring(L"haystack")));
+}
+
+// Tests that IsSubstring() generates the correct message when the input
+// argument type is ::std::wstring.
+TEST(IsSubstringTest, GeneratesCorrectMessageForWstring)
+{
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: L\"needle\"\n"
+ "Expected: a substring of haystack_expr\n"
+ "Which is: L\"haystack\"",
+ IsSubstring(
+ "needle_expr", "haystack_expr",
+ ::std::wstring(L"needle"), L"haystack").failure_message());
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+// Tests for ::testing::IsNotSubstring().
+
+// Tests that IsNotSubstring() returns the correct result when the input
+// argument type is const char*.
+TEST(IsNotSubstringTest, ReturnsCorrectResultForCString)
+{
+ EXPECT_TRUE(IsNotSubstring("", "", "needle", "haystack"));
+ EXPECT_FALSE(IsNotSubstring("", "", "needle", "two needles"));
+}
+
+// Tests that IsNotSubstring() returns the correct result when the input
+// argument type is const wchar_t*.
+TEST(IsNotSubstringTest, ReturnsCorrectResultForWideCString)
+{
+ EXPECT_TRUE(IsNotSubstring("", "", L"needle", L"haystack"));
+ EXPECT_FALSE(IsNotSubstring("", "", L"needle", L"two needles"));
+}
+
+// Tests that IsNotSubstring() generates the correct message when the input
+// argument type is const wchar_t*.
+TEST(IsNotSubstringTest, GeneratesCorrectMessageForWideCString)
+{
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: L\"needle\"\n"
+ "Expected: not a substring of haystack_expr\n"
+ "Which is: L\"two needles\"",
+ IsNotSubstring(
+ "needle_expr", "haystack_expr",
+ L"needle", L"two needles").failure_message());
+}
+
+// Tests that IsNotSubstring returns the correct result when the input
+// argument type is ::std::string.
+TEST(IsNotSubstringTest, ReturnsCorrectResultsForStdString)
+{
+ EXPECT_FALSE(IsNotSubstring("", "", std::string("hello"), "ahellob"));
+ EXPECT_TRUE(IsNotSubstring("", "", "hello", std::string("world")));
+}
+
+// Tests that IsNotSubstring() generates the correct message when the input
+// argument type is ::std::string.
+TEST(IsNotSubstringTest, GeneratesCorrectMessageForStdString)
+{
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: \"needle\"\n"
+ "Expected: not a substring of haystack_expr\n"
+ "Which is: \"two needles\"",
+ IsNotSubstring(
+ "needle_expr", "haystack_expr",
+ ::std::string("needle"), "two needles").failure_message());
+}
+
+#if GTEST_HAS_STD_WSTRING
+
+// Tests that IsNotSubstring returns the correct result when the input
+// argument type is ::std::wstring.
+TEST(IsNotSubstringTest, ReturnsCorrectResultForStdWstring)
+{
+ EXPECT_FALSE(
+ IsNotSubstring("", "", ::std::wstring(L"needle"), L"two needles"));
+ EXPECT_TRUE(IsNotSubstring("", "", L"needle", ::std::wstring(L"haystack")));
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+// Tests floating-point assertions.
+
+template <typename RawType>
+class FloatingPointTest : public Test
+{
+ protected:
+ // Pre-calculated numbers to be used by the tests.
+ struct TestValues {
+ RawType close_to_positive_zero;
+ RawType close_to_negative_zero;
+ RawType further_from_negative_zero;
+
+ RawType close_to_one;
+ RawType further_from_one;
+
+ RawType infinity;
+ RawType close_to_infinity;
+ RawType further_from_infinity;
+
+ RawType nan1;
+ RawType nan2;
+ };
+
+ typedef typename testing::internal::FloatingPoint<RawType> Floating;
+ typedef typename Floating::Bits Bits;
+
+ virtual void SetUp() {
+ const size_t max_ulps = Floating::kMaxUlps;
+
+ // The bits that represent 0.0.
+ const Bits zero_bits = Floating(0).bits();
+
+ // Makes some numbers close to 0.0.
+ values_.close_to_positive_zero = Floating::ReinterpretBits(
+ zero_bits + max_ulps/2);
+ values_.close_to_negative_zero = -Floating::ReinterpretBits(
+ zero_bits + max_ulps - max_ulps/2);
+ values_.further_from_negative_zero = -Floating::ReinterpretBits(
+ zero_bits + max_ulps + 1 - max_ulps/2);
+
+ // The bits that represent 1.0.
+ const Bits one_bits = Floating(1).bits();
+
+ // Makes some numbers close to 1.0.
+ values_.close_to_one = Floating::ReinterpretBits(one_bits + max_ulps);
+ values_.further_from_one = Floating::ReinterpretBits(
+ one_bits + max_ulps + 1);
+
+ // +infinity.
+ values_.infinity = Floating::Infinity();
+
+ // The bits that represent +infinity.
+ const Bits infinity_bits = Floating(values_.infinity).bits();
+
+ // Makes some numbers close to infinity.
+ values_.close_to_infinity = Floating::ReinterpretBits(
+ infinity_bits - max_ulps);
+ values_.further_from_infinity = Floating::ReinterpretBits(
+ infinity_bits - max_ulps - 1);
+
+ // Makes some NAN's. Sets the most significant bit of the fraction so that
+ // our NaN's are quiet; trying to process a signaling NaN would raise an
+ // exception if our environment enables floating point exceptions.
+ values_.nan1 = Floating::ReinterpretBits(Floating::kExponentBitMask
+ | (static_cast<Bits>(1) << (Floating::kFractionBitCount - 1)) | 1);
+ values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask
+ | (static_cast<Bits>(1) << (Floating::kFractionBitCount - 1)) | 200);
+ }
+
+ void TestSize() {
+ EXPECT_EQ(sizeof(RawType), sizeof(Bits));
+ }
+
+ static TestValues values_;
+};
+
+template <typename RawType>
+typename FloatingPointTest<RawType>::TestValues
+FloatingPointTest<RawType>::values_;
+
+// Instantiates FloatingPointTest for testing *_FLOAT_EQ.
+typedef FloatingPointTest<float> FloatTest;
+
+// Tests that the size of Float::Bits matches the size of float.
+TEST_F(FloatTest, Size)
+{
+ TestSize();
+}
+
+// Tests comparing with +0 and -0.
+TEST_F(FloatTest, Zeros)
+{
+ EXPECT_FLOAT_EQ(0.0, -0.0);
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(-0.0, 1.0),
+ "1.0");
+ EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.5),
+ "1.5");
+}
+
+// Tests comparing numbers close to 0.
+//
+// This ensures that *_FLOAT_EQ handles the sign correctly and no
+// overflow occurs when comparing numbers whose absolute value is very
+// small.
+TEST_F(FloatTest, AlmostZeros)
+{
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const FloatTest::TestValues& v = this->values_;
+
+ EXPECT_FLOAT_EQ(0.0, v.close_to_positive_zero);
+ EXPECT_FLOAT_EQ(-0.0, v.close_to_negative_zero);
+ EXPECT_FLOAT_EQ(v.close_to_positive_zero, v.close_to_negative_zero);
+
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_FLOAT_EQ(v.close_to_positive_zero,
+ v.further_from_negative_zero);
+ }, "v.further_from_negative_zero");
+}
+
+// Tests comparing numbers close to each other.
+TEST_F(FloatTest, SmallDiff)
+{
+ EXPECT_FLOAT_EQ(1.0, values_.close_to_one);
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, values_.further_from_one),
+ "values_.further_from_one");
+}
+
+// Tests comparing numbers far apart.
+TEST_F(FloatTest, LargeDiff)
+{
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(2.5, 3.0),
+ "3.0");
+}
+
+// Tests comparing with infinity.
+//
+// This ensures that no overflow occurs when comparing numbers whose
+// absolute value is very large.
+TEST_F(FloatTest, Infinity)
+{
+ EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity);
+ EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity);
+#if !GTEST_OS_SYMBIAN
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity),
+ "-values_.infinity");
+
+ // This is interesting as the representations of infinity and nan1
+ // are only 1 DLP apart.
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, values_.nan1),
+ "values_.nan1");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that comparing with NAN always returns false.
+TEST_F(FloatTest, NaN)
+{
+#if !GTEST_OS_SYMBIAN
+// Nokia's STLport crashes if we try to output infinity or NaN.
+
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const FloatTest::TestValues& v = this->values_;
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1),
+ "v.nan1");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2),
+ "v.nan2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1),
+ "v.nan1");
+
+ EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity),
+ "v.infinity");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that *_FLOAT_EQ are reflexive.
+TEST_F(FloatTest, Reflexive)
+{
+ EXPECT_FLOAT_EQ(0.0, 0.0);
+ EXPECT_FLOAT_EQ(1.0, 1.0);
+ ASSERT_FLOAT_EQ(values_.infinity, values_.infinity);
+}
+
+// Tests that *_FLOAT_EQ are commutative.
+TEST_F(FloatTest, Commutative)
+{
+ // We already tested EXPECT_FLOAT_EQ(1.0, values_.close_to_one).
+ EXPECT_FLOAT_EQ(values_.close_to_one, 1.0);
+
+ // We already tested EXPECT_FLOAT_EQ(1.0, values_.further_from_one).
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.further_from_one, 1.0),
+ "1.0");
+}
+
+// Tests EXPECT_NEAR.
+TEST_F(FloatTest, EXPECT_NEAR)
+{
+ EXPECT_NEAR(-1.0f, -1.1f, 0.2f);
+ EXPECT_NEAR(2.0f, 3.0f, 1.0f);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f,1.5f, 0.25f), // NOLINT
+ "The difference between 1.0f and 1.5f is 0.5, "
+ "which exceeds 0.25f");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous line.
+}
+
+// Tests ASSERT_NEAR.
+TEST_F(FloatTest, ASSERT_NEAR)
+{
+ ASSERT_NEAR(-1.0f, -1.1f, 0.2f);
+ ASSERT_NEAR(2.0f, 3.0f, 1.0f);
+ EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0f,1.5f, 0.25f), // NOLINT
+ "The difference between 1.0f and 1.5f is 0.5, "
+ "which exceeds 0.25f");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous line.
+}
+
+// Tests the cases where FloatLE() should succeed.
+TEST_F(FloatTest, FloatLESucceeds)
+{
+ EXPECT_PRED_FORMAT2(FloatLE, 1.0f, 2.0f); // When val1 < val2,
+ ASSERT_PRED_FORMAT2(FloatLE, 1.0f, 1.0f); // val1 == val2,
+
+ // or when val1 is greater than, but almost equals to, val2.
+ EXPECT_PRED_FORMAT2(FloatLE, values_.close_to_positive_zero, 0.0f);
+}
+
+// Tests the cases where FloatLE() should fail.
+TEST_F(FloatTest, FloatLEFails)
+{
+ // When val1 is greater than val2 by a large margin,
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(FloatLE, 2.0f, 1.0f),
+ "(2.0f) <= (1.0f)");
+
+ // or by a small yet non-negligible margin,
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(FloatLE, values_.further_from_one, 1.0f);
+ }, "(values_.further_from_one) <= (1.0f)");
+
+#if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ // C++Builder gives bad results for ordered comparisons involving NaNs
+ // due to compiler bugs.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(FloatLE, values_.nan1, values_.infinity);
+ }, "(values_.nan1) <= (values_.infinity)");
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(FloatLE, -values_.infinity, values_.nan1);
+ }, "(-values_.infinity) <= (values_.nan1)");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(FloatLE, values_.nan1, values_.nan1);
+ }, "(values_.nan1) <= (values_.nan1)");
+#endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+}
+
+// Instantiates FloatingPointTest for testing *_DOUBLE_EQ.
+typedef FloatingPointTest<double> DoubleTest;
+
+// Tests that the size of Double::Bits matches the size of double.
+TEST_F(DoubleTest, Size)
+{
+ TestSize();
+}
+
+// Tests comparing with +0 and -0.
+TEST_F(DoubleTest, Zeros)
+{
+ EXPECT_DOUBLE_EQ(0.0, -0.0);
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(-0.0, 1.0),
+ "1.0");
+ EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(0.0, 1.0),
+ "1.0");
+}
+
+// Tests comparing numbers close to 0.
+//
+// This ensures that *_DOUBLE_EQ handles the sign correctly and no
+// overflow occurs when comparing numbers whose absolute value is very
+// small.
+TEST_F(DoubleTest, AlmostZeros)
+{
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const DoubleTest::TestValues& v = this->values_;
+
+ EXPECT_DOUBLE_EQ(0.0, v.close_to_positive_zero);
+ EXPECT_DOUBLE_EQ(-0.0, v.close_to_negative_zero);
+ EXPECT_DOUBLE_EQ(v.close_to_positive_zero, v.close_to_negative_zero);
+
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_DOUBLE_EQ(v.close_to_positive_zero,
+ v.further_from_negative_zero);
+ }, "v.further_from_negative_zero");
+}
+
+// Tests comparing numbers close to each other.
+TEST_F(DoubleTest, SmallDiff)
+{
+ EXPECT_DOUBLE_EQ(1.0, values_.close_to_one);
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, values_.further_from_one),
+ "values_.further_from_one");
+}
+
+// Tests comparing numbers far apart.
+TEST_F(DoubleTest, LargeDiff)
+{
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(2.0, 3.0),
+ "3.0");
+}
+
+// Tests comparing with infinity.
+//
+// This ensures that no overflow occurs when comparing numbers whose
+// absolute value is very large.
+TEST_F(DoubleTest, Infinity)
+{
+ EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity);
+ EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity);
+#if !GTEST_OS_SYMBIAN
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity),
+ "-values_.infinity");
+
+ // This is interesting as the representations of infinity_ and nan1_
+ // are only 1 DLP apart.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, values_.nan1),
+ "values_.nan1");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that comparing with NAN always returns false.
+TEST_F(DoubleTest, NaN)
+{
+#if !GTEST_OS_SYMBIAN
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const DoubleTest::TestValues& v = this->values_;
+
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1),
+ "v.nan1");
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1");
+ EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity),
+ "v.infinity");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that *_DOUBLE_EQ are reflexive.
+TEST_F(DoubleTest, Reflexive)
+{
+ EXPECT_DOUBLE_EQ(0.0, 0.0);
+ EXPECT_DOUBLE_EQ(1.0, 1.0);
+#if !GTEST_OS_SYMBIAN
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ ASSERT_DOUBLE_EQ(values_.infinity, values_.infinity);
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that *_DOUBLE_EQ are commutative.
+TEST_F(DoubleTest, Commutative)
+{
+ // We already tested EXPECT_DOUBLE_EQ(1.0, values_.close_to_one).
+ EXPECT_DOUBLE_EQ(values_.close_to_one, 1.0);
+
+ // We already tested EXPECT_DOUBLE_EQ(1.0, values_.further_from_one).
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.further_from_one, 1.0),
+ "1.0");
+}
+
+// Tests EXPECT_NEAR.
+TEST_F(DoubleTest, EXPECT_NEAR)
+{
+ EXPECT_NEAR(-1.0, -1.1, 0.2);
+ EXPECT_NEAR(2.0, 3.0, 1.0);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT
+ "The difference between 1.0 and 1.5 is 0.5, "
+ "which exceeds 0.25");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous statement.
+}
+
+// Tests ASSERT_NEAR.
+TEST_F(DoubleTest, ASSERT_NEAR)
+{
+ ASSERT_NEAR(-1.0, -1.1, 0.2);
+ ASSERT_NEAR(2.0, 3.0, 1.0);
+ EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0, 1.5, 0.25), // NOLINT
+ "The difference between 1.0 and 1.5 is 0.5, "
+ "which exceeds 0.25");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous statement.
+}
+
+// Tests the cases where DoubleLE() should succeed.
+TEST_F(DoubleTest, DoubleLESucceeds)
+{
+ EXPECT_PRED_FORMAT2(DoubleLE, 1.0, 2.0); // When val1 < val2,
+ ASSERT_PRED_FORMAT2(DoubleLE, 1.0, 1.0); // val1 == val2,
+
+ // or when val1 is greater than, but almost equals to, val2.
+ EXPECT_PRED_FORMAT2(DoubleLE, values_.close_to_positive_zero, 0.0);
+}
+
+// Tests the cases where DoubleLE() should fail.
+TEST_F(DoubleTest, DoubleLEFails)
+{
+ // When val1 is greater than val2 by a large margin,
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(DoubleLE, 2.0, 1.0),
+ "(2.0) <= (1.0)");
+
+ // or by a small yet non-negligible margin,
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(DoubleLE, values_.further_from_one, 1.0);
+ }, "(values_.further_from_one) <= (1.0)");
+
+#if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ // C++Builder gives bad results for ordered comparisons involving NaNs
+ // due to compiler bugs.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.infinity);
+ }, "(values_.nan1) <= (values_.infinity)");
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(DoubleLE, -values_.infinity, values_.nan1);
+ }, " (-values_.infinity) <= (values_.nan1)");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.nan1);
+ }, "(values_.nan1) <= (values_.nan1)");
+#endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+}
+
+
+// Verifies that a test or test case whose name starts with DISABLED_ is
+// not run.
+
+// A test whose name starts with DISABLED_.
+// Should not run.
+TEST(DisabledTest, DISABLED_TestShouldNotRun)
+{
+ FAIL() << "Unexpected failure: Disabled test should not be run.";
+}
+
+// A test whose name does not start with DISABLED_.
+// Should run.
+TEST(DisabledTest, NotDISABLED_TestShouldRun)
+{
+ EXPECT_EQ(1, 1);
+}
+
+// A test case whose name starts with DISABLED_.
+// Should not run.
+TEST(DISABLED_TestCase, TestShouldNotRun)
+{
+ FAIL() << "Unexpected failure: Test in disabled test case should not be run.";
+}
+
+// A test case and test whose names start with DISABLED_.
+// Should not run.
+TEST(DISABLED_TestCase, DISABLED_TestShouldNotRun)
+{
+ FAIL() << "Unexpected failure: Test in disabled test case should not be run.";
+}
+
+// Check that when all tests in a test case are disabled, SetupTestCase() and
+// TearDownTestCase() are not called.
+class DisabledTestsTest : public Test
+{
+ protected:
+ static void SetUpTestCase() {
+ FAIL() << "Unexpected failure: All tests disabled in test case. "
+ "SetupTestCase() should not be called.";
+ }
+
+ static void TearDownTestCase() {
+ FAIL() << "Unexpected failure: All tests disabled in test case. "
+ "TearDownTestCase() should not be called.";
+ }
+};
+
+TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_1)
+{
+ FAIL() << "Unexpected failure: Disabled test should not be run.";
+}
+
+TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2)
+{
+ FAIL() << "Unexpected failure: Disabled test should not be run.";
+}
+
+// Tests that disabled typed tests aren't run.
+
+#if GTEST_HAS_TYPED_TEST
+
+template <typename T>
+class TypedTest : public Test
+{
+};
+
+typedef testing::Types<int, double> NumericTypes;
+TYPED_TEST_CASE(TypedTest, NumericTypes);
+
+TYPED_TEST(TypedTest, DISABLED_ShouldNotRun)
+{
+ FAIL() << "Unexpected failure: Disabled typed test should not run.";
+}
+
+template <typename T>
+class DISABLED_TypedTest : public Test
+{
+};
+
+TYPED_TEST_CASE(DISABLED_TypedTest, NumericTypes);
+
+TYPED_TEST(DISABLED_TypedTest, ShouldNotRun)
+{
+ FAIL() << "Unexpected failure: Disabled typed test should not run.";
+}
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// Tests that disabled type-parameterized tests aren't run.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+template <typename T>
+class TypedTestP : public Test
+{
+};
+
+TYPED_TEST_CASE_P(TypedTestP);
+
+TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun)
+{
+ FAIL() << "Unexpected failure: "
+ << "Disabled type-parameterized test should not run.";
+}
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP, DISABLED_ShouldNotRun);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, TypedTestP, NumericTypes);
+
+template <typename T>
+class DISABLED_TypedTestP : public Test
+{
+};
+
+TYPED_TEST_CASE_P(DISABLED_TypedTestP);
+
+TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun)
+{
+ FAIL() << "Unexpected failure: "
+ << "Disabled type-parameterized test should not run.";
+}
+
+REGISTER_TYPED_TEST_CASE_P(DISABLED_TypedTestP, ShouldNotRun);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, DISABLED_TypedTestP, NumericTypes);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+// Tests that assertion macros evaluate their arguments exactly once.
+
+class SingleEvaluationTest : public Test
+{
+ public: // Must be public and not protected due to a bug in g++ 3.4.2.
+ // This helper function is needed by the FailedASSERT_STREQ test
+ // below. It's public to work around C++Builder's bug with scoping local
+ // classes.
+ static void CompareAndIncrementCharPtrs() {
+ ASSERT_STREQ(p1_++, p2_++);
+ }
+
+ // This helper function is needed by the FailedASSERT_NE test below. It's
+ // public to work around C++Builder's bug with scoping local classes.
+ static void CompareAndIncrementInts() {
+ ASSERT_NE(a_++, b_++);
+ }
+
+ protected:
+ SingleEvaluationTest() {
+ p1_ = s1_;
+ p2_ = s2_;
+ a_ = 0;
+ b_ = 0;
+ }
+
+ static const char* const s1_;
+ static const char* const s2_;
+ static const char* p1_;
+ static const char* p2_;
+
+ static int a_;
+ static int b_;
+};
+
+const char* const SingleEvaluationTest::s1_ = "01234";
+const char* const SingleEvaluationTest::s2_ = "abcde";
+const char* SingleEvaluationTest::p1_;
+const char* SingleEvaluationTest::p2_;
+int SingleEvaluationTest::a_;
+int SingleEvaluationTest::b_;
+
+// Tests that when ASSERT_STREQ fails, it evaluates its arguments
+// exactly once.
+TEST_F(SingleEvaluationTest, FailedASSERT_STREQ)
+{
+ EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementCharPtrs(),
+ "p2_++");
+ EXPECT_EQ(s1_ + 1, p1_);
+ EXPECT_EQ(s2_ + 1, p2_);
+}
+
+// Tests that string assertion arguments are evaluated exactly once.
+TEST_F(SingleEvaluationTest, ASSERT_STR)
+{
+ // successful EXPECT_STRNE
+ EXPECT_STRNE(p1_++, p2_++);
+ EXPECT_EQ(s1_ + 1, p1_);
+ EXPECT_EQ(s2_ + 1, p2_);
+
+ // failed EXPECT_STRCASEEQ
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ(p1_++, p2_++),
+ "ignoring case");
+ EXPECT_EQ(s1_ + 2, p1_);
+ EXPECT_EQ(s2_ + 2, p2_);
+}
+
+// Tests that when ASSERT_NE fails, it evaluates its arguments exactly
+// once.
+TEST_F(SingleEvaluationTest, FailedASSERT_NE)
+{
+ EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementInts(),
+ "(a_++) != (b_++)");
+ EXPECT_EQ(1, a_);
+ EXPECT_EQ(1, b_);
+}
+
+// Tests that assertion arguments are evaluated exactly once.
+TEST_F(SingleEvaluationTest, OtherCases)
+{
+ // successful EXPECT_TRUE
+ EXPECT_TRUE(0 == a_++); // NOLINT
+ EXPECT_EQ(1, a_);
+
+ // failed EXPECT_TRUE
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(-1 == a_++), "-1 == a_++");
+ EXPECT_EQ(2, a_);
+
+ // successful EXPECT_GT
+ EXPECT_GT(a_++, b_++);
+ EXPECT_EQ(3, a_);
+ EXPECT_EQ(1, b_);
+
+ // failed EXPECT_LT
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(a_++, b_++), "(a_++) < (b_++)");
+ EXPECT_EQ(4, a_);
+ EXPECT_EQ(2, b_);
+
+ // successful ASSERT_TRUE
+ ASSERT_TRUE(0 < a_++); // NOLINT
+ EXPECT_EQ(5, a_);
+
+ // successful ASSERT_GT
+ ASSERT_GT(a_++, b_++);
+ EXPECT_EQ(6, a_);
+ EXPECT_EQ(3, b_);
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+void ThrowAnInteger()
+{
+ throw 1;
+}
+
+// Tests that assertion arguments are evaluated exactly once.
+TEST_F(SingleEvaluationTest, ExceptionTests)
+{
+ // successful EXPECT_THROW
+ EXPECT_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ }, int);
+ EXPECT_EQ(1, a_);
+
+ // failed EXPECT_THROW, throws different
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ }, bool), "throws a different type");
+ EXPECT_EQ(2, a_);
+
+ // failed EXPECT_THROW, throws nothing
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing");
+ EXPECT_EQ(3, a_);
+
+ // successful EXPECT_NO_THROW
+ EXPECT_NO_THROW(a_++);
+ EXPECT_EQ(4, a_);
+
+ // failed EXPECT_NO_THROW
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ }), "it throws");
+ EXPECT_EQ(5, a_);
+
+ // successful EXPECT_ANY_THROW
+ EXPECT_ANY_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ });
+ EXPECT_EQ(6, a_);
+
+ // failed EXPECT_ANY_THROW
+ EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't");
+ EXPECT_EQ(7, a_);
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Tests {ASSERT|EXPECT}_NO_FATAL_FAILURE.
+class NoFatalFailureTest : public Test
+{
+ protected:
+ void Succeeds() {}
+ void FailsNonFatal() {
+ ADD_FAILURE() << "some non-fatal failure";
+ }
+ void Fails() {
+ FAIL() << "some fatal failure";
+ }
+
+ void DoAssertNoFatalFailureOnFails() {
+ ASSERT_NO_FATAL_FAILURE(Fails());
+ ADD_FAILURE() << "shold not reach here.";
+ }
+
+ void DoExpectNoFatalFailureOnFails() {
+ EXPECT_NO_FATAL_FAILURE(Fails());
+ ADD_FAILURE() << "other failure";
+ }
+};
+
+TEST_F(NoFatalFailureTest, NoFailure)
+{
+ EXPECT_NO_FATAL_FAILURE(Succeeds());
+ ASSERT_NO_FATAL_FAILURE(Succeeds());
+}
+
+TEST_F(NoFatalFailureTest, NonFatalIsNoFailure)
+{
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_NO_FATAL_FAILURE(FailsNonFatal()),
+ "some non-fatal failure");
+ EXPECT_NONFATAL_FAILURE(
+ ASSERT_NO_FATAL_FAILURE(FailsNonFatal()),
+ "some non-fatal failure");
+}
+
+TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure)
+{
+ TestPartResultArray gtest_failures;
+ {
+ ScopedFakeTestPartResultReporter gtest_reporter(>est_failures);
+ DoAssertNoFatalFailureOnFails();
+ }
+ ASSERT_EQ(2, gtest_failures.size());
+ EXPECT_EQ(TestPartResult::kFatalFailure,
+ gtest_failures.GetTestPartResult(0).type());
+ EXPECT_EQ(TestPartResult::kFatalFailure,
+ gtest_failures.GetTestPartResult(1).type());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure",
+ gtest_failures.GetTestPartResult(0).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does",
+ gtest_failures.GetTestPartResult(1).message());
+}
+
+TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure)
+{
+ TestPartResultArray gtest_failures;
+ {
+ ScopedFakeTestPartResultReporter gtest_reporter(>est_failures);
+ DoExpectNoFatalFailureOnFails();
+ }
+ ASSERT_EQ(3, gtest_failures.size());
+ EXPECT_EQ(TestPartResult::kFatalFailure,
+ gtest_failures.GetTestPartResult(0).type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(1).type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(2).type());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure",
+ gtest_failures.GetTestPartResult(0).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does",
+ gtest_failures.GetTestPartResult(1).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "other failure",
+ gtest_failures.GetTestPartResult(2).message());
+}
+
+TEST_F(NoFatalFailureTest, MessageIsStreamable)
+{
+ TestPartResultArray gtest_failures;
+ {
+ ScopedFakeTestPartResultReporter gtest_reporter(>est_failures);
+ EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message";
+ }
+ ASSERT_EQ(2, gtest_failures.size());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(0).type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(1).type());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo",
+ gtest_failures.GetTestPartResult(0).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "my message",
+ gtest_failures.GetTestPartResult(1).message());
+}
+
+// Tests non-string assertions.
+
+// Tests EqFailure(), used for implementing *EQ* assertions.
+TEST(AssertionTest, EqFailure)
+{
+ const std::string foo_val("5"), bar_val("6");
+ const std::string msg1(
+ EqFailure("foo", "bar", foo_val, bar_val, false)
+ .failure_message());
+ EXPECT_STREQ(
+ "Value of: bar\n"
+ " Actual: 6\n"
+ "Expected: foo\n"
+ "Which is: 5",
+ msg1.c_str());
+
+ const std::string msg2(
+ EqFailure("foo", "6", foo_val, bar_val, false)
+ .failure_message());
+ EXPECT_STREQ(
+ "Value of: 6\n"
+ "Expected: foo\n"
+ "Which is: 5",
+ msg2.c_str());
+
+ const std::string msg3(
+ EqFailure("5", "bar", foo_val, bar_val, false)
+ .failure_message());
+ EXPECT_STREQ(
+ "Value of: bar\n"
+ " Actual: 6\n"
+ "Expected: 5",
+ msg3.c_str());
+
+ const std::string msg4(
+ EqFailure("5", "6", foo_val, bar_val, false).failure_message());
+ EXPECT_STREQ(
+ "Value of: 6\n"
+ "Expected: 5",
+ msg4.c_str());
+
+ const std::string msg5(
+ EqFailure("foo", "bar",
+ std::string("\"x\""), std::string("\"y\""),
+ true).failure_message());
+ EXPECT_STREQ(
+ "Value of: bar\n"
+ " Actual: \"y\"\n"
+ "Expected: foo (ignoring case)\n"
+ "Which is: \"x\"",
+ msg5.c_str());
+}
+
+// Tests AppendUserMessage(), used for implementing the *EQ* macros.
+TEST(AssertionTest, AppendUserMessage)
+{
+ const std::string foo("foo");
+
+ Message msg;
+ EXPECT_STREQ("foo",
+ AppendUserMessage(foo, msg).c_str());
+
+ msg << "bar";
+ EXPECT_STREQ("foo\nbar",
+ AppendUserMessage(foo, msg).c_str());
+}
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+# pragma option push -w-ccc -w-rch
+#endif
+
+// Tests ASSERT_TRUE.
+TEST(AssertionTest, ASSERT_TRUE)
+{
+ ASSERT_TRUE(2 > 1); // NOLINT
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(2 < 1),
+ "2 < 1");
+}
+
+// Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult.
+TEST(AssertionTest, AssertTrueWithAssertionResult)
+{
+ ASSERT_TRUE(ResultIsEven(2));
+#ifndef __BORLANDC__
+ // ICE's in C++Builder.
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)),
+ "Value of: ResultIsEven(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+#endif
+ ASSERT_TRUE(ResultIsEvenNoExplanation(2));
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)),
+ "Value of: ResultIsEvenNoExplanation(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+}
+
+// Tests ASSERT_FALSE.
+TEST(AssertionTest, ASSERT_FALSE)
+{
+ ASSERT_FALSE(2 < 1); // NOLINT
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(2 > 1),
+ "Value of: 2 > 1\n"
+ " Actual: true\n"
+ "Expected: false");
+}
+
+// Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult.
+TEST(AssertionTest, AssertFalseWithAssertionResult)
+{
+ ASSERT_FALSE(ResultIsEven(3));
+#ifndef __BORLANDC__
+ // ICE's in C++Builder.
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)),
+ "Value of: ResultIsEven(2)\n"
+ " Actual: true (2 is even)\n"
+ "Expected: false");
+#endif
+ ASSERT_FALSE(ResultIsEvenNoExplanation(3));
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)),
+ "Value of: ResultIsEvenNoExplanation(2)\n"
+ " Actual: true\n"
+ "Expected: false");
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" supressed them
+# pragma option pop
+#endif
+
+// Tests using ASSERT_EQ on double values. The purpose is to make
+// sure that the specialization we did for integer and anonymous enums
+// isn't used for double arguments.
+TEST(ExpectTest, ASSERT_EQ_Double)
+{
+ // A success.
+ ASSERT_EQ(5.6, 5.6);
+
+ // A failure.
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(5.1, 5.2),
+ "5.1");
+}
+
+// Tests ASSERT_EQ.
+TEST(AssertionTest, ASSERT_EQ)
+{
+ ASSERT_EQ(5, 2 + 3);
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(5, 2*3),
+ "Value of: 2*3\n"
+ " Actual: 6\n"
+ "Expected: 5");
+}
+
+// Tests ASSERT_EQ(NULL, pointer).
+#if GTEST_CAN_COMPARE_NULL
+TEST(AssertionTest, ASSERT_EQ_NULL)
+{
+ // A success.
+ const char* p = NULL;
+ // Some older GCC versions may issue a spurious waring in this or the next
+ // assertion statement. This warning should not be suppressed with
+ // static_cast since the test verifies the ability to use bare NULL as the
+ // expected parameter to the macro.
+ ASSERT_EQ(NULL, p);
+
+ // A failure.
+ static int n = 0;
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(NULL, &n),
+ "Value of: &n\n");
+}
+#endif // GTEST_CAN_COMPARE_NULL
+
+// Tests ASSERT_EQ(0, non_pointer). Since the literal 0 can be
+// treated as a null pointer by the compiler, we need to make sure
+// that ASSERT_EQ(0, non_pointer) isn't interpreted by Google Test as
+// ASSERT_EQ(static_cast<void*>(NULL), non_pointer).
+TEST(ExpectTest, ASSERT_EQ_0)
+{
+ int n = 0;
+
+ // A success.
+ ASSERT_EQ(0, n);
+
+ // A failure.
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(0, 5.6),
+ "Expected: 0");
+}
+
+// Tests ASSERT_NE.
+TEST(AssertionTest, ASSERT_NE)
+{
+ ASSERT_NE(6, 7);
+ EXPECT_FATAL_FAILURE(ASSERT_NE('a', 'a'),
+ "Expected: ('a') != ('a'), "
+ "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)");
+}
+
+// Tests ASSERT_LE.
+TEST(AssertionTest, ASSERT_LE)
+{
+ ASSERT_LE(2, 3);
+ ASSERT_LE(2, 2);
+ EXPECT_FATAL_FAILURE(ASSERT_LE(2, 0),
+ "Expected: (2) <= (0), actual: 2 vs 0");
+}
+
+// Tests ASSERT_LT.
+TEST(AssertionTest, ASSERT_LT)
+{
+ ASSERT_LT(2, 3);
+ EXPECT_FATAL_FAILURE(ASSERT_LT(2, 2),
+ "Expected: (2) < (2), actual: 2 vs 2");
+}
+
+// Tests ASSERT_GE.
+TEST(AssertionTest, ASSERT_GE)
+{
+ ASSERT_GE(2, 1);
+ ASSERT_GE(2, 2);
+ EXPECT_FATAL_FAILURE(ASSERT_GE(2, 3),
+ "Expected: (2) >= (3), actual: 2 vs 3");
+}
+
+// Tests ASSERT_GT.
+TEST(AssertionTest, ASSERT_GT)
+{
+ ASSERT_GT(2, 1);
+ EXPECT_FATAL_FAILURE(ASSERT_GT(2, 2),
+ "Expected: (2) > (2), actual: 2 vs 2");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+void ThrowNothing() {}
+
+// Tests ASSERT_THROW.
+TEST(AssertionTest, ASSERT_THROW)
+{
+ ASSERT_THROW(ThrowAnInteger(), int);
+
+# ifndef __BORLANDC__
+
+ // ICE's in C++Builder 2007 and 2009.
+ EXPECT_FATAL_FAILURE(
+ ASSERT_THROW(ThrowAnInteger(), bool),
+ "Expected: ThrowAnInteger() throws an exception of type bool.\n"
+ " Actual: it throws a different type.");
+# endif
+
+ EXPECT_FATAL_FAILURE(
+ ASSERT_THROW(ThrowNothing(), bool),
+ "Expected: ThrowNothing() throws an exception of type bool.\n"
+ " Actual: it throws nothing.");
+}
+
+// Tests ASSERT_NO_THROW.
+TEST(AssertionTest, ASSERT_NO_THROW)
+{
+ ASSERT_NO_THROW(ThrowNothing());
+ EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()),
+ "Expected: ThrowAnInteger() doesn't throw an exception."
+ "\n Actual: it throws.");
+}
+
+// Tests ASSERT_ANY_THROW.
+TEST(AssertionTest, ASSERT_ANY_THROW)
+{
+ ASSERT_ANY_THROW(ThrowAnInteger());
+ EXPECT_FATAL_FAILURE(
+ ASSERT_ANY_THROW(ThrowNothing()),
+ "Expected: ThrowNothing() throws an exception.\n"
+ " Actual: it doesn't.");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Makes sure we deal with the precedence of <<. This test should
+// compile.
+TEST(AssertionTest, AssertPrecedence)
+{
+ ASSERT_EQ(1 < 2, true);
+ bool false_value = false;
+ ASSERT_EQ(true && false_value, false);
+}
+
+// A subroutine used by the following test.
+void TestEq1(int x)
+{
+ ASSERT_EQ(1, x);
+}
+
+// Tests calling a test subroutine that's not part of a fixture.
+TEST(AssertionTest, NonFixtureSubroutine)
+{
+ EXPECT_FATAL_FAILURE(TestEq1(2),
+ "Value of: x");
+}
+
+// An uncopyable class.
+class Uncopyable
+{
+ public:
+ explicit Uncopyable(int a_value) : value_(a_value) {}
+
+ int value() const { return value_; }
+ bool operator==(const Uncopyable& rhs) const {
+ return value() == rhs.value();
+ }
+ private:
+ // This constructor deliberately has no implementation, as we don't
+ // want this class to be copyable.
+ Uncopyable(const Uncopyable&); // NOLINT
+
+ int value_;
+};
+
+::std::ostream& operator<<(::std::ostream& os, const Uncopyable& value)
+{
+ return os << value.value();
+}
+
+
+bool IsPositiveUncopyable(const Uncopyable& x)
+{
+ return x.value() > 0;
+}
+
+// A subroutine used by the following test.
+void TestAssertNonPositive()
+{
+ Uncopyable y(-1);
+ ASSERT_PRED1(IsPositiveUncopyable, y);
+}
+// A subroutine used by the following test.
+void TestAssertEqualsUncopyable()
+{
+ Uncopyable x(5);
+ Uncopyable y(-1);
+ ASSERT_EQ(x, y);
+}
+
+// Tests that uncopyable objects can be used in assertions.
+TEST(AssertionTest, AssertWorksWithUncopyableObject)
+{
+ Uncopyable x(5);
+ ASSERT_PRED1(IsPositiveUncopyable, x);
+ ASSERT_EQ(x, x);
+ EXPECT_FATAL_FAILURE(TestAssertNonPositive(),
+ "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1");
+ EXPECT_FATAL_FAILURE(TestAssertEqualsUncopyable(),
+ "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5");
+}
+
+// Tests that uncopyable objects can be used in expects.
+TEST(AssertionTest, ExpectWorksWithUncopyableObject)
+{
+ Uncopyable x(5);
+ EXPECT_PRED1(IsPositiveUncopyable, x);
+ Uncopyable y(-1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED1(IsPositiveUncopyable, y),
+ "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1");
+ EXPECT_EQ(x, x);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y),
+ "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5");
+}
+
+enum NamedEnum {
+ kE1 = 0,
+ kE2 = 1
+};
+
+TEST(AssertionTest, NamedEnum)
+{
+ EXPECT_EQ(kE1, kE1);
+ EXPECT_LT(kE1, kE2);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 0");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Actual: 1");
+}
+
+// The version of gcc used in XCode 2.2 has a bug and doesn't allow
+// anonymous enums in assertions. Therefore the following test is not
+// done on Mac.
+// Sun Studio and HP aCC also reject this code.
+#if !GTEST_OS_MAC && !defined(__SUNPRO_CC) && !defined(__HP_aCC)
+
+// Tests using assertions with anonymous enums.
+enum {
+ kCaseA = -1,
+
+# if GTEST_OS_LINUX
+
+ // We want to test the case where the size of the anonymous enum is
+ // larger than sizeof(int), to make sure our implementation of the
+ // assertions doesn't truncate the enums. However, MSVC
+ // (incorrectly) doesn't allow an enum value to exceed the range of
+ // an int, so this has to be conditionally compiled.
+ //
+ // On Linux, kCaseB and kCaseA have the same value when truncated to
+ // int size. We want to test whether this will confuse the
+ // assertions.
+ kCaseB = testing::internal::kMaxBiggestInt,
+
+# else
+
+ kCaseB = INT_MAX,
+
+# endif // GTEST_OS_LINUX
+
+ kCaseC = 42
+};
+
+TEST(AssertionTest, AnonymousEnum)
+{
+# if GTEST_OS_LINUX
+
+ EXPECT_EQ(static_cast<int>(kCaseA), static_cast<int>(kCaseB));
+
+# endif // GTEST_OS_LINUX
+
+ EXPECT_EQ(kCaseA, kCaseA);
+ EXPECT_NE(kCaseA, kCaseB);
+ EXPECT_LT(kCaseA, kCaseB);
+ EXPECT_LE(kCaseA, kCaseB);
+ EXPECT_GT(kCaseB, kCaseA);
+ EXPECT_GE(kCaseA, kCaseA);
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseB),
+ "(kCaseA) >= (kCaseB)");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseC),
+ "-1 vs 42");
+
+ ASSERT_EQ(kCaseA, kCaseA);
+ ASSERT_NE(kCaseA, kCaseB);
+ ASSERT_LT(kCaseA, kCaseB);
+ ASSERT_LE(kCaseA, kCaseB);
+ ASSERT_GT(kCaseB, kCaseA);
+ ASSERT_GE(kCaseA, kCaseA);
+
+# ifndef __BORLANDC__
+
+ // ICE's in C++Builder.
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseB),
+ "Value of: kCaseB");
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC),
+ "Actual: 42");
+# endif
+
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC),
+ "Which is: -1");
+}
+
+#endif // !GTEST_OS_MAC && !defined(__SUNPRO_CC)
+
+#if GTEST_OS_WINDOWS
+
+static HRESULT UnexpectedHRESULTFailure()
+{
+ return E_UNEXPECTED;
+}
+
+static HRESULT OkHRESULTSuccess()
+{
+ return S_OK;
+}
+
+static HRESULT FalseHRESULTSuccess()
+{
+ return S_FALSE;
+}
+
+// HRESULT assertion tests test both zero and non-zero
+// success codes as well as failure message for each.
+//
+// Windows CE doesn't support message texts.
+TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED)
+{
+ EXPECT_HRESULT_SUCCEEDED(S_OK);
+ EXPECT_HRESULT_SUCCEEDED(S_FALSE);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()),
+ "Expected: (UnexpectedHRESULTFailure()) succeeds.\n"
+ " Actual: 0x8000FFFF");
+}
+
+TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED)
+{
+ ASSERT_HRESULT_SUCCEEDED(S_OK);
+ ASSERT_HRESULT_SUCCEEDED(S_FALSE);
+
+ EXPECT_FATAL_FAILURE(ASSERT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()),
+ "Expected: (UnexpectedHRESULTFailure()) succeeds.\n"
+ " Actual: 0x8000FFFF");
+}
+
+TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED)
+{
+ EXPECT_HRESULT_FAILED(E_UNEXPECTED);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(OkHRESULTSuccess()),
+ "Expected: (OkHRESULTSuccess()) fails.\n"
+ " Actual: 0x0");
+ EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()),
+ "Expected: (FalseHRESULTSuccess()) fails.\n"
+ " Actual: 0x1");
+}
+
+TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED)
+{
+ ASSERT_HRESULT_FAILED(E_UNEXPECTED);
+
+# ifndef __BORLANDC__
+
+ // ICE's in C++Builder 2007 and 2009.
+ EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(OkHRESULTSuccess()),
+ "Expected: (OkHRESULTSuccess()) fails.\n"
+ " Actual: 0x0");
+# endif
+
+ EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()),
+ "Expected: (FalseHRESULTSuccess()) fails.\n"
+ " Actual: 0x1");
+}
+
+// Tests that streaming to the HRESULT macros works.
+TEST(HRESULTAssertionTest, Streaming)
+{
+ EXPECT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure";
+ ASSERT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure";
+ EXPECT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure";
+ ASSERT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure";
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure",
+ "expected failure");
+
+# ifndef __BORLANDC__
+
+ // ICE's in C++Builder 2007 and 2009.
+ EXPECT_FATAL_FAILURE(
+ ASSERT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure",
+ "expected failure");
+# endif
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_HRESULT_FAILED(S_OK) << "expected failure",
+ "expected failure");
+
+ EXPECT_FATAL_FAILURE(
+ ASSERT_HRESULT_FAILED(S_OK) << "expected failure",
+ "expected failure");
+}
+
+#endif // GTEST_OS_WINDOWS
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+# pragma option push -w-ccc -w-rch
+#endif
+
+// Tests that the assertion macros behave like single statements.
+TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement)
+{
+ if (AlwaysFalse())
+ ASSERT_TRUE(false) << "This should never be executed; "
+ "It's a compilation test only.";
+
+ if (AlwaysTrue())
+ EXPECT_FALSE(false);
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ASSERT_LT(1, 3);
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ EXPECT_GT(3, 2) << "";
+}
+
+#if GTEST_HAS_EXCEPTIONS
+// Tests that the compiler will not complain about unreachable code in the
+// EXPECT_THROW/EXPECT_ANY_THROW/EXPECT_NO_THROW macros.
+TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning)
+{
+ int n = 0;
+
+ EXPECT_THROW(throw 1, int);
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(n++, int), "");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw 1, const char*), "");
+ EXPECT_NO_THROW(n++);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(throw 1), "");
+ EXPECT_ANY_THROW(throw 1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), "");
+}
+
+TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement)
+{
+ if (AlwaysFalse())
+ EXPECT_THROW(ThrowNothing(), bool);
+
+ if (AlwaysTrue())
+ EXPECT_THROW(ThrowAnInteger(), int);
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ EXPECT_NO_THROW(ThrowAnInteger());
+
+ if (AlwaysTrue())
+ EXPECT_NO_THROW(ThrowNothing());
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ EXPECT_ANY_THROW(ThrowNothing());
+
+ if (AlwaysTrue())
+ EXPECT_ANY_THROW(ThrowAnInteger());
+ else
+ ; // NOLINT
+}
+#endif // GTEST_HAS_EXCEPTIONS
+
+TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement)
+{
+ if (AlwaysFalse())
+ EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. "
+ << "It's a compilation test only.";
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ASSERT_NO_FATAL_FAILURE(FAIL()) << "";
+ else
+ ; // NOLINT
+
+ if (AlwaysTrue())
+ EXPECT_NO_FATAL_FAILURE(SUCCEED());
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ ASSERT_NO_FATAL_FAILURE(SUCCEED());
+}
+
+// Tests that the assertion macros work well with switch statements.
+TEST(AssertionSyntaxTest, WorksWithSwitch)
+{
+ switch (0) {
+ case 1:
+ break;
+ default:
+ ASSERT_TRUE(true);
+ }
+
+ switch (0)
+ case 0:
+ EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case";
+
+ // Binary assertions are implemented using a different code path
+ // than the Boolean assertions. Hence we test them separately.
+ switch (0) {
+ case 1:
+ default:
+ ASSERT_EQ(1, 1) << "ASSERT_EQ failed in default switch handler";
+ }
+
+ switch (0)
+ case 0:
+ EXPECT_NE(1, 2);
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+void ThrowAString()
+{
+ throw "std::string";
+}
+
+// Test that the exception assertion macros compile and work with const
+// type qualifier.
+TEST(AssertionSyntaxTest, WorksWithConst)
+{
+ ASSERT_THROW(ThrowAString(), const char*);
+
+ EXPECT_THROW(ThrowAString(), const char*);
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+} // namespace
+
+namespace testing
+{
+
+// Tests that Google Test tracks SUCCEED*.
+TEST(SuccessfulAssertionTest, SUCCEED)
+{
+ SUCCEED();
+ SUCCEED() << "OK";
+ EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful EXPECT_*.
+TEST(SuccessfulAssertionTest, EXPECT)
+{
+ EXPECT_TRUE(true);
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful EXPECT_STR*.
+TEST(SuccessfulAssertionTest, EXPECT_STR)
+{
+ EXPECT_STREQ("", "");
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful ASSERT_*.
+TEST(SuccessfulAssertionTest, ASSERT)
+{
+ ASSERT_TRUE(true);
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful ASSERT_STR*.
+TEST(SuccessfulAssertionTest, ASSERT_STR)
+{
+ ASSERT_STREQ("", "");
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+} // namespace testing
+
+namespace
+{
+
+// Tests the message streaming variation of assertions.
+
+TEST(AssertionWithMessageTest, EXPECT)
+{
+ EXPECT_EQ(1, 1) << "This should succeed.";
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(1, 1) << "Expected failure #1.",
+ "Expected failure #1");
+ EXPECT_LE(1, 2) << "This should succeed.";
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(1, 0) << "Expected failure #2.",
+ "Expected failure #2.");
+ EXPECT_GE(1, 0) << "This should succeed.";
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(1, 2) << "Expected failure #3.",
+ "Expected failure #3.");
+
+ EXPECT_STREQ("1", "1") << "This should succeed.";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("1", "1") << "Expected failure #4.",
+ "Expected failure #4.");
+ EXPECT_STRCASEEQ("a", "A") << "This should succeed.";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("a", "A") << "Expected failure #5.",
+ "Expected failure #5.");
+
+ EXPECT_FLOAT_EQ(1, 1) << "This should succeed.";
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1, 1.2) << "Expected failure #6.",
+ "Expected failure #6.");
+ EXPECT_NEAR(1, 1.1, 0.2) << "This should succeed.";
+}
+
+TEST(AssertionWithMessageTest, ASSERT)
+{
+ ASSERT_EQ(1, 1) << "This should succeed.";
+ ASSERT_NE(1, 2) << "This should succeed.";
+ ASSERT_LE(1, 2) << "This should succeed.";
+ ASSERT_LT(1, 2) << "This should succeed.";
+ ASSERT_GE(1, 0) << "This should succeed.";
+ EXPECT_FATAL_FAILURE(ASSERT_GT(1, 2) << "Expected failure.",
+ "Expected failure.");
+}
+
+TEST(AssertionWithMessageTest, ASSERT_STR)
+{
+ ASSERT_STREQ("1", "1") << "This should succeed.";
+ ASSERT_STRNE("1", "2") << "This should succeed.";
+ ASSERT_STRCASEEQ("a", "A") << "This should succeed.";
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("a", "A") << "Expected failure.",
+ "Expected failure.");
+}
+
+TEST(AssertionWithMessageTest, ASSERT_FLOATING)
+{
+ ASSERT_FLOAT_EQ(1, 1) << "This should succeed.";
+ ASSERT_DOUBLE_EQ(1, 1) << "This should succeed.";
+ EXPECT_FATAL_FAILURE(ASSERT_NEAR(1,1.2, 0.1) << "Expect failure.", // NOLINT
+ "Expect failure.");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous statement.
+}
+
+// Tests using ASSERT_FALSE with a streamed message.
+TEST(AssertionWithMessageTest, ASSERT_FALSE)
+{
+ ASSERT_FALSE(false) << "This shouldn't fail.";
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_FALSE(true) << "Expected failure: " << 2 << " > " << 1
+ << " evaluates to " << true;
+ }, "Expected failure");
+}
+
+// Tests using FAIL with a streamed message.
+TEST(AssertionWithMessageTest, FAIL)
+{
+ EXPECT_FATAL_FAILURE(FAIL() << 0,
+ "0");
+}
+
+// Tests using SUCCEED with a streamed message.
+TEST(AssertionWithMessageTest, SUCCEED)
+{
+ SUCCEED() << "Success == " << 1;
+}
+
+// Tests using ASSERT_TRUE with a streamed message.
+TEST(AssertionWithMessageTest, ASSERT_TRUE)
+{
+ ASSERT_TRUE(true) << "This should succeed.";
+ ASSERT_TRUE(true) << true;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_TRUE(false) << static_cast<const char*>(NULL)
+ << static_cast<char*>(NULL);
+ }, "(null)(null)");
+}
+
+#if GTEST_OS_WINDOWS
+// Tests using wide strings in assertion messages.
+TEST(AssertionWithMessageTest, WideStringMessage)
+{
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_TRUE(false) << L"This failure is expected.\x8119";
+ }, "This failure is expected.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EQ(1, 2) << "This failure is "
+ << L"expected too.\x8120";
+ }, "This failure is expected too.");
+}
+#endif // GTEST_OS_WINDOWS
+
+// Tests EXPECT_TRUE.
+TEST(ExpectTest, EXPECT_TRUE)
+{
+ EXPECT_TRUE(true) << "Intentional success";
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #1.",
+ "Intentional failure #1.");
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #2.",
+ "Intentional failure #2.");
+ EXPECT_TRUE(2 > 1); // NOLINT
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 < 1),
+ "Value of: 2 < 1\n"
+ " Actual: false\n"
+ "Expected: true");
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 > 3),
+ "2 > 3");
+}
+
+// Tests EXPECT_TRUE(predicate) for predicates returning AssertionResult.
+TEST(ExpectTest, ExpectTrueWithAssertionResult)
+{
+ EXPECT_TRUE(ResultIsEven(2));
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEven(3)),
+ "Value of: ResultIsEven(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+ EXPECT_TRUE(ResultIsEvenNoExplanation(2));
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEvenNoExplanation(3)),
+ "Value of: ResultIsEvenNoExplanation(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+}
+
+// Tests EXPECT_FALSE with a streamed message.
+TEST(ExpectTest, EXPECT_FALSE)
+{
+ EXPECT_FALSE(2 < 1); // NOLINT
+ EXPECT_FALSE(false) << "Intentional success";
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #1.",
+ "Intentional failure #1.");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #2.",
+ "Intentional failure #2.");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 > 1),
+ "Value of: 2 > 1\n"
+ " Actual: true\n"
+ "Expected: false");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 < 3),
+ "2 < 3");
+}
+
+// Tests EXPECT_FALSE(predicate) for predicates returning AssertionResult.
+TEST(ExpectTest, ExpectFalseWithAssertionResult)
+{
+ EXPECT_FALSE(ResultIsEven(3));
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEven(2)),
+ "Value of: ResultIsEven(2)\n"
+ " Actual: true (2 is even)\n"
+ "Expected: false");
+ EXPECT_FALSE(ResultIsEvenNoExplanation(3));
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEvenNoExplanation(2)),
+ "Value of: ResultIsEvenNoExplanation(2)\n"
+ " Actual: true\n"
+ "Expected: false");
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" supressed them
+# pragma option pop
+#endif
+
+// Tests EXPECT_EQ.
+TEST(ExpectTest, EXPECT_EQ)
+{
+ EXPECT_EQ(5, 2 + 3);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2*3),
+ "Value of: 2*3\n"
+ " Actual: 6\n"
+ "Expected: 5");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2 - 3),
+ "2 - 3");
+}
+
+// Tests using EXPECT_EQ on double values. The purpose is to make
+// sure that the specialization we did for integer and anonymous enums
+// isn't used for double arguments.
+TEST(ExpectTest, EXPECT_EQ_Double)
+{
+ // A success.
+ EXPECT_EQ(5.6, 5.6);
+
+ // A failure.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5.1, 5.2),
+ "5.1");
+}
+
+#if GTEST_CAN_COMPARE_NULL
+// Tests EXPECT_EQ(NULL, pointer).
+TEST(ExpectTest, EXPECT_EQ_NULL)
+{
+ // A success.
+ const char* p = NULL;
+ // Some older GCC versions may issue a spurious warning in this or the next
+ // assertion statement. This warning should not be suppressed with
+ // static_cast since the test verifies the ability to use bare NULL as the
+ // expected parameter to the macro.
+ EXPECT_EQ(NULL, p);
+
+ // A failure.
+ int n = 0;
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(NULL, &n),
+ "Value of: &n\n");
+}
+#endif // GTEST_CAN_COMPARE_NULL
+
+// Tests EXPECT_EQ(0, non_pointer). Since the literal 0 can be
+// treated as a null pointer by the compiler, we need to make sure
+// that EXPECT_EQ(0, non_pointer) isn't interpreted by Google Test as
+// EXPECT_EQ(static_cast<void*>(NULL), non_pointer).
+TEST(ExpectTest, EXPECT_EQ_0)
+{
+ int n = 0;
+
+ // A success.
+ EXPECT_EQ(0, n);
+
+ // A failure.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(0, 5.6),
+ "Expected: 0");
+}
+
+// Tests EXPECT_NE.
+TEST(ExpectTest, EXPECT_NE)
+{
+ EXPECT_NE(6, 7);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE('a', 'a'),
+ "Expected: ('a') != ('a'), "
+ "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)");
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(2, 2),
+ "2");
+ char* const p0 = NULL;
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(p0, p0),
+ "p0");
+ // Only way to get the Nokia compiler to compile the cast
+ // is to have a separate void* variable first. Putting
+ // the two casts on the same line doesn't work, neither does
+ // a direct C-style to char*.
+ void* pv1 = (void*)0x1234; // NOLINT
+ char* const p1 = reinterpret_cast<char*>(pv1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(p1, p1),
+ "p1");
+}
+
+// Tests EXPECT_LE.
+TEST(ExpectTest, EXPECT_LE)
+{
+ EXPECT_LE(2, 3);
+ EXPECT_LE(2, 2);
+ EXPECT_NONFATAL_FAILURE(EXPECT_LE(2, 0),
+ "Expected: (2) <= (0), actual: 2 vs 0");
+ EXPECT_NONFATAL_FAILURE(EXPECT_LE(1.1, 0.9),
+ "(1.1) <= (0.9)");
+}
+
+// Tests EXPECT_LT.
+TEST(ExpectTest, EXPECT_LT)
+{
+ EXPECT_LT(2, 3);
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 2),
+ "Expected: (2) < (2), actual: 2 vs 2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1),
+ "(2) < (1)");
+}
+
+// Tests EXPECT_GE.
+TEST(ExpectTest, EXPECT_GE)
+{
+ EXPECT_GE(2, 1);
+ EXPECT_GE(2, 2);
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(2, 3),
+ "Expected: (2) >= (3), actual: 2 vs 3");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(0.9, 1.1),
+ "(0.9) >= (1.1)");
+}
+
+// Tests EXPECT_GT.
+TEST(ExpectTest, EXPECT_GT)
+{
+ EXPECT_GT(2, 1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 2),
+ "Expected: (2) > (2), actual: 2 vs 2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 3),
+ "(2) > (3)");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests EXPECT_THROW.
+TEST(ExpectTest, EXPECT_THROW)
+{
+ EXPECT_THROW(ThrowAnInteger(), int);
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool),
+ "Expected: ThrowAnInteger() throws an exception of "
+ "type bool.\n Actual: it throws a different type.");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW(ThrowNothing(), bool),
+ "Expected: ThrowNothing() throws an exception of type bool.\n"
+ " Actual: it throws nothing.");
+}
+
+// Tests EXPECT_NO_THROW.
+TEST(ExpectTest, EXPECT_NO_THROW)
+{
+ EXPECT_NO_THROW(ThrowNothing());
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()),
+ "Expected: ThrowAnInteger() doesn't throw an "
+ "exception.\n Actual: it throws.");
+}
+
+// Tests EXPECT_ANY_THROW.
+TEST(ExpectTest, EXPECT_ANY_THROW)
+{
+ EXPECT_ANY_THROW(ThrowAnInteger());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_ANY_THROW(ThrowNothing()),
+ "Expected: ThrowNothing() throws an exception.\n"
+ " Actual: it doesn't.");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Make sure we deal with the precedence of <<.
+TEST(ExpectTest, ExpectPrecedence)
+{
+ EXPECT_EQ(1 < 2, true);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(true, true && false),
+ "Value of: true && false");
+}
+
+
+// Tests the StreamableToString() function.
+
+// Tests using StreamableToString() on a scalar.
+TEST(StreamableToStringTest, Scalar)
+{
+ EXPECT_STREQ("5", StreamableToString(5).c_str());
+}
+
+// Tests using StreamableToString() on a non-char pointer.
+TEST(StreamableToStringTest, Pointer)
+{
+ int n = 0;
+ int* p = &n;
+ EXPECT_STRNE("(null)", StreamableToString(p).c_str());
+}
+
+// Tests using StreamableToString() on a NULL non-char pointer.
+TEST(StreamableToStringTest, NullPointer)
+{
+ int* p = NULL;
+ EXPECT_STREQ("(null)", StreamableToString(p).c_str());
+}
+
+// Tests using StreamableToString() on a C string.
+TEST(StreamableToStringTest, CString)
+{
+ EXPECT_STREQ("Foo", StreamableToString("Foo").c_str());
+}
+
+// Tests using StreamableToString() on a NULL C string.
+TEST(StreamableToStringTest, NullCString)
+{
+ char* p = NULL;
+ EXPECT_STREQ("(null)", StreamableToString(p).c_str());
+}
+
+// Tests using streamable values as assertion messages.
+
+// Tests using std::string as an assertion message.
+TEST(StreamableTest, string)
+{
+ static const std::string str(
+ "This failure message is a std::string, and is expected.");
+ EXPECT_FATAL_FAILURE(FAIL() << str,
+ str.c_str());
+}
+
+// Tests that we can output strings containing embedded NULs.
+// Limited to Linux because we can only do this with std::string's.
+TEST(StreamableTest, stringWithEmbeddedNUL)
+{
+ static const char char_array_with_nul[] =
+ "Here's a NUL\0 and some more string";
+ static const std::string string_with_nul(char_array_with_nul,
+ sizeof(char_array_with_nul)
+ - 1); // drops the trailing NUL
+ EXPECT_FATAL_FAILURE(FAIL() << string_with_nul,
+ "Here's a NUL\\0 and some more string");
+}
+
+// Tests that we can output a NUL char.
+TEST(StreamableTest, NULChar)
+{
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ FAIL() << "A NUL" << '\0' << " and some more string";
+ }, "A NUL\\0 and some more string");
+}
+
+// Tests using int as an assertion message.
+TEST(StreamableTest, int)
+{
+ EXPECT_FATAL_FAILURE(FAIL() << 900913,
+ "900913");
+}
+
+// Tests using NULL char pointer as an assertion message.
+//
+// In MSVC, streaming a NULL char * causes access violation. Google Test
+// implemented a workaround (substituting "(null)" for NULL). This
+// tests whether the workaround works.
+TEST(StreamableTest, NullCharPtr)
+{
+ EXPECT_FATAL_FAILURE(FAIL() << static_cast<const char*>(NULL),
+ "(null)");
+}
+
+// Tests that basic IO manipulators (endl, ends, and flush) can be
+// streamed to testing::Message.
+TEST(StreamableTest, BasicIoManip)
+{
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ FAIL() << "Line 1." << std::endl
+ << "A NUL char " << std::ends << std::flush << " in line 2.";
+ }, "Line 1.\nA NUL char \\0 in line 2.");
+}
+
+// Tests the macros that haven't been covered so far.
+
+void AddFailureHelper(bool* aborted)
+{
+ *aborted = true;
+ ADD_FAILURE() << "Intentional failure.";
+ *aborted = false;
+}
+
+// Tests ADD_FAILURE.
+TEST(MacroTest, ADD_FAILURE)
+{
+ bool aborted = true;
+ EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted),
+ "Intentional failure.");
+ EXPECT_FALSE(aborted);
+}
+
+// Tests ADD_FAILURE_AT.
+TEST(MacroTest, ADD_FAILURE_AT)
+{
+ // Verifies that ADD_FAILURE_AT does generate a nonfatal failure and
+ // the failure message contains the user-streamed part.
+ EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42) << "Wrong!", "Wrong!");
+
+ // Verifies that the user-streamed part is optional.
+ EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42), "Failed");
+
+ // Unfortunately, we cannot verify that the failure message contains
+ // the right file path and line number the same way, as
+ // EXPECT_NONFATAL_FAILURE() doesn't get to see the file path and
+ // line number. Instead, we do that in gtest_output_test_.cc.
+}
+
+// Tests FAIL.
+TEST(MacroTest, FAIL)
+{
+ EXPECT_FATAL_FAILURE(FAIL(),
+ "Failed");
+ EXPECT_FATAL_FAILURE(FAIL() << "Intentional failure.",
+ "Intentional failure.");
+}
+
+// Tests SUCCEED
+TEST(MacroTest, SUCCEED)
+{
+ SUCCEED();
+ SUCCEED() << "Explicit success.";
+}
+
+// Tests for EXPECT_EQ() and ASSERT_EQ().
+//
+// These tests fail *intentionally*, s.t. the failure messages can be
+// generated and tested.
+//
+// We have different tests for different argument types.
+
+// Tests using bool values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Bool)
+{
+ EXPECT_EQ(true, true);
+ EXPECT_FATAL_FAILURE({
+ bool false_value = false;
+ ASSERT_EQ(false_value, true);
+ }, "Value of: true");
+}
+
+// Tests using int values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Int)
+{
+ ASSERT_EQ(32, 32);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(32, 33),
+ "33");
+}
+
+// Tests using time_t values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Time_T)
+{
+ EXPECT_EQ(static_cast<time_t>(0),
+ static_cast<time_t>(0));
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast<time_t>(0),
+ static_cast<time_t>(1234)),
+ "1234");
+}
+
+// Tests using char values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Char)
+{
+ ASSERT_EQ('z', 'z');
+ const char ch = 'b';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ('\0', ch),
+ "ch");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ('a', ch),
+ "ch");
+}
+
+// Tests using wchar_t values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, WideChar)
+{
+ EXPECT_EQ(L'b', L'b');
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'\0', L'x'),
+ "Value of: L'x'\n"
+ " Actual: L'x' (120, 0x78)\n"
+ "Expected: L'\0'\n"
+ "Which is: L'\0' (0, 0x0)");
+
+ static wchar_t wchar;
+ wchar = L'b';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar),
+ "wchar");
+ wchar = 0x8119;
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast<wchar_t>(0x8120), wchar),
+ "Value of: wchar");
+}
+
+// Tests using ::std::string values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, StdString)
+{
+ // Compares a const char* to an std::string that has identical
+ // content.
+ ASSERT_EQ("Test", ::std::string("Test"));
+
+ // Compares two identical std::strings.
+ static const ::std::string str1("A * in the middle");
+ static const ::std::string str2(str1);
+ EXPECT_EQ(str1, str2);
+
+ // Compares a const char* to an std::string that has different
+ // content
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ("Test", ::std::string("test")),
+ "\"test\"");
+
+ // Compares an std::string to a char* that has different content.
+ char* const p1 = const_cast<char*>("foo");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::std::string("bar"), p1),
+ "p1");
+
+ // Compares two std::strings that have different contents, one of
+ // which having a NUL character in the middle. This should fail.
+ static ::std::string str3(str1);
+ str3.at(2) = '\0';
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(str1, str3),
+ "Value of: str3\n"
+ " Actual: \"A \\0 in the middle\"");
+}
+
+#if GTEST_HAS_STD_WSTRING
+
+// Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, StdWideString)
+{
+ // Compares two identical std::wstrings.
+ const ::std::wstring wstr1(L"A * in the middle");
+ const ::std::wstring wstr2(wstr1);
+ ASSERT_EQ(wstr1, wstr2);
+
+ // Compares an std::wstring to a const wchar_t* that has identical
+ // content.
+ const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' };
+ EXPECT_EQ(::std::wstring(kTestX8119), kTestX8119);
+
+ // Compares an std::wstring to a const wchar_t* that has different
+ // content.
+ const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' };
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_EQ(::std::wstring(kTestX8119), kTestX8120);
+ }, "kTestX8120");
+
+ // Compares two std::wstrings that have different contents, one of
+ // which having a NUL character in the middle.
+ ::std::wstring wstr3(wstr1);
+ wstr3.at(2) = L'\0';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(wstr1, wstr3),
+ "wstr3");
+
+ // Compares a wchar_t* to an std::wstring that has different
+ // content.
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EQ(const_cast<wchar_t*>(L"foo"), ::std::wstring(L"bar"));
+ }, "");
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+// Tests using ::string values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, GlobalString)
+{
+ // Compares a const char* to a ::string that has identical content.
+ EXPECT_EQ("Test", ::string("Test"));
+
+ // Compares two identical ::strings.
+ const ::string str1("A * in the middle");
+ const ::string str2(str1);
+ ASSERT_EQ(str1, str2);
+
+ // Compares a ::string to a const char* that has different content.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::string("Test"), "test"),
+ "test");
+
+ // Compares two ::strings that have different contents, one of which
+ // having a NUL character in the middle.
+ ::string str3(str1);
+ str3.at(2) = '\0';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(str1, str3),
+ "str3");
+
+ // Compares a ::string to a char* that has different content.
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EQ(::string("bar"), const_cast<char*>("foo"));
+ }, "");
+}
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+
+// Tests using ::wstring values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, GlobalWideString)
+{
+ // Compares two identical ::wstrings.
+ static const ::wstring wstr1(L"A * in the middle");
+ static const ::wstring wstr2(wstr1);
+ EXPECT_EQ(wstr1, wstr2);
+
+ // Compares a const wchar_t* to a ::wstring that has identical content.
+ const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' };
+ ASSERT_EQ(kTestX8119, ::wstring(kTestX8119));
+
+ // Compares a const wchar_t* to a ::wstring that has different
+ // content.
+ const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' };
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_EQ(kTestX8120, ::wstring(kTestX8119));
+ }, "Test\\x8119");
+
+ // Compares a wchar_t* to a ::wstring that has different content.
+ wchar_t* const p1 = const_cast<wchar_t*>(L"foo");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, ::wstring(L"bar")),
+ "bar");
+
+ // Compares two ::wstrings that have different contents, one of which
+ // having a NUL character in the middle.
+ static ::wstring wstr3;
+ wstr3 = wstr1;
+ wstr3.at(2) = L'\0';
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(wstr1, wstr3),
+ "wstr3");
+}
+
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Tests using char pointers in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, CharPointer)
+{
+ char* const p0 = NULL;
+ // Only way to get the Nokia compiler to compile the cast
+ // is to have a separate void* variable first. Putting
+ // the two casts on the same line doesn't work, neither does
+ // a direct C-style to char*.
+ void* pv1 = (void*)0x1234; // NOLINT
+ void* pv2 = (void*)0xABC0; // NOLINT
+ char* const p1 = reinterpret_cast<char*>(pv1);
+ char* const p2 = reinterpret_cast<char*>(pv2);
+ ASSERT_EQ(p1, p1);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2),
+ "Value of: p2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2),
+ "p2");
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast<char*>(0x1234),
+ reinterpret_cast<char*>(0xABC0)),
+ "ABC0");
+}
+
+// Tests using wchar_t pointers in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, WideCharPointer)
+{
+ wchar_t* const p0 = NULL;
+ // Only way to get the Nokia compiler to compile the cast
+ // is to have a separate void* variable first. Putting
+ // the two casts on the same line doesn't work, neither does
+ // a direct C-style to char*.
+ void* pv1 = (void*)0x1234; // NOLINT
+ void* pv2 = (void*)0xABC0; // NOLINT
+ wchar_t* const p1 = reinterpret_cast<wchar_t*>(pv1);
+ wchar_t* const p2 = reinterpret_cast<wchar_t*>(pv2);
+ EXPECT_EQ(p0, p0);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2),
+ "Value of: p2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2),
+ "p2");
+ void* pv3 = (void*)0x1234; // NOLINT
+ void* pv4 = (void*)0xABC0; // NOLINT
+ const wchar_t* p3 = reinterpret_cast<const wchar_t*>(pv3);
+ const wchar_t* p4 = reinterpret_cast<const wchar_t*>(pv4);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p3, p4),
+ "p4");
+}
+
+// Tests using other types of pointers in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, OtherPointer)
+{
+ ASSERT_EQ(static_cast<const int*>(NULL),
+ static_cast<const int*>(NULL));
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast<const int*>(NULL),
+ reinterpret_cast<const int*>(0x1234)),
+ "0x1234");
+}
+
+// A class that supports binary comparison operators but not streaming.
+class UnprintableChar
+{
+ public:
+ explicit UnprintableChar(char ch) : char_(ch) {}
+
+ bool operator==(const UnprintableChar& rhs) const {
+ return char_ == rhs.char_;
+ }
+ bool operator!=(const UnprintableChar& rhs) const {
+ return char_ != rhs.char_;
+ }
+ bool operator<(const UnprintableChar& rhs) const {
+ return char_ < rhs.char_;
+ }
+ bool operator<=(const UnprintableChar& rhs) const {
+ return char_ <= rhs.char_;
+ }
+ bool operator>(const UnprintableChar& rhs) const {
+ return char_ > rhs.char_;
+ }
+ bool operator>=(const UnprintableChar& rhs) const {
+ return char_ >= rhs.char_;
+ }
+
+ private:
+ char char_;
+};
+
+// Tests that ASSERT_EQ() and friends don't require the arguments to
+// be printable.
+TEST(ComparisonAssertionTest, AcceptsUnprintableArgs)
+{
+ const UnprintableChar x('x'), y('y');
+ ASSERT_EQ(x, x);
+ EXPECT_NE(x, y);
+ ASSERT_LT(x, y);
+ EXPECT_LE(x, y);
+ ASSERT_GT(y, x);
+ EXPECT_GE(x, x);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <78>");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <79>");
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(y, y), "1-byte object <79>");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <78>");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <79>");
+
+ // Code tested by EXPECT_FATAL_FAILURE cannot reference local
+ // variables, so we have to write UnprintableChar('x') instead of x.
+#ifndef __BORLANDC__
+ // ICE's in C++Builder.
+ EXPECT_FATAL_FAILURE(ASSERT_NE(UnprintableChar('x'), UnprintableChar('x')),
+ "1-byte object <78>");
+ EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')),
+ "1-byte object <78>");
+#endif
+ EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')),
+ "1-byte object <79>");
+ EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')),
+ "1-byte object <78>");
+ EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')),
+ "1-byte object <79>");
+}
+
+// Tests the FRIEND_TEST macro.
+
+// This class has a private member we want to test. We will test it
+// both in a TEST and in a TEST_F.
+class Foo
+{
+ public:
+ Foo() {}
+
+ private:
+ int Bar() const { return 1; }
+
+ // Declares the friend tests that can access the private member
+ // Bar().
+ FRIEND_TEST(FRIEND_TEST_Test, TEST);
+ FRIEND_TEST(FRIEND_TEST_Test2, TEST_F);
+};
+
+// Tests that the FRIEND_TEST declaration allows a TEST to access a
+// class's private members. This should compile.
+TEST(FRIEND_TEST_Test, TEST)
+{
+ ASSERT_EQ(1, Foo().Bar());
+}
+
+// The fixture needed to test using FRIEND_TEST with TEST_F.
+class FRIEND_TEST_Test2 : public Test
+{
+ protected:
+ Foo foo;
+};
+
+// Tests that the FRIEND_TEST declaration allows a TEST_F to access a
+// class's private members. This should compile.
+TEST_F(FRIEND_TEST_Test2, TEST_F)
+{
+ ASSERT_EQ(1, foo.Bar());
+}
+
+// Tests the life cycle of Test objects.
+
+// The test fixture for testing the life cycle of Test objects.
+//
+// This class counts the number of live test objects that uses this
+// fixture.
+class TestLifeCycleTest : public Test
+{
+ protected:
+ // Constructor. Increments the number of test objects that uses
+ // this fixture.
+ TestLifeCycleTest() { count_++; }
+
+ // Destructor. Decrements the number of test objects that uses this
+ // fixture.
+ ~TestLifeCycleTest() { count_--; }
+
+ // Returns the number of live test objects that uses this fixture.
+ int count() const { return count_; }
+
+ private:
+ static int count_;
+};
+
+int TestLifeCycleTest::count_ = 0;
+
+// Tests the life cycle of test objects.
+TEST_F(TestLifeCycleTest, Test1)
+{
+ // There should be only one test object in this test case that's
+ // currently alive.
+ ASSERT_EQ(1, count());
+}
+
+// Tests the life cycle of test objects.
+TEST_F(TestLifeCycleTest, Test2)
+{
+ // After Test1 is done and Test2 is started, there should still be
+ // only one live test object, as the object for Test1 should've been
+ // deleted.
+ ASSERT_EQ(1, count());
+}
+
+} // namespace
+
+// Tests that the copy constructor works when it is NOT optimized away by
+// the compiler.
+TEST(AssertionResultTest, CopyConstructorWorksWhenNotOptimied)
+{
+ // Checks that the copy constructor doesn't try to dereference NULL pointers
+ // in the source object.
+ AssertionResult r1 = AssertionSuccess();
+ AssertionResult r2 = r1;
+ // The following line is added to prevent the compiler from optimizing
+ // away the constructor call.
+ r1 << "abc";
+
+ AssertionResult r3 = r1;
+ EXPECT_EQ(static_cast<bool>(r3), static_cast<bool>(r1));
+ EXPECT_STREQ("abc", r1.message());
+}
+
+// Tests that AssertionSuccess and AssertionFailure construct
+// AssertionResult objects as expected.
+TEST(AssertionResultTest, ConstructionWorks)
+{
+ AssertionResult r1 = AssertionSuccess();
+ EXPECT_TRUE(r1);
+ EXPECT_STREQ("", r1.message());
+
+ AssertionResult r2 = AssertionSuccess() << "abc";
+ EXPECT_TRUE(r2);
+ EXPECT_STREQ("abc", r2.message());
+
+ AssertionResult r3 = AssertionFailure();
+ EXPECT_FALSE(r3);
+ EXPECT_STREQ("", r3.message());
+
+ AssertionResult r4 = AssertionFailure() << "def";
+ EXPECT_FALSE(r4);
+ EXPECT_STREQ("def", r4.message());
+
+ AssertionResult r5 = AssertionFailure(Message() << "ghi");
+ EXPECT_FALSE(r5);
+ EXPECT_STREQ("ghi", r5.message());
+}
+
+// Tests that the negation flips the predicate result but keeps the message.
+TEST(AssertionResultTest, NegationWorks)
+{
+ AssertionResult r1 = AssertionSuccess() << "abc";
+ EXPECT_FALSE(!r1);
+ EXPECT_STREQ("abc", (!r1).message());
+
+ AssertionResult r2 = AssertionFailure() << "def";
+ EXPECT_TRUE(!r2);
+ EXPECT_STREQ("def", (!r2).message());
+}
+
+TEST(AssertionResultTest, StreamingWorks)
+{
+ AssertionResult r = AssertionSuccess();
+ r << "abc" << 'd' << 0 << true;
+ EXPECT_STREQ("abcd0true", r.message());
+}
+
+TEST(AssertionResultTest, CanStreamOstreamManipulators)
+{
+ AssertionResult r = AssertionSuccess();
+ r << "Data" << std::endl << std::flush << std::ends << "Will be visible";
+ EXPECT_STREQ("Data\n\\0Will be visible", r.message());
+}
+
+// Tests streaming a user type whose definition and operator << are
+// both in the global namespace.
+class Base
+{
+ public:
+ explicit Base(int an_x) : x_(an_x) {}
+ int x() const { return x_; }
+ private:
+ int x_;
+};
+std::ostream& operator<<(std::ostream& os,
+ const Base& val)
+{
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const Base* pointer)
+{
+ return os << "(" << pointer->x() << ")";
+}
+
+TEST(MessageTest, CanStreamUserTypeInGlobalNameSpace)
+{
+ Message msg;
+ Base a(1);
+
+ msg << a << &a; // Uses ::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming a user type whose definition and operator<< are
+// both in an unnamed namespace.
+namespace
+{
+class MyTypeInUnnamedNameSpace : public Base
+{
+ public:
+ explicit MyTypeInUnnamedNameSpace(int an_x): Base(an_x) {}
+};
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInUnnamedNameSpace& val)
+{
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInUnnamedNameSpace* pointer)
+{
+ return os << "(" << pointer->x() << ")";
+}
+} // namespace
+
+TEST(MessageTest, CanStreamUserTypeInUnnamedNameSpace)
+{
+ Message msg;
+ MyTypeInUnnamedNameSpace a(1);
+
+ msg << a << &a; // Uses <unnamed_namespace>::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming a user type whose definition and operator<< are
+// both in a user namespace.
+namespace namespace1
+{
+class MyTypeInNameSpace1 : public Base
+{
+ public:
+ explicit MyTypeInNameSpace1(int an_x): Base(an_x) {}
+};
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInNameSpace1& val)
+{
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInNameSpace1* pointer)
+{
+ return os << "(" << pointer->x() << ")";
+}
+} // namespace namespace1
+
+TEST(MessageTest, CanStreamUserTypeInUserNameSpace)
+{
+ Message msg;
+ namespace1::MyTypeInNameSpace1 a(1);
+
+ msg << a << &a; // Uses namespace1::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming a user type whose definition is in a user namespace
+// but whose operator<< is in the global namespace.
+namespace namespace2
+{
+class MyTypeInNameSpace2 : public ::Base
+{
+ public:
+ explicit MyTypeInNameSpace2(int an_x): Base(an_x) {}
+};
+} // namespace namespace2
+std::ostream& operator<<(std::ostream& os,
+ const namespace2::MyTypeInNameSpace2& val)
+{
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const namespace2::MyTypeInNameSpace2* pointer)
+{
+ return os << "(" << pointer->x() << ")";
+}
+
+TEST(MessageTest, CanStreamUserTypeInUserNameSpaceWithStreamOperatorInGlobal)
+{
+ Message msg;
+ namespace2::MyTypeInNameSpace2 a(1);
+
+ msg << a << &a; // Uses ::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming NULL pointers to testing::Message.
+TEST(MessageTest, NullPointers)
+{
+ Message msg;
+ char* const p1 = NULL;
+ unsigned char* const p2 = NULL;
+ int* p3 = NULL;
+ double* p4 = NULL;
+ bool* p5 = NULL;
+ Message* p6 = NULL;
+
+ msg << p1 << p2 << p3 << p4 << p5 << p6;
+ ASSERT_STREQ("(null)(null)(null)(null)(null)(null)",
+ msg.GetString().c_str());
+}
+
+// Tests streaming wide strings to testing::Message.
+TEST(MessageTest, WideStrings)
+{
+ // Streams a NULL of type const wchar_t*.
+ const wchar_t* const_wstr = NULL;
+ EXPECT_STREQ("(null)",
+ (Message() << const_wstr).GetString().c_str());
+
+ // Streams a NULL of type wchar_t*.
+ wchar_t* wstr = NULL;
+ EXPECT_STREQ("(null)",
+ (Message() << wstr).GetString().c_str());
+
+ // Streams a non-NULL of type const wchar_t*.
+ const_wstr = L"abc\x8119";
+ EXPECT_STREQ("abc\xe8\x84\x99",
+ (Message() << const_wstr).GetString().c_str());
+
+ // Streams a non-NULL of type wchar_t*.
+ wstr = const_cast<wchar_t*>(const_wstr);
+ EXPECT_STREQ("abc\xe8\x84\x99",
+ (Message() << wstr).GetString().c_str());
+}
+
+
+// This line tests that we can define tests in the testing namespace.
+namespace testing
+{
+
+// Tests the TestInfo class.
+
+class TestInfoTest : public Test
+{
+ protected:
+ static const TestInfo* GetTestInfo(const char* test_name) {
+ const TestCase* const test_case = GetUnitTestImpl()->
+ GetTestCase("TestInfoTest", "", NULL, NULL);
+
+ for (int i = 0; i < test_case->total_test_count(); ++i) {
+ const TestInfo* const test_info = test_case->GetTestInfo(i);
+ if (strcmp(test_name, test_info->name()) == 0)
+ return test_info;
+ }
+ return NULL;
+ }
+
+ static const TestResult* GetTestResult(
+ const TestInfo* test_info) {
+ return test_info->result();
+ }
+};
+
+// Tests TestInfo::test_case_name() and TestInfo::name().
+TEST_F(TestInfoTest, Names)
+{
+ const TestInfo* const test_info = GetTestInfo("Names");
+
+ ASSERT_STREQ("TestInfoTest", test_info->test_case_name());
+ ASSERT_STREQ("Names", test_info->name());
+}
+
+// Tests TestInfo::result().
+TEST_F(TestInfoTest, result)
+{
+ const TestInfo* const test_info = GetTestInfo("result");
+
+ // Initially, there is no TestPartResult for this test.
+ ASSERT_EQ(0, GetTestResult(test_info)->total_part_count());
+
+ // After the previous assertion, there is still none.
+ ASSERT_EQ(0, GetTestResult(test_info)->total_part_count());
+}
+
+// Tests setting up and tearing down a test case.
+
+class SetUpTestCaseTest : public Test
+{
+ protected:
+ // This will be called once before the first test in this test case
+ // is run.
+ static void SetUpTestCase() {
+ printf("Setting up the test case . . .\n");
+
+ // Initializes some shared resource. In this simple example, we
+ // just create a C string. More complex stuff can be done if
+ // desired.
+ shared_resource_ = "123";
+
+ // Increments the number of test cases that have been set up.
+ counter_++;
+
+ // SetUpTestCase() should be called only once.
+ EXPECT_EQ(1, counter_);
+ }
+
+ // This will be called once after the last test in this test case is
+ // run.
+ static void TearDownTestCase() {
+ printf("Tearing down the test case . . .\n");
+
+ // Decrements the number of test cases that have been set up.
+ counter_--;
+
+ // TearDownTestCase() should be called only once.
+ EXPECT_EQ(0, counter_);
+
+ // Cleans up the shared resource.
+ shared_resource_ = NULL;
+ }
+
+ // This will be called before each test in this test case.
+ virtual void SetUp() {
+ // SetUpTestCase() should be called only once, so counter_ should
+ // always be 1.
+ EXPECT_EQ(1, counter_);
+ }
+
+ // Number of test cases that have been set up.
+ static int counter_;
+
+ // Some resource to be shared by all tests in this test case.
+ static const char* shared_resource_;
+};
+
+int SetUpTestCaseTest::counter_ = 0;
+const char* SetUpTestCaseTest::shared_resource_ = NULL;
+
+// A test that uses the shared resource.
+TEST_F(SetUpTestCaseTest, Test1)
+{
+ EXPECT_STRNE(NULL, shared_resource_);
+}
+
+// Another test that uses the shared resource.
+TEST_F(SetUpTestCaseTest, Test2)
+{
+ EXPECT_STREQ("123", shared_resource_);
+}
+
+// The InitGoogleTestTest test case tests testing::InitGoogleTest().
+
+// The Flags struct stores a copy of all Google Test flags.
+struct Flags {
+ // Constructs a Flags struct where each flag has its default value.
+ Flags() : also_run_disabled_tests(false),
+ break_on_failure(false),
+ catch_exceptions(false),
+ death_test_use_fork(false),
+ filter(""),
+ list_tests(false),
+ output(""),
+ print_time(true),
+ random_seed(0),
+ repeat(1),
+ shuffle(false),
+ stack_trace_depth(kMaxStackTraceDepth),
+ stream_result_to(""),
+ throw_on_failure(false) {}
+
+ // Factory methods.
+
+ // Creates a Flags struct where the gtest_also_run_disabled_tests flag has
+ // the given value.
+ static Flags AlsoRunDisabledTests(bool also_run_disabled_tests) {
+ Flags flags;
+ flags.also_run_disabled_tests = also_run_disabled_tests;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_break_on_failure flag has
+ // the given value.
+ static Flags BreakOnFailure(bool break_on_failure) {
+ Flags flags;
+ flags.break_on_failure = break_on_failure;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_catch_exceptions flag has
+ // the given value.
+ static Flags CatchExceptions(bool catch_exceptions) {
+ Flags flags;
+ flags.catch_exceptions = catch_exceptions;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_death_test_use_fork flag has
+ // the given value.
+ static Flags DeathTestUseFork(bool death_test_use_fork) {
+ Flags flags;
+ flags.death_test_use_fork = death_test_use_fork;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_filter flag has the given
+ // value.
+ static Flags Filter(const char* filter) {
+ Flags flags;
+ flags.filter = filter;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_list_tests flag has the
+ // given value.
+ static Flags ListTests(bool list_tests) {
+ Flags flags;
+ flags.list_tests = list_tests;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_output flag has the given
+ // value.
+ static Flags Output(const char* output) {
+ Flags flags;
+ flags.output = output;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_print_time flag has the given
+ // value.
+ static Flags PrintTime(bool print_time) {
+ Flags flags;
+ flags.print_time = print_time;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_random_seed flag has
+ // the given value.
+ static Flags RandomSeed(Int32 random_seed) {
+ Flags flags;
+ flags.random_seed = random_seed;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_repeat flag has the given
+ // value.
+ static Flags Repeat(Int32 repeat) {
+ Flags flags;
+ flags.repeat = repeat;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_shuffle flag has
+ // the given value.
+ static Flags Shuffle(bool shuffle) {
+ Flags flags;
+ flags.shuffle = shuffle;
+ return flags;
+ }
+
+ // Creates a Flags struct where the GTEST_FLAG(stack_trace_depth) flag has
+ // the given value.
+ static Flags StackTraceDepth(Int32 stack_trace_depth) {
+ Flags flags;
+ flags.stack_trace_depth = stack_trace_depth;
+ return flags;
+ }
+
+ // Creates a Flags struct where the GTEST_FLAG(stream_result_to) flag has
+ // the given value.
+ static Flags StreamResultTo(const char* stream_result_to) {
+ Flags flags;
+ flags.stream_result_to = stream_result_to;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_throw_on_failure flag has
+ // the given value.
+ static Flags ThrowOnFailure(bool throw_on_failure) {
+ Flags flags;
+ flags.throw_on_failure = throw_on_failure;
+ return flags;
+ }
+
+ // These fields store the flag values.
+ bool also_run_disabled_tests;
+ bool break_on_failure;
+ bool catch_exceptions;
+ bool death_test_use_fork;
+ const char* filter;
+ bool list_tests;
+ const char* output;
+ bool print_time;
+ Int32 random_seed;
+ Int32 repeat;
+ bool shuffle;
+ Int32 stack_trace_depth;
+ const char* stream_result_to;
+ bool throw_on_failure;
+};
+
+// Fixture for testing InitGoogleTest().
+class InitGoogleTestTest : public Test
+{
+ protected:
+ // Clears the flags before each test.
+ virtual void SetUp() {
+ GTEST_FLAG(also_run_disabled_tests) = false;
+ GTEST_FLAG(break_on_failure) = false;
+ GTEST_FLAG(catch_exceptions) = false;
+ GTEST_FLAG(death_test_use_fork) = false;
+ GTEST_FLAG(filter) = "";
+ GTEST_FLAG(list_tests) = false;
+ GTEST_FLAG(output) = "";
+ GTEST_FLAG(print_time) = true;
+ GTEST_FLAG(random_seed) = 0;
+ GTEST_FLAG(repeat) = 1;
+ GTEST_FLAG(shuffle) = false;
+ GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth;
+ GTEST_FLAG(stream_result_to) = "";
+ GTEST_FLAG(throw_on_failure) = false;
+ }
+
+ // Asserts that two narrow or wide string arrays are equal.
+ template <typename CharType>
+ static void AssertStringArrayEq(size_t size1, CharType** array1,
+ size_t size2, CharType** array2) {
+ ASSERT_EQ(size1, size2) << " Array sizes different.";
+
+ for (size_t i = 0; i != size1; i++) {
+ ASSERT_STREQ(array1[i], array2[i]) << " where i == " << i;
+ }
+ }
+
+ // Verifies that the flag values match the expected values.
+ static void CheckFlags(const Flags& expected) {
+ EXPECT_EQ(expected.also_run_disabled_tests,
+ GTEST_FLAG(also_run_disabled_tests));
+ EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure));
+ EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions));
+ EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork));
+ EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str());
+ EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests));
+ EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str());
+ EXPECT_EQ(expected.print_time, GTEST_FLAG(print_time));
+ EXPECT_EQ(expected.random_seed, GTEST_FLAG(random_seed));
+ EXPECT_EQ(expected.repeat, GTEST_FLAG(repeat));
+ EXPECT_EQ(expected.shuffle, GTEST_FLAG(shuffle));
+ EXPECT_EQ(expected.stack_trace_depth, GTEST_FLAG(stack_trace_depth));
+ EXPECT_STREQ(expected.stream_result_to,
+ GTEST_FLAG(stream_result_to).c_str());
+ EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure));
+ }
+
+ // Parses a command line (specified by argc1 and argv1), then
+ // verifies that the flag values are expected and that the
+ // recognized flags are removed from the command line.
+ template <typename CharType>
+ static void TestParsingFlags(int argc1, const CharType** argv1,
+ int argc2, const CharType** argv2,
+ const Flags& expected, bool should_print_help) {
+ const bool saved_help_flag = ::testing::internal::g_help_flag;
+ ::testing::internal::g_help_flag = false;
+
+#if GTEST_HAS_STREAM_REDIRECTION
+ CaptureStdout();
+#endif
+
+ // Parses the command line.
+ internal::ParseGoogleTestFlagsOnly(&argc1, const_cast<CharType**>(argv1));
+
+#if GTEST_HAS_STREAM_REDIRECTION
+ const std::string captured_stdout = GetCapturedStdout();
+#endif
+
+ // Verifies the flag values.
+ CheckFlags(expected);
+
+ // Verifies that the recognized flags are removed from the command
+ // line.
+ AssertStringArrayEq(argc1 + 1, argv1, argc2 + 1, argv2);
+
+ // ParseGoogleTestFlagsOnly should neither set g_help_flag nor print the
+ // help message for the flags it recognizes.
+ EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag);
+
+#if GTEST_HAS_STREAM_REDIRECTION
+ const char* const expected_help_fragment =
+ "This program contains tests written using";
+ if (should_print_help) {
+ EXPECT_PRED_FORMAT2(IsSubstring, expected_help_fragment, captured_stdout);
+ } else {
+ EXPECT_PRED_FORMAT2(IsNotSubstring,
+ expected_help_fragment, captured_stdout);
+ }
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+ ::testing::internal::g_help_flag = saved_help_flag;
+ }
+
+ // This macro wraps TestParsingFlags s.t. the user doesn't need
+ // to specify the array sizes.
+
+#define GTEST_TEST_PARSING_FLAGS_(argv1, argv2, expected, should_print_help) \
+ TestParsingFlags(sizeof(argv1)/sizeof(*argv1) - 1, argv1, \
+ sizeof(argv2)/sizeof(*argv2) - 1, argv2, \
+ expected, should_print_help)
+};
+
+// Tests parsing an empty command line.
+TEST_F(InitGoogleTestTest, Empty)
+{
+ const char* argv[] = {
+ NULL
+ };
+
+ const char* argv2[] = {
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false);
+}
+
+// Tests parsing a command line that has no flag.
+TEST_F(InitGoogleTestTest, NoFlag)
+{
+ const char* argv[] = {
+ "foo.exe",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false);
+}
+
+// Tests parsing a bad --gtest_filter flag.
+TEST_F(InitGoogleTestTest, FilterBad)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ "--gtest_filter",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true);
+}
+
+// Tests parsing an empty --gtest_filter flag.
+TEST_F(InitGoogleTestTest, FilterEmpty)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter=",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), false);
+}
+
+// Tests parsing a non-empty --gtest_filter flag.
+TEST_F(InitGoogleTestTest, FilterNonEmpty)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter=abc",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false);
+}
+
+// Tests parsing --gtest_break_on_failure.
+TEST_F(InitGoogleTestTest, BreakOnFailureWithoutValue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false);
+}
+
+// Tests parsing --gtest_break_on_failure=0.
+TEST_F(InitGoogleTestTest, BreakOnFailureFalse_0)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false);
+}
+
+// Tests parsing --gtest_break_on_failure=f.
+TEST_F(InitGoogleTestTest, BreakOnFailureFalse_f)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=f",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false);
+}
+
+// Tests parsing --gtest_break_on_failure=F.
+TEST_F(InitGoogleTestTest, BreakOnFailureFalse_F)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=F",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false);
+}
+
+// Tests parsing a --gtest_break_on_failure flag that has a "true"
+// definition.
+TEST_F(InitGoogleTestTest, BreakOnFailureTrue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false);
+}
+
+// Tests parsing --gtest_catch_exceptions.
+TEST_F(InitGoogleTestTest, CatchExceptions)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_catch_exceptions",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::CatchExceptions(true), false);
+}
+
+// Tests parsing --gtest_death_test_use_fork.
+TEST_F(InitGoogleTestTest, DeathTestUseFork)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_death_test_use_fork",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::DeathTestUseFork(true), false);
+}
+
+// Tests having the same flag twice with different values. The
+// expected behavior is that the one coming last takes precedence.
+TEST_F(InitGoogleTestTest, DuplicatedFlags)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter=a",
+ "--gtest_filter=b",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("b"), false);
+}
+
+// Tests having an unrecognized flag on the command line.
+TEST_F(InitGoogleTestTest, UnrecognizedFlag)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure",
+ "bar", // Unrecognized by Google Test.
+ "--gtest_filter=b",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ "bar",
+ NULL
+ };
+
+ Flags flags;
+ flags.break_on_failure = true;
+ flags.filter = "b";
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, flags, false);
+}
+
+// Tests having a --gtest_list_tests flag
+TEST_F(InitGoogleTestTest, ListTestsFlag)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false);
+}
+
+// Tests having a --gtest_list_tests flag with a "true" value
+TEST_F(InitGoogleTestTest, ListTestsTrue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false);
+}
+
+// Tests having a --gtest_list_tests flag with a "false" value
+TEST_F(InitGoogleTestTest, ListTestsFalse)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false);
+}
+
+// Tests parsing --gtest_list_tests=f.
+TEST_F(InitGoogleTestTest, ListTestsFalse_f)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=f",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false);
+}
+
+// Tests parsing --gtest_list_tests=F.
+TEST_F(InitGoogleTestTest, ListTestsFalse_F)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=F",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false);
+}
+
+// Tests parsing --gtest_output (invalid).
+TEST_F(InitGoogleTestTest, OutputEmpty)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ "--gtest_output",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true);
+}
+
+// Tests parsing --gtest_output=xml
+TEST_F(InitGoogleTestTest, OutputXml)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output=xml",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml"), false);
+}
+
+// Tests parsing --gtest_output=xml:file
+TEST_F(InitGoogleTestTest, OutputXmlFile)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output=xml:file",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:file"), false);
+}
+
+// Tests parsing --gtest_output=xml:directory/path/
+TEST_F(InitGoogleTestTest, OutputXmlDirectory)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output=xml:directory/path/",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::Output("xml:directory/path/"), false);
+}
+
+// Tests having a --gtest_print_time flag
+TEST_F(InitGoogleTestTest, PrintTimeFlag)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false);
+}
+
+// Tests having a --gtest_print_time flag with a "true" value
+TEST_F(InitGoogleTestTest, PrintTimeTrue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false);
+}
+
+// Tests having a --gtest_print_time flag with a "false" value
+TEST_F(InitGoogleTestTest, PrintTimeFalse)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false);
+}
+
+// Tests parsing --gtest_print_time=f.
+TEST_F(InitGoogleTestTest, PrintTimeFalse_f)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=f",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false);
+}
+
+// Tests parsing --gtest_print_time=F.
+TEST_F(InitGoogleTestTest, PrintTimeFalse_F)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=F",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false);
+}
+
+// Tests parsing --gtest_random_seed=number
+TEST_F(InitGoogleTestTest, RandomSeed)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_random_seed=1000",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::RandomSeed(1000), false);
+}
+
+// Tests parsing --gtest_repeat=number
+TEST_F(InitGoogleTestTest, Repeat)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_repeat=1000",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Repeat(1000), false);
+}
+
+// Tests having a --gtest_also_run_disabled_tests flag
+TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFlag)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_also_run_disabled_tests",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::AlsoRunDisabledTests(true), false);
+}
+
+// Tests having a --gtest_also_run_disabled_tests flag with a "true" value
+TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsTrue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_also_run_disabled_tests=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::AlsoRunDisabledTests(true), false);
+}
+
+// Tests having a --gtest_also_run_disabled_tests flag with a "false" value
+TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFalse)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_also_run_disabled_tests=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::AlsoRunDisabledTests(false), false);
+}
+
+// Tests parsing --gtest_shuffle.
+TEST_F(InitGoogleTestTest, ShuffleWithoutValue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_shuffle",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false);
+}
+
+// Tests parsing --gtest_shuffle=0.
+TEST_F(InitGoogleTestTest, ShuffleFalse_0)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_shuffle=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(false), false);
+}
+
+// Tests parsing a --gtest_shuffle flag that has a "true"
+// definition.
+TEST_F(InitGoogleTestTest, ShuffleTrue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_shuffle=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false);
+}
+
+// Tests parsing --gtest_stack_trace_depth=number.
+TEST_F(InitGoogleTestTest, StackTraceDepth)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_stack_trace_depth=5",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::StackTraceDepth(5), false);
+}
+
+TEST_F(InitGoogleTestTest, StreamResultTo)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_stream_result_to=localhost:1234",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(
+ argv, argv2, Flags::StreamResultTo("localhost:1234"), false);
+}
+
+// Tests parsing --gtest_throw_on_failure.
+TEST_F(InitGoogleTestTest, ThrowOnFailureWithoutValue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_throw_on_failure",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false);
+}
+
+// Tests parsing --gtest_throw_on_failure=0.
+TEST_F(InitGoogleTestTest, ThrowOnFailureFalse_0)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_throw_on_failure=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(false), false);
+}
+
+// Tests parsing a --gtest_throw_on_failure flag that has a "true"
+// definition.
+TEST_F(InitGoogleTestTest, ThrowOnFailureTrue)
+{
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_throw_on_failure=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false);
+}
+
+#if GTEST_OS_WINDOWS
+// Tests parsing wide strings.
+TEST_F(InitGoogleTestTest, WideStrings)
+{
+ const wchar_t* argv[] = {
+ L"foo.exe",
+ L"--gtest_filter=Foo*",
+ L"--gtest_list_tests=1",
+ L"--gtest_break_on_failure",
+ L"--non_gtest_flag",
+ NULL
+ };
+
+ const wchar_t* argv2[] = {
+ L"foo.exe",
+ L"--non_gtest_flag",
+ NULL
+ };
+
+ Flags expected_flags;
+ expected_flags.break_on_failure = true;
+ expected_flags.filter = "Foo*";
+ expected_flags.list_tests = true;
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false);
+}
+#endif // GTEST_OS_WINDOWS
+
+// Tests current_test_info() in UnitTest.
+class CurrentTestInfoTest : public Test
+{
+ protected:
+ // Tests that current_test_info() returns NULL before the first test in
+ // the test case is run.
+ static void SetUpTestCase() {
+ // There should be no tests running at this point.
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ EXPECT_TRUE(test_info == NULL)
+ << "There should be no tests running at this point.";
+ }
+
+ // Tests that current_test_info() returns NULL after the last test in
+ // the test case has run.
+ static void TearDownTestCase() {
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ EXPECT_TRUE(test_info == NULL)
+ << "There should be no tests running at this point.";
+ }
+};
+
+// Tests that current_test_info() returns TestInfo for currently running
+// test by checking the expected test name against the actual one.
+TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestCase)
+{
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ ASSERT_TRUE(NULL != test_info)
+ << "There is a test running so we should have a valid TestInfo.";
+ EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name())
+ << "Expected the name of the currently running test case.";
+ EXPECT_STREQ("WorksForFirstTestInATestCase", test_info->name())
+ << "Expected the name of the currently running test.";
+}
+
+// Tests that current_test_info() returns TestInfo for currently running
+// test by checking the expected test name against the actual one. We
+// use this test to see that the TestInfo object actually changed from
+// the previous invocation.
+TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestCase)
+{
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ ASSERT_TRUE(NULL != test_info)
+ << "There is a test running so we should have a valid TestInfo.";
+ EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name())
+ << "Expected the name of the currently running test case.";
+ EXPECT_STREQ("WorksForSecondTestInATestCase", test_info->name())
+ << "Expected the name of the currently running test.";
+}
+
+} // namespace testing
+
+// These two lines test that we can define tests in a namespace that
+// has the name "testing" and is nested in another namespace.
+namespace my_namespace
+{
+namespace testing
+{
+
+// Makes sure that TEST knows to use ::testing::Test instead of
+// ::my_namespace::testing::Test.
+class Test {};
+
+// Makes sure that an assertion knows to use ::testing::Message instead of
+// ::my_namespace::testing::Message.
+class Message {};
+
+// Makes sure that an assertion knows to use
+// ::testing::AssertionResult instead of
+// ::my_namespace::testing::AssertionResult.
+class AssertionResult {};
+
+// Tests that an assertion that should succeed works as expected.
+TEST(NestedTestingNamespaceTest, Success)
+{
+ EXPECT_EQ(1, 1) << "This shouldn't fail.";
+}
+
+// Tests that an assertion that should fail works as expected.
+TEST(NestedTestingNamespaceTest, Failure)
+{
+ EXPECT_FATAL_FAILURE(FAIL() << "This failure is expected.",
+ "This failure is expected.");
+}
+
+} // namespace testing
+} // namespace my_namespace
+
+// Tests that one can call superclass SetUp and TearDown methods--
+// that is, that they are not private.
+// No tests are based on this fixture; the test "passes" if it compiles
+// successfully.
+class ProtectedFixtureMethodsTest : public Test
+{
+ protected:
+ virtual void SetUp() {
+ Test::SetUp();
+ }
+ virtual void TearDown() {
+ Test::TearDown();
+ }
+};
+
+// StreamingAssertionsTest tests the streaming versions of a representative
+// sample of assertions.
+TEST(StreamingAssertionsTest, Unconditional)
+{
+ SUCCEED() << "expected success";
+ EXPECT_NONFATAL_FAILURE(ADD_FAILURE() << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(FAIL() << "expected failure",
+ "expected failure");
+}
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+# pragma option push -w-ccc -w-rch
+#endif
+
+TEST(StreamingAssertionsTest, Truth)
+{
+ EXPECT_TRUE(true) << "unexpected failure";
+ ASSERT_TRUE(true) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(false) << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, Truth2)
+{
+ EXPECT_FALSE(false) << "unexpected failure";
+ ASSERT_FALSE(false) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(true) << "expected failure",
+ "expected failure");
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" supressed them
+# pragma option pop
+#endif
+
+TEST(StreamingAssertionsTest, IntegerEquals)
+{
+ EXPECT_EQ(1, 1) << "unexpected failure";
+ ASSERT_EQ(1, 1) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(1, 2) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(1, 2) << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, IntegerLessThan)
+{
+ EXPECT_LT(1, 2) << "unexpected failure";
+ ASSERT_LT(1, 2) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_LT(2, 1) << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringsEqual)
+{
+ EXPECT_STREQ("foo", "foo") << "unexpected failure";
+ ASSERT_STREQ("foo", "foo") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ("foo", "bar") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ("foo", "bar") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringsNotEqual)
+{
+ EXPECT_STRNE("foo", "bar") << "unexpected failure";
+ ASSERT_STRNE("foo", "bar") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("foo", "foo") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STRNE("foo", "foo") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringsEqualIgnoringCase)
+{
+ EXPECT_STRCASEEQ("foo", "FOO") << "unexpected failure";
+ ASSERT_STRCASEEQ("foo", "FOO") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ("foo", "bar") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("foo", "bar") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringNotEqualIgnoringCase)
+{
+ EXPECT_STRCASENE("foo", "bar") << "unexpected failure";
+ ASSERT_STRCASENE("foo", "bar") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("foo", "FOO") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("bar", "BAR") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, FloatingPointEquals)
+{
+ EXPECT_FLOAT_EQ(1.0, 1.0) << "unexpected failure";
+ ASSERT_FLOAT_EQ(1.0, 1.0) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(0.0, 1.0) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.0) << "expected failure",
+ "expected failure");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+TEST(StreamingAssertionsTest, Throw)
+{
+ EXPECT_THROW(ThrowAnInteger(), int) << "unexpected failure";
+ ASSERT_THROW(ThrowAnInteger(), int) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool) <<
+ "expected failure", "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_THROW(ThrowAnInteger(), bool) <<
+ "expected failure", "expected failure");
+}
+
+TEST(StreamingAssertionsTest, NoThrow)
+{
+ EXPECT_NO_THROW(ThrowNothing()) << "unexpected failure";
+ ASSERT_NO_THROW(ThrowNothing()) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()) <<
+ "expected failure", "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()) <<
+ "expected failure", "expected failure");
+}
+
+TEST(StreamingAssertionsTest, AnyThrow)
+{
+ EXPECT_ANY_THROW(ThrowAnInteger()) << "unexpected failure";
+ ASSERT_ANY_THROW(ThrowAnInteger()) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(ThrowNothing()) <<
+ "expected failure", "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_ANY_THROW(ThrowNothing()) <<
+ "expected failure", "expected failure");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Tests that Google Test correctly decides whether to use colors in the output.
+
+TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsYes)
+{
+ GTEST_FLAG(color) = "yes";
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+}
+
+TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsAliasOfYes)
+{
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+
+ GTEST_FLAG(color) = "True";
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ GTEST_FLAG(color) = "t";
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ GTEST_FLAG(color) = "1";
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+}
+
+TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsNo)
+{
+ GTEST_FLAG(color) = "no";
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY.
+}
+
+TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsInvalid)
+{
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+
+ GTEST_FLAG(color) = "F";
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ GTEST_FLAG(color) = "0";
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ GTEST_FLAG(color) = "unknown";
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+}
+
+TEST(ColoredOutputTest, UsesColorsWhenStdoutIsTty)
+{
+ GTEST_FLAG(color) = "auto";
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+}
+
+TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors)
+{
+ GTEST_FLAG(color) = "auto";
+
+#if GTEST_OS_WINDOWS
+ // On Windows, we ignore the TERM variable as it's usually not set.
+
+ SetEnv("TERM", "dumb");
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "");
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm");
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+#else
+ // On non-Windows platforms, we rely on TERM to determine if the
+ // terminal supports colors.
+
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "emacs"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "vt100"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm-mono"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm-color"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm-256color"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "screen"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "screen-256color"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "linux"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "cygwin"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+#endif // GTEST_OS_WINDOWS
+}
+
+// Verifies that StaticAssertTypeEq works in a namespace scope.
+
+static bool dummy1 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq<bool, bool>();
+static bool dummy2 GTEST_ATTRIBUTE_UNUSED_ =
+ StaticAssertTypeEq<const int, const int>();
+
+// Verifies that StaticAssertTypeEq works in a class.
+
+template <typename T>
+class StaticAssertTypeEqTestHelper
+{
+ public:
+ StaticAssertTypeEqTestHelper() { StaticAssertTypeEq<bool, T>(); }
+};
+
+TEST(StaticAssertTypeEqTest, WorksInClass)
+{
+ StaticAssertTypeEqTestHelper<bool>();
+}
+
+// Verifies that StaticAssertTypeEq works inside a function.
+
+typedef int IntAlias;
+
+TEST(StaticAssertTypeEqTest, CompilesForEqualTypes)
+{
+ StaticAssertTypeEq<int, IntAlias>();
+ StaticAssertTypeEq<int*, IntAlias*>();
+}
+
+TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace)
+{
+ testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
+
+ // We don't have a stack walker in Google Test yet.
+ EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 0).c_str());
+ EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 1).c_str());
+}
+
+TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure)
+{
+ EXPECT_FALSE(HasNonfatalFailure());
+}
+
+static void FailFatally() { FAIL(); }
+
+TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure)
+{
+ FailFatally();
+ const bool has_nonfatal_failure = HasNonfatalFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_FALSE(has_nonfatal_failure);
+}
+
+TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure)
+{
+ ADD_FAILURE();
+ const bool has_nonfatal_failure = HasNonfatalFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_nonfatal_failure);
+}
+
+TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures)
+{
+ FailFatally();
+ ADD_FAILURE();
+ const bool has_nonfatal_failure = HasNonfatalFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_nonfatal_failure);
+}
+
+// A wrapper for calling HasNonfatalFailure outside of a test body.
+static bool HasNonfatalFailureHelper()
+{
+ return testing::Test::HasNonfatalFailure();
+}
+
+TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody)
+{
+ EXPECT_FALSE(HasNonfatalFailureHelper());
+}
+
+TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2)
+{
+ ADD_FAILURE();
+ const bool has_nonfatal_failure = HasNonfatalFailureHelper();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_nonfatal_failure);
+}
+
+TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure)
+{
+ EXPECT_FALSE(HasFailure());
+}
+
+TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure)
+{
+ FailFatally();
+ const bool has_failure = HasFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure)
+{
+ ADD_FAILURE();
+ const bool has_failure = HasFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures)
+{
+ FailFatally();
+ ADD_FAILURE();
+ const bool has_failure = HasFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+// A wrapper for calling HasFailure outside of a test body.
+static bool HasFailureHelper() { return testing::Test::HasFailure(); }
+
+TEST(HasFailureTest, WorksOutsideOfTestBody)
+{
+ EXPECT_FALSE(HasFailureHelper());
+}
+
+TEST(HasFailureTest, WorksOutsideOfTestBody2)
+{
+ ADD_FAILURE();
+ const bool has_failure = HasFailureHelper();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+class TestListener : public EmptyTestEventListener
+{
+ public:
+ TestListener() : on_start_counter_(NULL), is_destroyed_(NULL) {}
+ TestListener(int* on_start_counter, bool* is_destroyed)
+ : on_start_counter_(on_start_counter),
+ is_destroyed_(is_destroyed) {}
+
+ virtual ~TestListener() {
+ if (is_destroyed_)
+ *is_destroyed_ = true;
+ }
+
+ protected:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
+ if (on_start_counter_ != NULL)
+ (*on_start_counter_)++;
+ }
+
+ private:
+ int* on_start_counter_;
+ bool* is_destroyed_;
+};
+
+// Tests the constructor.
+TEST(TestEventListenersTest, ConstructionWorks)
+{
+ TestEventListeners listeners;
+
+ EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != NULL);
+ EXPECT_TRUE(listeners.default_result_printer() == NULL);
+ EXPECT_TRUE(listeners.default_xml_generator() == NULL);
+}
+
+// Tests that the TestEventListeners destructor deletes all the listeners it
+// owns.
+TEST(TestEventListenersTest, DestructionWorks)
+{
+ bool default_result_printer_is_destroyed = false;
+ bool default_xml_printer_is_destroyed = false;
+ bool extra_listener_is_destroyed = false;
+ TestListener* default_result_printer = new TestListener(
+ NULL, &default_result_printer_is_destroyed);
+ TestListener* default_xml_printer = new TestListener(
+ NULL, &default_xml_printer_is_destroyed);
+ TestListener* extra_listener = new TestListener(
+ NULL, &extra_listener_is_destroyed);
+
+ {
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners,
+ default_result_printer);
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners,
+ default_xml_printer);
+ listeners.Append(extra_listener);
+ }
+ EXPECT_TRUE(default_result_printer_is_destroyed);
+ EXPECT_TRUE(default_xml_printer_is_destroyed);
+ EXPECT_TRUE(extra_listener_is_destroyed);
+}
+
+// Tests that a listener Append'ed to a TestEventListeners list starts
+// receiving events.
+TEST(TestEventListenersTest, Append)
+{
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ listeners.Append(listener);
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(1, on_start_counter);
+ }
+ EXPECT_TRUE(is_destroyed);
+}
+
+// Tests that listeners receive events in the order they were appended to
+// the list, except for *End requests, which must be received in the reverse
+// order.
+class SequenceTestingListener : public EmptyTestEventListener
+{
+ public:
+ SequenceTestingListener(std::vector<std::string>* vector, const char* id)
+ : vector_(vector), id_(id) {}
+
+ protected:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
+ vector_->push_back(GetEventDescription("OnTestProgramStart"));
+ }
+
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {
+ vector_->push_back(GetEventDescription("OnTestProgramEnd"));
+ }
+
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {
+ vector_->push_back(GetEventDescription("OnTestIterationStart"));
+ }
+
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {
+ vector_->push_back(GetEventDescription("OnTestIterationEnd"));
+ }
+
+ private:
+ std::string GetEventDescription(const char* method) {
+ Message message;
+ message << id_ << "." << method;
+ return message.GetString();
+ }
+
+ std::vector<std::string>* vector_;
+ const char* const id_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener);
+};
+
+TEST(EventListenerTest, AppendKeepsOrder)
+{
+ std::vector<std::string> vec;
+ TestEventListeners listeners;
+ listeners.Append(new SequenceTestingListener(&vec, "1st"));
+ listeners.Append(new SequenceTestingListener(&vec, "2nd"));
+ listeners.Append(new SequenceTestingListener(&vec, "3rd"));
+
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("1st.OnTestProgramStart", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestProgramStart", vec[1].c_str());
+ EXPECT_STREQ("3rd.OnTestProgramStart", vec[2].c_str());
+
+ vec.clear();
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd(
+ *UnitTest::GetInstance());
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("3rd.OnTestProgramEnd", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestProgramEnd", vec[1].c_str());
+ EXPECT_STREQ("1st.OnTestProgramEnd", vec[2].c_str());
+
+ vec.clear();
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart(
+ *UnitTest::GetInstance(), 0);
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("1st.OnTestIterationStart", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestIterationStart", vec[1].c_str());
+ EXPECT_STREQ("3rd.OnTestIterationStart", vec[2].c_str());
+
+ vec.clear();
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd(
+ *UnitTest::GetInstance(), 0);
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("3rd.OnTestIterationEnd", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestIterationEnd", vec[1].c_str());
+ EXPECT_STREQ("1st.OnTestIterationEnd", vec[2].c_str());
+}
+
+// Tests that a listener removed from a TestEventListeners list stops receiving
+// events and is not deleted when the list is destroyed.
+TEST(TestEventListenersTest, Release)
+{
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ // Although Append passes the ownership of this object to the list,
+ // the following calls release it, and we need to delete it before the
+ // test ends.
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ listeners.Append(listener);
+ EXPECT_EQ(listener, listeners.Release(listener));
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_TRUE(listeners.Release(listener) == NULL);
+ }
+ EXPECT_EQ(0, on_start_counter);
+ EXPECT_FALSE(is_destroyed);
+ delete listener;
+}
+
+// Tests that no events are forwarded when event forwarding is disabled.
+TEST(EventListenerTest, SuppressEventForwarding)
+{
+ int on_start_counter = 0;
+ TestListener* listener = new TestListener(&on_start_counter, NULL);
+
+ TestEventListeners listeners;
+ listeners.Append(listener);
+ ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners));
+ TestEventListenersAccessor::SuppressEventForwarding(&listeners);
+ ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners));
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(0, on_start_counter);
+}
+
+// Tests that events generated by Google Test are not forwarded in
+// death test subprocesses.
+TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses)
+{
+ EXPECT_DEATH_IF_SUPPORTED({
+ GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled(
+ *GetUnitTestImpl()->listeners())) << "expected failure";
+ },
+ "expected failure");
+}
+
+// Tests that a listener installed via SetDefaultResultPrinter() starts
+// receiving events and is returned via default_result_printer() and that
+// the previous default_result_printer is removed from the list and deleted.
+TEST(EventListenerTest, default_result_printer)
+{
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.default_result_printer());
+
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+
+ EXPECT_EQ(1, on_start_counter);
+
+ // Replacing default_result_printer with something else should remove it
+ // from the list and destroy it.
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, NULL);
+
+ EXPECT_TRUE(listeners.default_result_printer() == NULL);
+ EXPECT_TRUE(is_destroyed);
+
+ // After broadcasting an event the counter is still the same, indicating
+ // the listener is not in the list anymore.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(1, on_start_counter);
+}
+
+// Tests that the default_result_printer listener stops receiving events
+// when removed via Release and that is not owned by the list anymore.
+TEST(EventListenerTest, RemovingDefaultResultPrinterWorks)
+{
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ // Although Append passes the ownership of this object to the list,
+ // the following calls release it, and we need to delete it before the
+ // test ends.
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.Release(listener));
+ EXPECT_TRUE(listeners.default_result_printer() == NULL);
+ EXPECT_FALSE(is_destroyed);
+
+ // Broadcasting events now should not affect default_result_printer.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(0, on_start_counter);
+ }
+ // Destroying the list should not affect the listener now, too.
+ EXPECT_FALSE(is_destroyed);
+ delete listener;
+}
+
+// Tests that a listener installed via SetDefaultXmlGenerator() starts
+// receiving events and is returned via default_xml_generator() and that
+// the previous default_xml_generator is removed from the list and deleted.
+TEST(EventListenerTest, default_xml_generator)
+{
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.default_xml_generator());
+
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+
+ EXPECT_EQ(1, on_start_counter);
+
+ // Replacing default_xml_generator with something else should remove it
+ // from the list and destroy it.
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, NULL);
+
+ EXPECT_TRUE(listeners.default_xml_generator() == NULL);
+ EXPECT_TRUE(is_destroyed);
+
+ // After broadcasting an event the counter is still the same, indicating
+ // the listener is not in the list anymore.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(1, on_start_counter);
+}
+
+// Tests that the default_xml_generator listener stops receiving events
+// when removed via Release and that is not owned by the list anymore.
+TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks)
+{
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ // Although Append passes the ownership of this object to the list,
+ // the following calls release it, and we need to delete it before the
+ // test ends.
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.Release(listener));
+ EXPECT_TRUE(listeners.default_xml_generator() == NULL);
+ EXPECT_FALSE(is_destroyed);
+
+ // Broadcasting events now should not affect default_xml_generator.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(0, on_start_counter);
+ }
+ // Destroying the list should not affect the listener now, too.
+ EXPECT_FALSE(is_destroyed);
+ delete listener;
+}
+
+// Sanity tests to ensure that the alternative, verbose spellings of
+// some of the macros work. We don't test them thoroughly as that
+// would be quite involved. Since their implementations are
+// straightforward, and they are rarely used, we'll just rely on the
+// users to tell us when they are broken.
+GTEST_TEST(AlternativeNameTest, Works) // GTEST_TEST is the same as TEST.
+{
+ GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED.
+
+ // GTEST_FAIL is the same as FAIL.
+ EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure",
+ "An expected failure");
+
+ // GTEST_ASSERT_XY is the same as ASSERT_XY.
+
+ GTEST_ASSERT_EQ(0, 0);
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(0, 1) << "An expected failure",
+ "An expected failure");
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(1, 0) << "An expected failure",
+ "An expected failure");
+
+ GTEST_ASSERT_NE(0, 1);
+ GTEST_ASSERT_NE(1, 0);
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_NE(0, 0) << "An expected failure",
+ "An expected failure");
+
+ GTEST_ASSERT_LE(0, 0);
+ GTEST_ASSERT_LE(0, 1);
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_LE(1, 0) << "An expected failure",
+ "An expected failure");
+
+ GTEST_ASSERT_LT(0, 1);
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(0, 0) << "An expected failure",
+ "An expected failure");
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(1, 0) << "An expected failure",
+ "An expected failure");
+
+ GTEST_ASSERT_GE(0, 0);
+ GTEST_ASSERT_GE(1, 0);
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_GE(0, 1) << "An expected failure",
+ "An expected failure");
+
+ GTEST_ASSERT_GT(1, 0);
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(0, 1) << "An expected failure",
+ "An expected failure");
+ EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(1, 1) << "An expected failure",
+ "An expected failure");
+}
+
+// Tests for internal utilities necessary for implementation of the universal
+// printing.
+// TODO(vladl at google.com): Find a better home for them.
+
+class ConversionHelperBase {};
+class ConversionHelperDerived : public ConversionHelperBase {};
+
+// Tests that IsAProtocolMessage<T>::value is a compile-time constant.
+TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant)
+{
+ GTEST_COMPILE_ASSERT_(IsAProtocolMessage<ProtocolMessage>::value,
+ const_true);
+ GTEST_COMPILE_ASSERT_(!IsAProtocolMessage<int>::value, const_false);
+}
+
+// Tests that IsAProtocolMessage<T>::value is true when T is
+// proto2::Message or a sub-class of it.
+TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage)
+{
+ EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value);
+ EXPECT_TRUE(IsAProtocolMessage<ProtocolMessage>::value);
+}
+
+// Tests that IsAProtocolMessage<T>::value is false when T is neither
+// ProtocolMessage nor a sub-class of it.
+TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage)
+{
+ EXPECT_FALSE(IsAProtocolMessage<int>::value);
+ EXPECT_FALSE(IsAProtocolMessage<const ConversionHelperBase>::value);
+}
+
+// Tests that CompileAssertTypesEqual compiles when the type arguments are
+// equal.
+TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual)
+{
+ CompileAssertTypesEqual<void, void>();
+ CompileAssertTypesEqual<int*, int*>();
+}
+
+// Tests that RemoveReference does not affect non-reference types.
+TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType)
+{
+ CompileAssertTypesEqual<int, RemoveReference<int>::type>();
+ CompileAssertTypesEqual<const char, RemoveReference<const char>::type>();
+}
+
+// Tests that RemoveReference removes reference from reference types.
+TEST(RemoveReferenceTest, RemovesReference)
+{
+ CompileAssertTypesEqual<int, RemoveReference<int&>::type>();
+ CompileAssertTypesEqual<const char, RemoveReference<const char&>::type>();
+}
+
+// Tests GTEST_REMOVE_REFERENCE_.
+
+template <typename T1, typename T2>
+void TestGTestRemoveReference()
+{
+ CompileAssertTypesEqual<T1, GTEST_REMOVE_REFERENCE_(T2)>();
+}
+
+TEST(RemoveReferenceTest, MacroVersion)
+{
+ TestGTestRemoveReference<int, int>();
+ TestGTestRemoveReference<const char, const char&>();
+}
+
+
+// Tests that RemoveConst does not affect non-const types.
+TEST(RemoveConstTest, DoesNotAffectNonConstType)
+{
+ CompileAssertTypesEqual<int, RemoveConst<int>::type>();
+ CompileAssertTypesEqual<char&, RemoveConst<char&>::type>();
+}
+
+// Tests that RemoveConst removes const from const types.
+TEST(RemoveConstTest, RemovesConst)
+{
+ CompileAssertTypesEqual<int, RemoveConst<const int>::type>();
+ CompileAssertTypesEqual<char[2], RemoveConst<const char[2]>::type>();
+ CompileAssertTypesEqual<char[2][3], RemoveConst<const char[2][3]>::type>();
+}
+
+// Tests GTEST_REMOVE_CONST_.
+
+template <typename T1, typename T2>
+void TestGTestRemoveConst()
+{
+ CompileAssertTypesEqual<T1, GTEST_REMOVE_CONST_(T2)>();
+}
+
+TEST(RemoveConstTest, MacroVersion)
+{
+ TestGTestRemoveConst<int, int>();
+ TestGTestRemoveConst<double&, double&>();
+ TestGTestRemoveConst<char, const char>();
+}
+
+// Tests GTEST_REMOVE_REFERENCE_AND_CONST_.
+
+template <typename T1, typename T2>
+void TestGTestRemoveReferenceAndConst()
+{
+ CompileAssertTypesEqual<T1, GTEST_REMOVE_REFERENCE_AND_CONST_(T2)>();
+}
+
+TEST(RemoveReferenceToConstTest, Works)
+{
+ TestGTestRemoveReferenceAndConst<int, int>();
+ TestGTestRemoveReferenceAndConst<double, double&>();
+ TestGTestRemoveReferenceAndConst<char, const char>();
+ TestGTestRemoveReferenceAndConst<char, const char&>();
+ TestGTestRemoveReferenceAndConst<const char*, const char*>();
+}
+
+// Tests that AddReference does not affect reference types.
+TEST(AddReferenceTest, DoesNotAffectReferenceType)
+{
+ CompileAssertTypesEqual<int&, AddReference<int&>::type>();
+ CompileAssertTypesEqual<const char&, AddReference<const char&>::type>();
+}
+
+// Tests that AddReference adds reference to non-reference types.
+TEST(AddReferenceTest, AddsReference)
+{
+ CompileAssertTypesEqual<int&, AddReference<int>::type>();
+ CompileAssertTypesEqual<const char&, AddReference<const char>::type>();
+}
+
+// Tests GTEST_ADD_REFERENCE_.
+
+template <typename T1, typename T2>
+void TestGTestAddReference()
+{
+ CompileAssertTypesEqual<T1, GTEST_ADD_REFERENCE_(T2)>();
+}
+
+TEST(AddReferenceTest, MacroVersion)
+{
+ TestGTestAddReference<int&, int>();
+ TestGTestAddReference<const char&, const char&>();
+}
+
+// Tests GTEST_REFERENCE_TO_CONST_.
+
+template <typename T1, typename T2>
+void TestGTestReferenceToConst()
+{
+ CompileAssertTypesEqual<T1, GTEST_REFERENCE_TO_CONST_(T2)>();
+}
+
+TEST(GTestReferenceToConstTest, Works)
+{
+ TestGTestReferenceToConst<const char&, char>();
+ TestGTestReferenceToConst<const int&, const int>();
+ TestGTestReferenceToConst<const double&, double>();
+ TestGTestReferenceToConst<const std::string&, const std::string&>();
+}
+
+// Tests that ImplicitlyConvertible<T1, T2>::value is a compile-time constant.
+TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant)
+{
+ GTEST_COMPILE_ASSERT_((ImplicitlyConvertible<int, int>::value), const_true);
+ GTEST_COMPILE_ASSERT_((!ImplicitlyConvertible<void*, int*>::value),
+ const_false);
+}
+
+// Tests that ImplicitlyConvertible<T1, T2>::value is true when T1 can
+// be implicitly converted to T2.
+TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible)
+{
+ EXPECT_TRUE((ImplicitlyConvertible<int, double>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<double, int>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<int*, void*>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<int*, const int*>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<ConversionHelperDerived&,
+ const ConversionHelperBase&>::value));
+ EXPECT_TRUE((ImplicitlyConvertible<const ConversionHelperBase,
+ ConversionHelperBase>::value));
+}
+
+// Tests that ImplicitlyConvertible<T1, T2>::value is false when T1
+// cannot be implicitly converted to T2.
+TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible)
+{
+ EXPECT_FALSE((ImplicitlyConvertible<double, int*>::value));
+ EXPECT_FALSE((ImplicitlyConvertible<void*, int*>::value));
+ EXPECT_FALSE((ImplicitlyConvertible<const int*, int*>::value));
+ EXPECT_FALSE((ImplicitlyConvertible<ConversionHelperBase&,
+ ConversionHelperDerived&>::value));
+}
+
+// Tests IsContainerTest.
+
+class NonContainer {};
+
+TEST(IsContainerTestTest, WorksForNonContainer)
+{
+ EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<int>(0)));
+ EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<char[5]>(0)));
+ EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<NonContainer>(0)));
+}
+
+TEST(IsContainerTestTest, WorksForContainer)
+{
+ EXPECT_EQ(sizeof(IsContainer),
+ sizeof(IsContainerTest<std::vector<bool> >(0)));
+ EXPECT_EQ(sizeof(IsContainer),
+ sizeof(IsContainerTest<std::map<int, double> >(0)));
+}
+
+// Tests ArrayEq().
+
+TEST(ArrayEqTest, WorksForDegeneratedArrays)
+{
+ EXPECT_TRUE(ArrayEq(5, 5L));
+ EXPECT_FALSE(ArrayEq('a', 0));
+}
+
+TEST(ArrayEqTest, WorksForOneDimensionalArrays)
+{
+ // Note that a and b are distinct but compatible types.
+ const int a[] = { 0, 1 };
+ long b[] = { 0, 1 };
+ EXPECT_TRUE(ArrayEq(a, b));
+ EXPECT_TRUE(ArrayEq(a, 2, b));
+
+ b[0] = 2;
+ EXPECT_FALSE(ArrayEq(a, b));
+ EXPECT_FALSE(ArrayEq(a, 1, b));
+}
+
+TEST(ArrayEqTest, WorksForTwoDimensionalArrays)
+{
+ const char a[][3] = { "hi", "lo" };
+ const char b[][3] = { "hi", "lo" };
+ const char c[][3] = { "hi", "li" };
+
+ EXPECT_TRUE(ArrayEq(a, b));
+ EXPECT_TRUE(ArrayEq(a, 2, b));
+
+ EXPECT_FALSE(ArrayEq(a, c));
+ EXPECT_FALSE(ArrayEq(a, 2, c));
+}
+
+// Tests ArrayAwareFind().
+
+TEST(ArrayAwareFindTest, WorksForOneDimensionalArray)
+{
+ const char a[] = "hello";
+ EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o'));
+ EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x'));
+}
+
+TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray)
+{
+ int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
+ const int b[2] = { 2, 3 };
+ EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b));
+
+ const int c[2] = { 6, 7 };
+ EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c));
+}
+
+// Tests CopyArray().
+
+TEST(CopyArrayTest, WorksForDegeneratedArrays)
+{
+ int n = 0;
+ CopyArray('a', &n);
+ EXPECT_EQ('a', n);
+}
+
+TEST(CopyArrayTest, WorksForOneDimensionalArrays)
+{
+ const char a[3] = "hi";
+ int b[3];
+#ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions.
+ CopyArray(a, &b);
+ EXPECT_TRUE(ArrayEq(a, b));
+#endif
+
+ int c[3];
+ CopyArray(a, 3, c);
+ EXPECT_TRUE(ArrayEq(a, c));
+}
+
+TEST(CopyArrayTest, WorksForTwoDimensionalArrays)
+{
+ const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } };
+ int b[2][3];
+#ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions.
+ CopyArray(a, &b);
+ EXPECT_TRUE(ArrayEq(a, b));
+#endif
+
+ int c[2][3];
+ CopyArray(a, 2, c);
+ EXPECT_TRUE(ArrayEq(a, c));
+}
+
+// Tests NativeArray.
+
+TEST(NativeArrayTest, ConstructorFromArrayWorks)
+{
+ const int a[3] = { 0, 1, 2 };
+ NativeArray<int> na(a, 3, kReference);
+ EXPECT_EQ(3U, na.size());
+ EXPECT_EQ(a, na.begin());
+}
+
+TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo)
+{
+ typedef int Array[2];
+ Array* a = new Array[1];
+ (*a)[0] = 0;
+ (*a)[1] = 1;
+ NativeArray<int> na(*a, 2, kCopy);
+ EXPECT_NE(*a, na.begin());
+ delete[] a;
+ EXPECT_EQ(0, na.begin()[0]);
+ EXPECT_EQ(1, na.begin()[1]);
+
+ // We rely on the heap checker to verify that na deletes the copy of
+ // array.
+}
+
+TEST(NativeArrayTest, TypeMembersAreCorrect)
+{
+ StaticAssertTypeEq<char, NativeArray<char>::value_type>();
+ StaticAssertTypeEq<int[2], NativeArray<int[2]>::value_type>();
+
+ StaticAssertTypeEq<const char*, NativeArray<char>::const_iterator>();
+ StaticAssertTypeEq<const bool(*)[2], NativeArray<bool[2]>::const_iterator>();
+}
+
+TEST(NativeArrayTest, MethodsWork)
+{
+ const int a[3] = { 0, 1, 2 };
+ NativeArray<int> na(a, 3, kCopy);
+ ASSERT_EQ(3U, na.size());
+ EXPECT_EQ(3, na.end() - na.begin());
+
+ NativeArray<int>::const_iterator it = na.begin();
+ EXPECT_EQ(0, *it);
+ ++it;
+ EXPECT_EQ(1, *it);
+ it++;
+ EXPECT_EQ(2, *it);
+ ++it;
+ EXPECT_EQ(na.end(), it);
+
+ EXPECT_TRUE(na == na);
+
+ NativeArray<int> na2(a, 3, kReference);
+ EXPECT_TRUE(na == na2);
+
+ const int b1[3] = { 0, 1, 1 };
+ const int b2[4] = { 0, 1, 2, 3 };
+ EXPECT_FALSE(na == NativeArray<int>(b1, 3, kReference));
+ EXPECT_FALSE(na == NativeArray<int>(b2, 4, kCopy));
+}
+
+TEST(NativeArrayTest, WorksForTwoDimensionalArray)
+{
+ const char a[2][3] = { "hi", "lo" };
+ NativeArray<char[3]> na(a, 2, kReference);
+ ASSERT_EQ(2U, na.size());
+ EXPECT_EQ(a, na.begin());
+}
+
+// Tests SkipPrefix().
+
+TEST(SkipPrefixTest, SkipsWhenPrefixMatches)
+{
+ const char* const str = "hello";
+
+ const char* p = str;
+ EXPECT_TRUE(SkipPrefix("", &p));
+ EXPECT_EQ(str, p);
+
+ p = str;
+ EXPECT_TRUE(SkipPrefix("hell", &p));
+ EXPECT_EQ(str + 4, p);
+}
+
+TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch)
+{
+ const char* const str = "world";
+
+ const char* p = str;
+ EXPECT_FALSE(SkipPrefix("W", &p));
+ EXPECT_EQ(str, p);
+
+ p = str;
+ EXPECT_FALSE(SkipPrefix("world!", &p));
+ EXPECT_EQ(str, p);
+}
diff --git a/external/gtest-1.6.0/test/gtest_xml_outfile1_test_.cc b/external/gtest-1.6.0/test/gtest_xml_outfile1_test_.cc
new file mode 100644
index 0000000..51f7c4c
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_xml_outfile1_test_.cc
@@ -0,0 +1,51 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray at gmail.com (Keith Ray)
+//
+// gtest_xml_outfile1_test_ writes some xml via TestProperty used by
+// gtest_xml_outfiles_test.py
+
+#include "gtest/gtest.h"
+
+class PropertyOne : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ RecordProperty("SetUpProp", 1);
+ }
+ virtual void TearDown() {
+ RecordProperty("TearDownProp", 1);
+ }
+};
+
+TEST_F(PropertyOne, TestSomeProperties)
+{
+ RecordProperty("TestSomeProperty", 1);
+}
diff --git a/external/gtest-1.6.0/test/gtest_xml_outfile2_test_.cc b/external/gtest-1.6.0/test/gtest_xml_outfile2_test_.cc
new file mode 100644
index 0000000..43ddf97
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_xml_outfile2_test_.cc
@@ -0,0 +1,51 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray at gmail.com (Keith Ray)
+//
+// gtest_xml_outfile2_test_ writes some xml via TestProperty used by
+// gtest_xml_outfiles_test.py
+
+#include "gtest/gtest.h"
+
+class PropertyTwo : public testing::Test
+{
+ protected:
+ virtual void SetUp() {
+ RecordProperty("SetUpProp", 2);
+ }
+ virtual void TearDown() {
+ RecordProperty("TearDownProp", 2);
+ }
+};
+
+TEST_F(PropertyTwo, TestSomeProperties)
+{
+ RecordProperty("TestSomeProperty", 2);
+}
diff --git a/external/gtest-1.6.0/test/gtest_xml_outfiles_test.py b/external/gtest-1.6.0/test/gtest_xml_outfiles_test.py
new file mode 100755
index 0000000..524e437
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_xml_outfiles_test.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for the gtest_xml_output module."""
+
+__author__ = "keith.ray at gmail.com (Keith Ray)"
+
+import os
+from xml.dom import minidom, Node
+
+import gtest_test_utils
+import gtest_xml_test_utils
+
+
+GTEST_OUTPUT_SUBDIR = "xml_outfiles"
+GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_"
+GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_"
+
+EXPECTED_XML_1 = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests">
+ <testsuite name="PropertyOne" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="TestSomeProperties" status="run" time="*" classname="PropertyOne" SetUpProp="1" TestSomeProperty="1" TearDownProp="1" />
+ </testsuite>
+</testsuites>
+"""
+
+EXPECTED_XML_2 = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests">
+ <testsuite name="PropertyTwo" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="TestSomeProperties" status="run" time="*" classname="PropertyTwo" SetUpProp="2" TestSomeProperty="2" TearDownProp="2" />
+ </testsuite>
+</testsuites>
+"""
+
+
+class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase):
+ """Unit test for Google Test's XML output functionality."""
+
+ def setUp(self):
+ # We want the trailing '/' that the last "" provides in os.path.join, for
+ # telling Google Test to create an output directory instead of a single file
+ # for xml output.
+ self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(),
+ GTEST_OUTPUT_SUBDIR, "")
+ self.DeleteFilesAndDir()
+
+ def tearDown(self):
+ self.DeleteFilesAndDir()
+
+ def DeleteFilesAndDir(self):
+ try:
+ os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml"))
+ except os.error:
+ pass
+ try:
+ os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml"))
+ except os.error:
+ pass
+ try:
+ os.rmdir(self.output_dir_)
+ except os.error:
+ pass
+
+ def testOutfile1(self):
+ self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_XML_1)
+
+ def testOutfile2(self):
+ self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_XML_2)
+
+ def _TestOutFile(self, test_name, expected_xml):
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name)
+ command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_]
+ p = gtest_test_utils.Subprocess(command,
+ working_dir=gtest_test_utils.GetTempDir())
+ self.assert_(p.exited)
+ self.assertEquals(0, p.exit_code)
+
+ # TODO(wan at google.com): libtool causes the built test binary to be
+ # named lt-gtest_xml_outfiles_test_ instead of
+ # gtest_xml_outfiles_test_. To account for this possibillity, we
+ # allow both names in the following code. We should remove this
+ # hack when Chandler Carruth's libtool replacement tool is ready.
+ output_file_name1 = test_name + ".xml"
+ output_file1 = os.path.join(self.output_dir_, output_file_name1)
+ output_file_name2 = 'lt-' + output_file_name1
+ output_file2 = os.path.join(self.output_dir_, output_file_name2)
+ self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2),
+ output_file1)
+
+ expected = minidom.parseString(expected_xml)
+ if os.path.isfile(output_file1):
+ actual = minidom.parse(output_file1)
+ else:
+ actual = minidom.parse(output_file2)
+ self.NormalizeXml(actual.documentElement)
+ self.AssertEquivalentNodes(expected.documentElement,
+ actual.documentElement)
+ expected.unlink()
+ actual.unlink()
+
+
+if __name__ == "__main__":
+ os.environ["GTEST_STACK_TRACE_DEPTH"] = "0"
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_xml_output_unittest.py b/external/gtest-1.6.0/test/gtest_xml_output_unittest.py
new file mode 100755
index 0000000..f605d4e
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_xml_output_unittest.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for the gtest_xml_output module"""
+
+__author__ = 'eefacm at gmail.com (Sean Mcafee)'
+
+import datetime
+import errno
+import os
+import re
+import sys
+from xml.dom import minidom, Node
+
+import gtest_test_utils
+import gtest_xml_test_utils
+
+
+GTEST_FILTER_FLAG = '--gtest_filter'
+GTEST_LIST_TESTS_FLAG = '--gtest_list_tests'
+GTEST_OUTPUT_FLAG = "--gtest_output"
+GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
+GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_"
+
+SUPPORTS_STACK_TRACES = False
+
+if SUPPORTS_STACK_TRACES:
+ STACK_TRACE_TEMPLATE = '\nStack trace:\n*'
+else:
+ STACK_TRACE_TEMPLATE = ''
+
+EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="23" failures="4" disabled="2" errors="0" time="*" timestamp="*" name="AllTests" ad_hoc_property="42">
+ <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
+ </testsuite>
+ <testsuite name="FailedTest" tests="1" failures="1" disabled="0" errors="0" time="*">
+ <testcase name="Fails" status="run" time="*" classname="FailedTest">
+ <failure message="gtest_xml_output_unittest_.cc:*
Value of: 2
Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Value of: 2
+Expected: 1%(stack)s]]></failure>
+ </testcase>
+ </testsuite>
+ <testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" errors="0" time="*">
+ <testcase name="Succeeds" status="run" time="*" classname="MixedResultTest"/>
+ <testcase name="Fails" status="run" time="*" classname="MixedResultTest">
+ <failure message="gtest_xml_output_unittest_.cc:*
Value of: 2
Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Value of: 2
+Expected: 1%(stack)s]]></failure>
+ <failure message="gtest_xml_output_unittest_.cc:*
Value of: 3
Expected: 2" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Value of: 3
+Expected: 2%(stack)s]]></failure>
+ </testcase>
+ <testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
+ </testsuite>
+ <testsuite name="XmlQuotingTest" tests="1" failures="1" disabled="0" errors="0" time="*">
+ <testcase name="OutputsCData" status="run" time="*" classname="XmlQuotingTest">
+ <failure message="gtest_xml_output_unittest_.cc:*
Failed
XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]></top>" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Failed
+XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]><![CDATA[</top>%(stack)s]]></failure>
+ </testcase>
+ </testsuite>
+ <testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" errors="0" time="*">
+ <testcase name="InvalidCharactersInMessage" status="run" time="*" classname="InvalidCharactersTest">
+ <failure message="gtest_xml_output_unittest_.cc:*
Failed
Invalid characters in brackets []" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Failed
+Invalid characters in brackets []%(stack)s]]></failure>
+ </testcase>
+ </testsuite>
+ <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
+ <testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/>
+ </testsuite>
+ <testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" errors="0" time="*" SetUpTestCase="yes" TearDownTestCase="aye">
+ <testcase name="OneProperty" status="run" time="*" classname="PropertyRecordingTest" key_1="1"/>
+ <testcase name="IntValuedProperty" status="run" time="*" classname="PropertyRecordingTest" key_int="1"/>
+ <testcase name="ThreeProperties" status="run" time="*" classname="PropertyRecordingTest" key_1="1" key_2="2" key_3="3"/>
+ <testcase name="TwoValuesForOneKeyUsesLastValue" status="run" time="*" classname="PropertyRecordingTest" key_1="2"/>
+ </testsuite>
+ <testsuite name="NoFixtureTest" tests="3" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="RecordProperty" status="run" time="*" classname="NoFixtureTest" key="1"/>
+ <testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_int="1"/>
+ <testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_string="1"/>
+ </testsuite>
+ <testsuite name="Single/ValueParamTest" tests="4" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="HasValueParamAttribute/0" value_param="33" status="run" time="*" classname="Single/ValueParamTest" />
+ <testcase name="HasValueParamAttribute/1" value_param="42" status="run" time="*" classname="Single/ValueParamTest" />
+ <testcase name="AnotherTestThatHasValueParamAttribute/0" value_param="33" status="run" time="*" classname="Single/ValueParamTest" />
+ <testcase name="AnotherTestThatHasValueParamAttribute/1" value_param="42" status="run" time="*" classname="Single/ValueParamTest" />
+ </testsuite>
+ <testsuite name="TypedTest/0" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="TypedTest/0" />
+ </testsuite>
+ <testsuite name="TypedTest/1" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="TypedTest/1" />
+ </testsuite>
+ <testsuite name="Single/TypeParameterizedTestCase/0" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="Single/TypeParameterizedTestCase/0" />
+ </testsuite>
+ <testsuite name="Single/TypeParameterizedTestCase/1" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="Single/TypeParameterizedTestCase/1" />
+ </testsuite>
+</testsuites>""" % {'stack': STACK_TRACE_TEMPLATE}
+
+EXPECTED_FILTERED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" time="*"
+ timestamp="*" name="AllTests" ad_hoc_property="42">
+ <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0"
+ errors="0" time="*">
+ <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
+ </testsuite>
+</testsuites>"""
+
+EXPECTED_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="0" failures="0" disabled="0" errors="0" time="*"
+ timestamp="*" name="AllTests">
+</testsuites>"""
+
+GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME)
+
+SUPPORTS_TYPED_TESTS = 'TypedTest' in gtest_test_utils.Subprocess(
+ [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False).output
+
+
+class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
+ """
+ Unit test for Google Test's XML output functionality.
+ """
+
+ # This test currently breaks on platforms that do not support typed and
+ # type-parameterized tests, so we don't run it under them.
+ if SUPPORTS_TYPED_TESTS:
+ def testNonEmptyXmlOutput(self):
+ """
+ Runs a test program that generates a non-empty XML output, and
+ tests that the XML output is expected.
+ """
+ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1)
+
+ def testEmptyXmlOutput(self):
+ """Verifies XML output for a Google Test binary without actual tests.
+
+ Runs a test program that generates an empty XML output, and
+ tests that the XML output is expected.
+ """
+
+ self._TestXmlOutput('gtest_no_test_unittest', EXPECTED_EMPTY_XML, 0)
+
+ def testTimestampValue(self):
+ """Checks whether the timestamp attribute in the XML output is valid.
+
+ Runs a test program that generates an empty XML output, and checks if
+ the timestamp attribute in the testsuites tag is valid.
+ """
+ actual = self._GetXmlOutput('gtest_no_test_unittest', [], 0)
+ date_time_str = actual.documentElement.getAttributeNode('timestamp').value
+ # datetime.strptime() is only available in Python 2.5+ so we have to
+ # parse the expected datetime manually.
+ match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str)
+ self.assertTrue(
+ re.match,
+ 'XML datettime string %s has incorrect format' % date_time_str)
+ date_time_from_xml = datetime.datetime(
+ year=int(match.group(1)), month=int(match.group(2)),
+ day=int(match.group(3)), hour=int(match.group(4)),
+ minute=int(match.group(5)), second=int(match.group(6)))
+
+ time_delta = abs(datetime.datetime.now() - date_time_from_xml)
+ # timestamp value should be near the current local time
+ self.assertTrue(time_delta < datetime.timedelta(seconds=600),
+ 'time_delta is %s' % time_delta)
+ actual.unlink()
+
+ def testDefaultOutputFile(self):
+ """
+ Confirms that Google Test produces an XML output file with the expected
+ default name if no name is explicitly specified.
+ """
+ output_file = os.path.join(gtest_test_utils.GetTempDir(),
+ GTEST_DEFAULT_OUTPUT_FILE)
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_no_test_unittest')
+ try:
+ os.remove(output_file)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+
+ p = gtest_test_utils.Subprocess(
+ [gtest_prog_path, '%s=xml' % GTEST_OUTPUT_FLAG],
+ working_dir=gtest_test_utils.GetTempDir())
+ self.assert_(p.exited)
+ self.assertEquals(0, p.exit_code)
+ self.assert_(os.path.isfile(output_file))
+
+ def testSuppressedXmlOutput(self):
+ """
+ Tests that no XML file is generated if the default XML listener is
+ shut down before RUN_ALL_TESTS is invoked.
+ """
+
+ xml_path = os.path.join(gtest_test_utils.GetTempDir(),
+ GTEST_PROGRAM_NAME + 'out.xml')
+ if os.path.isfile(xml_path):
+ os.remove(xml_path)
+
+ command = [GTEST_PROGRAM_PATH,
+ '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path),
+ '--shut_down_xml']
+ p = gtest_test_utils.Subprocess(command)
+ if p.terminated_by_signal:
+ # p.signal is avalable only if p.terminated_by_signal is True.
+ self.assertFalse(
+ p.terminated_by_signal,
+ '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal))
+ else:
+ self.assert_(p.exited)
+ self.assertEquals(1, p.exit_code,
+ "'%s' exited with code %s, which doesn't match "
+ 'the expected exit code %s.'
+ % (command, p.exit_code, 1))
+
+ self.assert_(not os.path.isfile(xml_path))
+
+ def testFilteredTestXmlOutput(self):
+ """Verifies XML output when a filter is applied.
+
+ Runs a test program that executes only some tests and verifies that
+ non-selected tests do not show up in the XML output.
+ """
+
+ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_FILTERED_TEST_XML, 0,
+ extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG])
+
+ def _GetXmlOutput(self, gtest_prog_name, extra_args, expected_exit_code):
+ """
+ Returns the xml output generated by running the program gtest_prog_name.
+ Furthermore, the program's exit code must be expected_exit_code.
+ """
+ xml_path = os.path.join(gtest_test_utils.GetTempDir(),
+ gtest_prog_name + 'out.xml')
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name)
+
+ command = ([gtest_prog_path, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path)] +
+ extra_args)
+ p = gtest_test_utils.Subprocess(command)
+ if p.terminated_by_signal:
+ self.assert_(False,
+ '%s was killed by signal %d' % (gtest_prog_name, p.signal))
+ else:
+ self.assert_(p.exited)
+ self.assertEquals(expected_exit_code, p.exit_code,
+ "'%s' exited with code %s, which doesn't match "
+ 'the expected exit code %s.'
+ % (command, p.exit_code, expected_exit_code))
+ actual = minidom.parse(xml_path)
+ return actual
+
+ def _TestXmlOutput(self, gtest_prog_name, expected_xml,
+ expected_exit_code, extra_args=None):
+ """
+ Asserts that the XML document generated by running the program
+ gtest_prog_name matches expected_xml, a string containing another
+ XML document. Furthermore, the program's exit code must be
+ expected_exit_code.
+ """
+
+ actual = self._GetXmlOutput(gtest_prog_name, extra_args or [],
+ expected_exit_code)
+ expected = minidom.parseString(expected_xml)
+ self.NormalizeXml(actual.documentElement)
+ self.AssertEquivalentNodes(expected.documentElement,
+ actual.documentElement)
+ expected.unlink()
+ actual.unlink()
+
+
+if __name__ == '__main__':
+ os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
+ gtest_test_utils.Main()
diff --git a/external/gtest-1.6.0/test/gtest_xml_output_unittest_.cc b/external/gtest-1.6.0/test/gtest_xml_output_unittest_.cc
new file mode 100644
index 0000000..7726551
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_xml_output_unittest_.cc
@@ -0,0 +1,203 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: eefacm at gmail.com (Sean Mcafee)
+
+// Unit test for Google Test XML output.
+//
+// A user can specify XML output in a Google Test program to run via
+// either the GTEST_OUTPUT environment variable or the --gtest_output
+// flag. This is used for testing such functionality.
+//
+// This program will be invoked from a Python unit test. Don't run it
+// directly.
+
+#include "gtest/gtest.h"
+
+using ::testing::InitGoogleTest;
+using ::testing::TestEventListeners;
+using ::testing::TestWithParam;
+using ::testing::UnitTest;
+using ::testing::Test;
+using ::testing::Values;
+
+class SuccessfulTest : public Test
+{
+};
+
+TEST_F(SuccessfulTest, Succeeds)
+{
+ SUCCEED() << "This is a success.";
+ ASSERT_EQ(1, 1);
+}
+
+class FailedTest : public Test
+{
+};
+
+TEST_F(FailedTest, Fails)
+{
+ ASSERT_EQ(1, 2);
+}
+
+class DisabledTest : public Test
+{
+};
+
+TEST_F(DisabledTest, DISABLED_test_not_run)
+{
+ FAIL() << "Unexpected failure: Disabled test should not be run";
+}
+
+TEST(MixedResultTest, Succeeds)
+{
+ EXPECT_EQ(1, 1);
+ ASSERT_EQ(1, 1);
+}
+
+TEST(MixedResultTest, Fails)
+{
+ EXPECT_EQ(1, 2);
+ ASSERT_EQ(2, 3);
+}
+
+TEST(MixedResultTest, DISABLED_test)
+{
+ FAIL() << "Unexpected failure: Disabled test should not be run";
+}
+
+TEST(XmlQuotingTest, OutputsCData)
+{
+ FAIL() << "XML output: "
+ "<?xml encoding=\"utf-8\"><top><![CDATA[cdata text]]></top>";
+}
+
+// Helps to test that invalid characters produced by test code do not make
+// it into the XML file.
+TEST(InvalidCharactersTest, InvalidCharactersInMessage)
+{
+ FAIL() << "Invalid characters in brackets [\x1\x2]";
+}
+
+class PropertyRecordingTest : public Test
+{
+ public:
+ static void SetUpTestCase() { RecordProperty("SetUpTestCase", "yes"); }
+ static void TearDownTestCase() { RecordProperty("TearDownTestCase", "aye"); }
+};
+
+TEST_F(PropertyRecordingTest, OneProperty)
+{
+ RecordProperty("key_1", "1");
+}
+
+TEST_F(PropertyRecordingTest, IntValuedProperty)
+{
+ RecordProperty("key_int", 1);
+}
+
+TEST_F(PropertyRecordingTest, ThreeProperties)
+{
+ RecordProperty("key_1", "1");
+ RecordProperty("key_2", "2");
+ RecordProperty("key_3", "3");
+}
+
+TEST_F(PropertyRecordingTest, TwoValuesForOneKeyUsesLastValue)
+{
+ RecordProperty("key_1", "1");
+ RecordProperty("key_1", "2");
+}
+
+TEST(NoFixtureTest, RecordProperty)
+{
+ RecordProperty("key", "1");
+}
+
+void ExternalUtilityThatCallsRecordProperty(const std::string& key, int value)
+{
+ testing::Test::RecordProperty(key, value);
+}
+
+void ExternalUtilityThatCallsRecordProperty(const std::string& key,
+ const std::string& value)
+{
+ testing::Test::RecordProperty(key, value);
+}
+
+TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty)
+{
+ ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1);
+}
+
+TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty)
+{
+ ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1");
+}
+
+// Verifies that the test parameter value is output in the 'value_param'
+// XML attribute for value-parameterized tests.
+class ValueParamTest : public TestWithParam<int> {};
+TEST_P(ValueParamTest, HasValueParamAttribute) {}
+TEST_P(ValueParamTest, AnotherTestThatHasValueParamAttribute) {}
+INSTANTIATE_TEST_CASE_P(Single, ValueParamTest, Values(33, 42));
+
+#if GTEST_HAS_TYPED_TEST
+// Verifies that the type parameter name is output in the 'type_param'
+// XML attribute for typed tests.
+template <typename T> class TypedTest : public Test {};
+typedef testing::Types<int, long> TypedTestTypes;
+TYPED_TEST_CASE(TypedTest, TypedTestTypes);
+TYPED_TEST(TypedTest, HasTypeParamAttribute) {}
+#endif
+
+#if GTEST_HAS_TYPED_TEST_P
+// Verifies that the type parameter name is output in the 'type_param'
+// XML attribute for type-parameterized tests.
+template <typename T> class TypeParameterizedTestCase : public Test {};
+TYPED_TEST_CASE_P(TypeParameterizedTestCase);
+TYPED_TEST_P(TypeParameterizedTestCase, HasTypeParamAttribute) {}
+REGISTER_TYPED_TEST_CASE_P(TypeParameterizedTestCase, HasTypeParamAttribute);
+typedef testing::Types<int, long> TypeParameterizedTestCaseTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(Single,
+ TypeParameterizedTestCase,
+ TypeParameterizedTestCaseTypes);
+#endif
+
+int main(int argc, char** argv)
+{
+ InitGoogleTest(&argc, argv);
+
+ if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) {
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_xml_generator());
+ }
+ testing::Test::RecordProperty("ad_hoc_property", "42");
+ return RUN_ALL_TESTS();
+}
diff --git a/external/gtest-1.6.0/test/gtest_xml_test_utils.py b/external/gtest-1.6.0/test/gtest_xml_test_utils.py
new file mode 100755
index 0000000..3d0c3b2
--- /dev/null
+++ b/external/gtest-1.6.0/test/gtest_xml_test_utils.py
@@ -0,0 +1,194 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test utilities for gtest_xml_output"""
+
+__author__ = 'eefacm at gmail.com (Sean Mcafee)'
+
+import re
+from xml.dom import minidom, Node
+
+import gtest_test_utils
+
+
+GTEST_OUTPUT_FLAG = '--gtest_output'
+GTEST_DEFAULT_OUTPUT_FILE = 'test_detail.xml'
+
+class GTestXMLTestCase(gtest_test_utils.TestCase):
+ """
+ Base class for tests of Google Test's XML output functionality.
+ """
+
+
+ def AssertEquivalentNodes(self, expected_node, actual_node):
+ """
+ Asserts that actual_node (a DOM node object) is equivalent to
+ expected_node (another DOM node object), in that either both of
+ them are CDATA nodes and have the same value, or both are DOM
+ elements and actual_node meets all of the following conditions:
+
+ * It has the same tag name as expected_node.
+ * It has the same set of attributes as expected_node, each with
+ the same value as the corresponding attribute of expected_node.
+ Exceptions are any attribute named "time", which needs only be
+ convertible to a floating-point number and any attribute named
+ "type_param" which only has to be non-empty.
+ * It has an equivalent set of child nodes (including elements and
+ CDATA sections) as expected_node. Note that we ignore the
+ order of the children as they are not guaranteed to be in any
+ particular order.
+ """
+
+ if expected_node.nodeType == Node.CDATA_SECTION_NODE:
+ self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType)
+ self.assertEquals(expected_node.nodeValue, actual_node.nodeValue)
+ return
+
+ self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType)
+ self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType)
+ self.assertEquals(expected_node.tagName, actual_node.tagName)
+
+ expected_attributes = expected_node.attributes
+ actual_attributes = actual_node .attributes
+ self.assertEquals(
+ expected_attributes.length, actual_attributes.length,
+ 'attribute numbers differ in element %s:\nExpected: %r\nActual: %r' % (
+ actual_node.tagName, expected_attributes.keys(),
+ actual_attributes.keys()))
+ for i in range(expected_attributes.length):
+ expected_attr = expected_attributes.item(i)
+ actual_attr = actual_attributes.get(expected_attr.name)
+ self.assert_(
+ actual_attr is not None,
+ 'expected attribute %s not found in element %s' %
+ (expected_attr.name, actual_node.tagName))
+ self.assertEquals(
+ expected_attr.value, actual_attr.value,
+ ' values of attribute %s in element %s differ: %s vs %s' %
+ (expected_attr.name, actual_node.tagName,
+ expected_attr.value, actual_attr.value))
+
+ expected_children = self._GetChildren(expected_node)
+ actual_children = self._GetChildren(actual_node)
+ self.assertEquals(
+ len(expected_children), len(actual_children),
+ 'number of child elements differ in element ' + actual_node.tagName)
+ for child_id, child in expected_children.iteritems():
+ self.assert_(child_id in actual_children,
+ '<%s> is not in <%s> (in element %s)' %
+ (child_id, actual_children, actual_node.tagName))
+ self.AssertEquivalentNodes(child, actual_children[child_id])
+
+ identifying_attribute = {
+ 'testsuites': 'name',
+ 'testsuite': 'name',
+ 'testcase': 'name',
+ 'failure': 'message',
+ }
+
+ def _GetChildren(self, element):
+ """
+ Fetches all of the child nodes of element, a DOM Element object.
+ Returns them as the values of a dictionary keyed by the IDs of the
+ children. For <testsuites>, <testsuite> and <testcase> elements, the ID
+ is the value of their "name" attribute; for <failure> elements, it is
+ the value of the "message" attribute; CDATA sections and non-whitespace
+ text nodes are concatenated into a single CDATA section with ID
+ "detail". An exception is raised if any element other than the above
+ four is encountered, if two child elements with the same identifying
+ attributes are encountered, or if any other type of node is encountered.
+ """
+
+ children = {}
+ for child in element.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self.assert_(child.tagName in self.identifying_attribute,
+ 'Encountered unknown element <%s>' % child.tagName)
+ childID = child.getAttribute(self.identifying_attribute[child.tagName])
+ self.assert_(childID not in children)
+ children[childID] = child
+ elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]:
+ if 'detail' not in children:
+ if (child.nodeType == Node.CDATA_SECTION_NODE or
+ not child.nodeValue.isspace()):
+ children['detail'] = child.ownerDocument.createCDATASection(
+ child.nodeValue)
+ else:
+ children['detail'].nodeValue += child.nodeValue
+ else:
+ self.fail('Encountered unexpected node type %d' % child.nodeType)
+ return children
+
+ def NormalizeXml(self, element):
+ """
+ Normalizes Google Test's XML output to eliminate references to transient
+ information that may change from run to run.
+
+ * The "time" attribute of <testsuites>, <testsuite> and <testcase>
+ elements is replaced with a single asterisk, if it contains
+ only digit characters.
+ * The "timestamp" attribute of <testsuites> elements is replaced with a
+ single asterisk, if it contains a valid ISO8601 datetime value.
+ * The "type_param" attribute of <testcase> elements is replaced with a
+ single asterisk (if it sn non-empty) as it is the type name returned
+ by the compiler and is platform dependent.
+ * The line info reported in the first line of the "message"
+ attribute and CDATA section of <failure> elements is replaced with the
+ file's basename and a single asterisk for the line number.
+ * The directory names in file paths are removed.
+ * The stack traces are removed.
+ """
+
+ if element.tagName == 'testsuites':
+ timestamp = element.getAttributeNode('timestamp')
+ timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d$',
+ '*', timestamp.value)
+ if element.tagName in ('testsuites', 'testsuite', 'testcase'):
+ time = element.getAttributeNode('time')
+ time.value = re.sub(r'^\d+(\.\d+)?$', '*', time.value)
+ type_param = element.getAttributeNode('type_param')
+ if type_param and type_param.value:
+ type_param.value = '*'
+ elif element.tagName == 'failure':
+ source_line_pat = r'^.*[/\\](.*:)\d+\n'
+ # Replaces the source line information with a normalized form.
+ message = element.getAttributeNode('message')
+ message.value = re.sub(source_line_pat, '\\1*\n', message.value)
+ for child in element.childNodes:
+ if child.nodeType == Node.CDATA_SECTION_NODE:
+ # Replaces the source line information with a normalized form.
+ cdata = re.sub(source_line_pat, '\\1*\n', child.nodeValue)
+ # Removes the actual stack trace.
+ child.nodeValue = re.sub(r'\nStack trace:\n(.|\n)*',
+ '', cdata)
+ for child in element.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self.NormalizeXml(child)
diff --git a/external/gtest-1.6.0/test/production.cc b/external/gtest-1.6.0/test/production.cc
new file mode 100644
index 0000000..8b8a40b
--- /dev/null
+++ b/external/gtest-1.6.0/test/production.cc
@@ -0,0 +1,36 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// This is part of the unit test for include/gtest/gtest_prod.h.
+
+#include "production.h"
+
+PrivateCode::PrivateCode() : x_(0) {}
diff --git a/external/gtest-1.6.0/test/production.h b/external/gtest-1.6.0/test/production.h
new file mode 100644
index 0000000..44c0cd3
--- /dev/null
+++ b/external/gtest-1.6.0/test/production.h
@@ -0,0 +1,56 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// This is part of the unit test for include/gtest/gtest_prod.h.
+
+#ifndef GTEST_TEST_PRODUCTION_H_
+#define GTEST_TEST_PRODUCTION_H_
+
+#include "gtest/gtest_prod.h"
+
+class PrivateCode
+{
+ public:
+ // Declares a friend test that does not use a fixture.
+ FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers);
+
+ // Declares a friend test that uses a fixture.
+ FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers);
+
+ PrivateCode();
+
+ int x() const { return x_; }
+ private:
+ void set_x(int an_x) { x_ = an_x; }
+ int x_;
+};
+
+#endif // GTEST_TEST_PRODUCTION_H_
diff --git a/external/gtest-1.6.0/xcode/Config/DebugProject.xcconfig b/external/gtest-1.6.0/xcode/Config/DebugProject.xcconfig
new file mode 100644
index 0000000..3d68157
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Config/DebugProject.xcconfig
@@ -0,0 +1,30 @@
+//
+// DebugProject.xcconfig
+//
+// These are Debug Configuration project settings for the gtest framework and
+// examples. It is set in the "Based On:" dropdown in the "Project" info
+// dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+#include "General.xcconfig"
+
+// No optimization
+GCC_OPTIMIZATION_LEVEL = 0
+
+// Deployment postprocessing is what triggers Xcode to strip, turn it off
+DEPLOYMENT_POSTPROCESSING = NO
+
+// Dead code stripping off
+DEAD_CODE_STRIPPING = NO
+
+// Debug symbols should be on obviously
+GCC_GENERATE_DEBUGGING_SYMBOLS = YES
+
+// Define the DEBUG macro in all debug builds
+OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1
+
+// These are turned off to avoid STL incompatibilities with client code
+// // Turns on special C++ STL checks to "encourage" good STL use
+// GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS
diff --git a/external/gtest-1.6.0/xcode/Config/FrameworkTarget.xcconfig b/external/gtest-1.6.0/xcode/Config/FrameworkTarget.xcconfig
new file mode 100644
index 0000000..357b1c8
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Config/FrameworkTarget.xcconfig
@@ -0,0 +1,17 @@
+//
+// FrameworkTarget.xcconfig
+//
+// These are Framework target settings for the gtest framework and examples. It
+// is set in the "Based On:" dropdown in the "Target" info dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+// Dynamic libs need to be position independent
+GCC_DYNAMIC_NO_PIC = NO
+
+// Dynamic libs should not have their external symbols stripped.
+STRIP_STYLE = non-global
+
+// Let the user install by specifying the $DSTROOT with xcodebuild
+SKIP_INSTALL = NO
diff --git a/external/gtest-1.6.0/xcode/Config/General.xcconfig b/external/gtest-1.6.0/xcode/Config/General.xcconfig
new file mode 100644
index 0000000..f23e322
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Config/General.xcconfig
@@ -0,0 +1,41 @@
+//
+// General.xcconfig
+//
+// These are General configuration settings for the gtest framework and
+// examples.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+// Build for PPC and Intel, 32- and 64-bit
+ARCHS = i386 x86_64 ppc ppc64
+
+// Zerolink prevents link warnings so turn it off
+ZERO_LINK = NO
+
+// Prebinding considered unhelpful in 10.3 and later
+PREBINDING = NO
+
+// Strictest warning policy
+WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof -Wno-sign-compare -Wshadow
+
+// Work around Xcode bugs by using external strip. See:
+// http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html
+SEPARATE_STRIP = YES
+
+// Force C99 dialect
+GCC_C_LANGUAGE_STANDARD = c99
+
+// not sure why apple defaults this on, but it's pretty risky
+ALWAYS_SEARCH_USER_PATHS = NO
+
+// Turn on position dependent code for most cases (overridden where appropriate)
+GCC_DYNAMIC_NO_PIC = YES
+
+// Default SDK and minimum OS version is 10.4
+SDKROOT = $(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk
+MACOSX_DEPLOYMENT_TARGET = 10.4
+GCC_VERSION = 4.0
+
+// VERSIONING BUILD SETTINGS (used in Info.plist)
+GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc.
diff --git a/external/gtest-1.6.0/xcode/Config/ReleaseProject.xcconfig b/external/gtest-1.6.0/xcode/Config/ReleaseProject.xcconfig
new file mode 100644
index 0000000..5349f0a
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Config/ReleaseProject.xcconfig
@@ -0,0 +1,32 @@
+//
+// ReleaseProject.xcconfig
+//
+// These are Release Configuration project settings for the gtest framework
+// and examples. It is set in the "Based On:" dropdown in the "Project" info
+// dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+#include "General.xcconfig"
+
+// subconfig/Release.xcconfig
+
+// Optimize for space and size (Apple recommendation)
+GCC_OPTIMIZATION_LEVEL = s
+
+// Deploment postprocessing is what triggers Xcode to strip
+DEPLOYMENT_POSTPROCESSING = YES
+
+// No symbols
+GCC_GENERATE_DEBUGGING_SYMBOLS = NO
+
+// Dead code strip does not affect ObjC code but can help for C
+DEAD_CODE_STRIPPING = YES
+
+// NDEBUG is used by things like assert.h, so define it for general compat.
+// ASSERT going away in release tends to create unused vars.
+OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable
+
+// When we strip we want to strip all symbols in release, but save externals.
+STRIP_STYLE = all
diff --git a/external/gtest-1.6.0/xcode/Config/StaticLibraryTarget.xcconfig b/external/gtest-1.6.0/xcode/Config/StaticLibraryTarget.xcconfig
new file mode 100644
index 0000000..3922fa5
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Config/StaticLibraryTarget.xcconfig
@@ -0,0 +1,18 @@
+//
+// StaticLibraryTarget.xcconfig
+//
+// These are static library target settings for libgtest.a. It
+// is set in the "Based On:" dropdown in the "Target" info dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+// Static libs can be included in bundles so make them position independent
+GCC_DYNAMIC_NO_PIC = NO
+
+// Static libs should not have their internal globals or external symbols
+// stripped.
+STRIP_STYLE = debugging
+
+// Let the user install by specifying the $DSTROOT with xcodebuild
+SKIP_INSTALL = NO
diff --git a/external/gtest-1.6.0/xcode/Config/TestTarget.xcconfig b/external/gtest-1.6.0/xcode/Config/TestTarget.xcconfig
new file mode 100644
index 0000000..e6652ba
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Config/TestTarget.xcconfig
@@ -0,0 +1,8 @@
+//
+// TestTarget.xcconfig
+//
+// These are Test target settings for the gtest framework and examples. It
+// is set in the "Based On:" dropdown in the "Target" info dialog.
+
+PRODUCT_NAME = $(TARGET_NAME)
+HEADER_SEARCH_PATHS = ../include
diff --git a/external/gtest-1.6.0/xcode/Resources/Info.plist b/external/gtest-1.6.0/xcode/Resources/Info.plist
new file mode 100644
index 0000000..9dd28ea
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Resources/Info.plist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.${PRODUCT_NAME}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>GTEST_VERSIONINFO_LONG</string>
+ <key>CFBundleShortVersionString</key>
+ <string>GTEST_VERSIONINFO_SHORT</string>
+ <key>CFBundleGetInfoString</key>
+ <string>${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${GTEST_VERSIONINFO_ABOUT}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/external/gtest-1.6.0/xcode/Samples/FrameworkSample/Info.plist b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/Info.plist
new file mode 100644
index 0000000..f3852ed
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gtest.${PRODUCT_NAME:identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/external/gtest-1.6.0/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..497617e
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj
@@ -0,0 +1,457 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 4024D162113D7D2400C7059E /* Test */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */;
+ buildPhases = (
+ 4024D161113D7D2400C7059E /* ShellScript */,
+ );
+ dependencies = (
+ 4024D166113D7D3100C7059E /* PBXTargetDependency */,
+ );
+ name = Test;
+ productName = TestAndBuild;
+ };
+ 4024D1E9113D83FF00C7059E /* TestAndBuild */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 4024D1ED113D840900C7059E /* PBXTargetDependency */,
+ 4024D1EF113D840D00C7059E /* PBXTargetDependency */,
+ );
+ name = TestAndBuild;
+ productName = TestAndBuild;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1230E5AEE3500C7F239 /* widget.cc */; };
+ 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7EB1240E5AEE3500C7F239 /* widget.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */; };
+ 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; };
+ 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D185113D7D5500C7059E /* libgtest.a */; };
+ 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D183113D7D5500C7059E /* libgtest_main.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = gTestExample;
+ };
+ 4024D165113D7D3100C7059E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3B07BDE90E3F3F9E00647869;
+ remoteInfo = WidgetFrameworkTest;
+ };
+ 4024D1EC113D840900C7059E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = WidgetFramework;
+ };
+ 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4024D162113D7D2400C7059E;
+ remoteInfo = Test;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WidgetFrameworkTest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3B7EB1230E5AEE3500C7F239 /* widget.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget.cc; sourceTree = "<group>"; };
+ 3B7EB1240E5AEE3500C7F239 /* widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = widget.h; sourceTree = "<group>"; };
+ 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget_test.cc; sourceTree = "<group>"; };
+ 4024D183113D7D5500C7059E /* libgtest_main.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest_main.a; path = /usr/local/lib/libgtest_main.a; sourceTree = "<absolute>"; };
+ 4024D185113D7D5500C7059E /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest.a; path = /usr/local/lib/libgtest.a; sourceTree = "<absolute>"; };
+ 4024D1E2113D838200C7059E /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = "<group>"; };
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ 8D07F2C80486CC7A007CD1D0 /* Widget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Widget.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 3B07BDE80E3F3F9E00647869 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */,
+ 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */,
+ 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C80486CC7A007CD1D0 /* Widget.framework */,
+ 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* gTestExample */ = {
+ isa = PBXGroup;
+ children = (
+ 4024D1E1113D836C00C7059E /* Scripts */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 089C1665FE841158C02AAC07 /* Resources */,
+ 3B07BE350E4094E400647869 /* Test */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = gTestExample;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 4024D183113D7D5500C7059E /* libgtest_main.a */,
+ 4024D185113D7D5500C7059E /* libgtest.a */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C1665FE841158C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 3B7EB1230E5AEE3500C7F239 /* widget.cc */,
+ 3B7EB1240E5AEE3500C7F239 /* widget.h */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 3B07BE350E4094E400647869 /* Test */ = {
+ isa = PBXGroup;
+ children = (
+ 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */,
+ );
+ name = Test;
+ sourceTree = "<group>";
+ };
+ 4024D1E1113D836C00C7059E /* Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 4024D1E2113D838200C7059E /* runtests.sh */,
+ );
+ name = Scripts;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */;
+ buildPhases = (
+ 3B07BDE70E3F3F9E00647869 /* Sources */,
+ 3B07BDE80E3F3F9E00647869 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */,
+ );
+ name = WidgetFrameworkTest;
+ productName = gTestExampleTest;
+ productReference = 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */;
+ productType = "com.apple.product-type.tool";
+ };
+ 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */;
+ buildPhases = (
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */,
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ 8D07F2C50486CC7A007CD1D0 /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = WidgetFramework;
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = gTestExample;
+ productReference = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* gTestExample */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */,
+ 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */,
+ 4024D162113D7D2400C7059E /* Test */,
+ 4024D1E9113D83FF00C7059E /* TestAndBuild */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8D07F2C50486CC7A007CD1D0 /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 4024D161113D7D2400C7059E /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/bash $SRCROOT/runtests.sh $BUILT_PRODUCTS_DIR/WidgetFrameworkTest\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 3B07BDE70E3F3F9E00647869 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */;
+ targetProxy = 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */;
+ };
+ 4024D166113D7D3100C7059E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */;
+ targetProxy = 4024D165113D7D3100C7059E /* PBXContainerItemProxy */;
+ };
+ 4024D1ED113D840900C7059E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */;
+ targetProxy = 4024D1EC113D840900C7059E /* PBXContainerItemProxy */;
+ };
+ 4024D1EF113D840D00C7059E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4024D162113D7D2400C7059E /* Test */;
+ targetProxy = 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 3B07BDEC0E3F3F9F00647869 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = WidgetFrameworkTest;
+ };
+ name = Debug;
+ };
+ 3B07BDED0E3F3F9F00647869 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = WidgetFrameworkTest;
+ };
+ name = Release;
+ };
+ 4024D163113D7D2400C7059E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Debug;
+ };
+ 4024D164113D7D2400C7059E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Release;
+ };
+ 4024D1EA113D83FF00C7059E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Debug;
+ };
+ 4024D1EB113D83FF00C7059E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Release;
+ };
+ 4FADC24308B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@loader_path/../Frameworks";
+ PRODUCT_NAME = Widget;
+ };
+ name = Debug;
+ };
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@loader_path/../Frameworks";
+ PRODUCT_NAME = Widget;
+ };
+ name = Release;
+ };
+ 4FADC24708B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_VERSION = 4.0;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Debug;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_VERSION = 4.0;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3B07BDEC0E3F3F9F00647869 /* Debug */,
+ 3B07BDED0E3F3F9F00647869 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4024D163113D7D2400C7059E /* Debug */,
+ 4024D164113D7D2400C7059E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4024D1EA113D83FF00C7059E /* Debug */,
+ 4024D1EB113D83FF00C7059E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24308B4156D00ABE55E /* Debug */,
+ 4FADC24408B4156D00ABE55E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24708B4156D00ABE55E /* Debug */,
+ 4FADC24808B4156D00ABE55E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/external/gtest-1.6.0/xcode/Samples/FrameworkSample/runtests.sh b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/runtests.sh
new file mode 100644
index 0000000..4a0d413
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/runtests.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Executes the samples and tests for the Google Test Framework.
+
+# Help the dynamic linker find the path to the libraries.
+export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR
+export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR
+
+# Create some executables.
+test_executables=$@
+
+# Now execute each one in turn keeping track of how many succeeded and failed.
+succeeded=0
+failed=0
+failed_list=()
+for test in ${test_executables[*]}; do
+ "$test"
+ result=$?
+ if [ $result -eq 0 ]; then
+ succeeded=$(( $succeeded + 1 ))
+ else
+ failed=$(( failed + 1 ))
+ failed_list="$failed_list $test"
+ fi
+done
+
+# Report the successes and failures to the console.
+echo "Tests complete with $succeeded successes and $failed failures."
+if [ $failed -ne 0 ]; then
+ echo "The following tests failed:"
+ echo $failed_list
+fi
+exit $failed
diff --git a/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget.cc b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget.cc
new file mode 100644
index 0000000..fd27833
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget.cc
@@ -0,0 +1,67 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: preston.a.jackson at gmail.com (Preston Jackson)
+//
+// Google Test - FrameworkSample
+// widget.cc
+//
+
+// Widget is a very simple class used for demonstrating the use of gtest
+
+#include "widget.h"
+
+Widget::Widget(int number, const std::string& name)
+ : number_(number),
+ name_(name) {}
+
+Widget::~Widget() {}
+
+float Widget::GetFloatValue() const
+{
+ return number_;
+}
+
+int Widget::GetIntValue() const
+{
+ return static_cast<int>(number_);
+}
+
+std::string Widget::GetStringValue() const
+{
+ return name_;
+}
+
+void Widget::GetCharPtrValue(char* buffer, size_t max_size) const
+{
+ // Copy the char* representation of name_ into buffer, up to max_size.
+ strncpy(buffer, name_.c_str(), max_size-1);
+ buffer[max_size-1] = '\0';
+ return;
+}
diff --git a/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget.h b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget.h
new file mode 100644
index 0000000..58bacf4
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget.h
@@ -0,0 +1,60 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: preston.a.jackson at gmail.com (Preston Jackson)
+//
+// Google Test - FrameworkSample
+// widget.h
+//
+
+// Widget is a very simple class used for demonstrating the use of gtest. It
+// simply stores two values a string and an integer, which are returned via
+// public accessors in multiple forms.
+
+#import <string>
+
+class Widget
+{
+ public:
+ Widget(int number, const std::string& name);
+ ~Widget();
+
+ // Public accessors to number data
+ float GetFloatValue() const;
+ int GetIntValue() const;
+
+ // Public accessors to the string data
+ std::string GetStringValue() const;
+ void GetCharPtrValue(char* buffer, size_t max_size) const;
+
+ private:
+ // Data members
+ float number_;
+ std::string name_;
+};
diff --git a/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget_test.cc b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget_test.cc
new file mode 100644
index 0000000..4fdd73a
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Samples/FrameworkSample/widget_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: preston.a.jackson at gmail.com (Preston Jackson)
+//
+// Google Test - FrameworkSample
+// widget_test.cc
+//
+
+// This is a simple test file for the Widget class in the Widget.framework
+
+#include <string>
+#include "gtest/gtest.h"
+
+#include <Widget/widget.h>
+
+// This test verifies that the constructor sets the internal state of the
+// Widget class correctly.
+TEST(WidgetInitializerTest, TestConstructor)
+{
+ Widget widget(1.0f, "name");
+ EXPECT_FLOAT_EQ(1.0f, widget.GetFloatValue());
+ EXPECT_EQ(std::string("name"), widget.GetStringValue());
+}
+
+// This test verifies the conversion of the float and string values to int and
+// char*, respectively.
+TEST(WidgetInitializerTest, TestConversion)
+{
+ Widget widget(1.0f, "name");
+ EXPECT_EQ(1, widget.GetIntValue());
+
+ size_t max_size = 128;
+ char buffer[max_size];
+ widget.GetCharPtrValue(buffer, max_size);
+ EXPECT_STREQ("name", buffer);
+}
+
+// Use the Google Test main that is linked into the framework. It does something
+// like this:
+// int main(int argc, char** argv) {
+// testing::InitGoogleTest(&argc, argv);
+// return RUN_ALL_TESTS();
+// }
diff --git a/external/gtest-1.6.0/xcode/Scripts/runtests.sh b/external/gtest-1.6.0/xcode/Scripts/runtests.sh
new file mode 100644
index 0000000..3fc229f
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Scripts/runtests.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Executes the samples and tests for the Google Test Framework.
+
+# Help the dynamic linker find the path to the libraries.
+export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR
+export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR
+
+# Create some executables.
+test_executables=("$BUILT_PRODUCTS_DIR/gtest_unittest-framework"
+ "$BUILT_PRODUCTS_DIR/gtest_unittest"
+ "$BUILT_PRODUCTS_DIR/sample1_unittest-framework"
+ "$BUILT_PRODUCTS_DIR/sample1_unittest-static")
+
+# Now execute each one in turn keeping track of how many succeeded and failed.
+succeeded=0
+failed=0
+failed_list=()
+for test in ${test_executables[*]}; do
+ "$test"
+ result=$?
+ if [ $result -eq 0 ]; then
+ succeeded=$(( $succeeded + 1 ))
+ else
+ failed=$(( failed + 1 ))
+ failed_list="$failed_list $test"
+ fi
+done
+
+# Report the successes and failures to the console.
+echo "Tests complete with $succeeded successes and $failed failures."
+if [ $failed -ne 0 ]; then
+ echo "The following tests failed:"
+ echo $failed_list
+fi
+exit $failed
diff --git a/external/gtest-1.6.0/xcode/Scripts/versiongenerate.py b/external/gtest-1.6.0/xcode/Scripts/versiongenerate.py
new file mode 100644
index 0000000..81de8c9
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/Scripts/versiongenerate.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""A script to prepare version informtion for use the gtest Info.plist file.
+
+ This script extracts the version information from the configure.ac file and
+ uses it to generate a header file containing the same information. The
+ #defines in this header file will be included in during the generation of
+ the Info.plist of the framework, giving the correct value to the version
+ shown in the Finder.
+
+ This script makes the following assumptions (these are faults of the script,
+ not problems with the Autoconf):
+ 1. The AC_INIT macro will be contained within the first 1024 characters
+ of configure.ac
+ 2. The version string will be 3 integers separated by periods and will be
+ surrounded by squre brackets, "[" and "]" (e.g. [1.0.1]). The first
+ segment represents the major version, the second represents the minor
+ version and the third represents the fix version.
+ 3. No ")" character exists between the opening "(" and closing ")" of
+ AC_INIT, including in comments and character strings.
+"""
+
+import sys
+import re
+
+# Read the command line argument (the output directory for Version.h)
+if (len(sys.argv) < 3):
+ print "Usage: versiongenerate.py input_dir output_dir"
+ sys.exit(1)
+else:
+ input_dir = sys.argv[1]
+ output_dir = sys.argv[2]
+
+# Read the first 1024 characters of the configure.ac file
+config_file = open("%s/configure.ac" % input_dir, 'r')
+buffer_size = 1024
+opening_string = config_file.read(buffer_size)
+config_file.close()
+
+# Extract the version string from the AC_INIT macro
+# The following init_expression means:
+# Extract three integers separated by periods and surrounded by squre
+# brackets(e.g. "[1.0.1]") between "AC_INIT(" and ")". Do not be greedy
+# (*? is the non-greedy flag) since that would pull in everything between
+# the first "(" and the last ")" in the file.
+version_expression = re.compile(r"AC_INIT\(.*?\[(\d+)\.(\d+)\.(\d+)\].*?\)",
+ re.DOTALL)
+version_values = version_expression.search(opening_string)
+major_version = version_values.group(1)
+minor_version = version_values.group(2)
+fix_version = version_values.group(3)
+
+# Write the version information to a header file to be included in the
+# Info.plist file.
+file_data = """//
+// DO NOT MODIFY THIS FILE (but you can delete it)
+//
+// This file is autogenerated by the versiongenerate.py script. This script
+// is executed in a "Run Script" build phase when creating gtest.framework. This
+// header file is not used during compilation of C-source. Rather, it simply
+// defines some version strings for substitution in the Info.plist. Because of
+// this, we are not not restricted to C-syntax nor are we using include guards.
+//
+
+#define GTEST_VERSIONINFO_SHORT %s.%s
+#define GTEST_VERSIONINFO_LONG %s.%s.%s
+
+""" % (major_version, minor_version, major_version, minor_version, fix_version)
+version_file = open("%s/Version.h" % output_dir, 'w')
+version_file.write(file_data)
+version_file.close()
diff --git a/external/gtest-1.6.0/xcode/gtest.xcodeproj/project.pbxproj b/external/gtest-1.6.0/xcode/gtest.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..da6455b
--- /dev/null
+++ b/external/gtest-1.6.0/xcode/gtest.xcodeproj/project.pbxproj
@@ -0,0 +1,1084 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 3B238F5F0E828B5400846E11 /* Check */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */;
+ buildPhases = (
+ 3B238F5E0E828B5400846E11 /* ShellScript */,
+ );
+ dependencies = (
+ 40899F9D0FFA740F000B29AE /* PBXTargetDependency */,
+ 40C849F7101A43440083642A /* PBXTargetDependency */,
+ 4089A0980FFAD34A000B29AE /* PBXTargetDependency */,
+ 40C849F9101A43490083642A /* PBXTargetDependency */,
+ );
+ name = Check;
+ productName = Check;
+ };
+ 40C44ADC0E3798F4008FCC51 /* Version Info */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */;
+ buildPhases = (
+ 40C44ADB0E3798F4008FCC51 /* Generate Version.h */,
+ );
+ comments = "The generation of Version.h must be performed in its own target. Since the Info.plist is preprocessed before any of the other build phases in gtest, the Version.h file would not be ready if included as a build phase of that target.";
+ dependencies = (
+ );
+ name = "Version Info";
+ productName = Version.h;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */ = {isa = PBXBuildFile; fileRef = 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */; };
+ 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DB0E2F799B00CF7658 /* gtest-death-test.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404884390E2F799B00CF7658 /* gtest-message.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DC0E2F799B00CF7658 /* gtest-message.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DD0E2F799B00CF7658 /* gtest-spi.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843B0E2F799B00CF7658 /* gtest.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DE0E2F799B00CF7658 /* gtest.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883E00E2F799B00CF7658 /* gtest_prod.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404884500E2F799B00CF7658 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 404883F60E2F799B00CF7658 /* README */; };
+ 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */; };
+ 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E30E2F799B00CF7658 /* gtest-filepath.h */; };
+ 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E40E2F799B00CF7658 /* gtest-internal.h */; };
+ 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E50E2F799B00CF7658 /* gtest-port.h */; };
+ 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E60E2F799B00CF7658 /* gtest-string.h */; };
+ 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */ = {isa = PBXBuildFile; fileRef = 404884A90E2F7CD900CF7658 /* CHANGES */; };
+ 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */ = {isa = PBXBuildFile; fileRef = 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */; };
+ 404884AE0E2F7CD900CF7658 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 404884AB0E2F7CD900CF7658 /* LICENSE */; };
+ 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; };
+ 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 40899F4D0FFA7271000B29AE /* gtest-tuple.h */; };
+ 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; };
+ 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; };
+ 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; };
+ 40C848FF101A21150083642A /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; };
+ 40C84915101A21DF0083642A /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4048840D0E2F799B00CF7658 /* gtest_main.cc */; };
+ 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C84978101A36540083642A /* libgtest_main.a in Resources */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C84980101A36850083642A /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; };
+ 40C84982101A36850083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; };
+ 40C84983101A36850083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C8498F101A36A60083642A /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; };
+ 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; };
+ 40C84992101A36A60083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; };
+ 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C849A2101A37050083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; };
+ 40C849A4101A37150083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; };
+ 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 4539C9330EC280AE00A70F4C /* gtest-param-test.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */; };
+ 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */; };
+ 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9370EC280E200A70F4C /* gtest-param-util.h */; };
+ 4567C8181264FF71007740BE /* gtest-printers.h in Headers */ = {isa = PBXBuildFile; fileRef = 4567C8171264FF71007740BE /* gtest-printers.h */; settings = {ATTRIBUTES = (Public, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40899F420FFA7184000B29AE;
+ remoteInfo = gtest_unittest;
+ };
+ 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4089A0120FFACEFC000B29AE;
+ remoteInfo = sample1_unittest;
+ };
+ 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C848F9101A209C0083642A;
+ remoteInfo = "gtest-static";
+ };
+ 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C44ADC0E3798F4008FCC51;
+ remoteInfo = Version.h;
+ };
+ 40C8497C101A36850083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C848F9101A209C0083642A;
+ remoteInfo = "gtest-static";
+ };
+ 40C8497E101A36850083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8490A101A217E0083642A;
+ remoteInfo = "gtest_main-static";
+ };
+ 40C8498B101A36A60083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C848F9101A209C0083642A;
+ remoteInfo = "gtest-static";
+ };
+ 40C8498D101A36A60083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8490A101A217E0083642A;
+ remoteInfo = "gtest_main-static";
+ };
+ 40C8499B101A36DC0083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8490A101A217E0083642A;
+ remoteInfo = "gtest_main-static";
+ };
+ 40C8499D101A36E50083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = "gtest-framework";
+ };
+ 40C8499F101A36F10083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = "gtest-framework";
+ };
+ 40C849F6101A43440083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8497A101A36850083642A;
+ remoteInfo = "gtest_unittest-static";
+ };
+ 40C849F8101A43490083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C84989101A36A60083642A;
+ remoteInfo = "sample1_unittest-static";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 404884A50E2F7C0400CF7658 /* Copy Headers Internal */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = Headers/internal;
+ dstSubfolderSpec = 6;
+ files = (
+ 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */,
+ 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */,
+ 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */,
+ 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */,
+ 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */,
+ 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */,
+ 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */,
+ 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */,
+ 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */,
+ 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */,
+ );
+ name = "Copy Headers Internal";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 224A12A10E9EADA700BD17FD /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-all.cc"; sourceTree = "<group>"; };
+ 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "gtest-test-part.h"; sourceTree = "<group>"; };
+ 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_unittest.cc; sourceTree = "<group>"; };
+ 3B87D2100E96B92E000D1852 /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = "<group>"; };
+ 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-type-util.h"; sourceTree = "<group>"; };
+ 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-typed-test.h"; sourceTree = "<group>"; };
+ 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = "<group>"; };
+ 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = "<group>"; };
+ 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = "<group>"; };
+ 404883DD0E2F799B00CF7658 /* gtest-spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-spi.h"; sourceTree = "<group>"; };
+ 404883DE0E2F799B00CF7658 /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest.h; sourceTree = "<group>"; };
+ 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_pred_impl.h; sourceTree = "<group>"; };
+ 404883E00E2F799B00CF7658 /* gtest_prod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_prod.h; sourceTree = "<group>"; };
+ 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test-internal.h"; sourceTree = "<group>"; };
+ 404883E30E2F799B00CF7658 /* gtest-filepath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-filepath.h"; sourceTree = "<group>"; };
+ 404883E40E2F799B00CF7658 /* gtest-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-internal.h"; sourceTree = "<group>"; };
+ 404883E50E2F799B00CF7658 /* gtest-port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-port.h"; sourceTree = "<group>"; };
+ 404883E60E2F799B00CF7658 /* gtest-string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-string.h"; sourceTree = "<group>"; };
+ 404883F60E2F799B00CF7658 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README; path = ../README; sourceTree = SOURCE_ROOT; };
+ 4048840D0E2F799B00CF7658 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_main.cc; sourceTree = "<group>"; };
+ 404884A90E2F7CD900CF7658 /* CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CHANGES; path = ../CHANGES; sourceTree = SOURCE_ROOT; };
+ 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CONTRIBUTORS; path = ../CONTRIBUTORS; sourceTree = SOURCE_ROOT; };
+ 404884AB0E2F7CD900CF7658 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = SOURCE_ROOT; };
+ 40899F430FFA7184000B29AE /* gtest_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gtest_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40899F4D0FFA7271000B29AE /* gtest-tuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-tuple.h"; sourceTree = "<group>"; };
+ 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryTarget.xcconfig; sourceTree = "<group>"; };
+ 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4089A02C0FFACF7F000B29AE /* sample1.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1.cc; sourceTree = "<group>"; };
+ 4089A02D0FFACF7F000B29AE /* sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample1.h; sourceTree = "<group>"; };
+ 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1_unittest.cc; sourceTree = "<group>"; };
+ 40C848FA101A209C0083642A /* libgtest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40C8490B101A217E0083642A /* libgtest_main.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest_main.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40C84987101A36850083642A /* gtest_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gtest_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40C84997101A36A60083642A /* sample1_unittest-static */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-static"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugProject.xcconfig; sourceTree = "<group>"; };
+ 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = "<group>"; };
+ 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = "<group>"; };
+ 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = "<group>"; };
+ 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 4539C8FF0EC27F6400A70F4C /* gtest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = gtest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4539C9330EC280AE00A70F4C /* gtest-param-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-test.h"; sourceTree = "<group>"; };
+ 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-linked_ptr.h"; sourceTree = "<group>"; };
+ 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util-generated.h"; sourceTree = "<group>"; };
+ 4539C9370EC280E200A70F4C /* gtest-param-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util.h"; sourceTree = "<group>"; };
+ 4567C8171264FF71007740BE /* gtest-printers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-printers.h"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 40899F410FFA7184000B29AE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C849A4101A37150083642A /* gtest.framework in Frameworks */,
+ 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4089A0110FFACEFC000B29AE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C849A2101A37050083642A /* gtest.framework in Frameworks */,
+ 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C84981101A36850083642A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84982101A36850083642A /* libgtest.a in Frameworks */,
+ 40C84983101A36850083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C84991101A36A60083642A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84992101A36A60083642A /* libgtest.a in Frameworks */,
+ 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 4539C8FF0EC27F6400A70F4C /* gtest.framework */,
+ 40C848FA101A209C0083642A /* libgtest.a */,
+ 40C8490B101A217E0083642A /* libgtest_main.a */,
+ 40899F430FFA7184000B29AE /* gtest_unittest-framework */,
+ 40C84987101A36850083642A /* gtest_unittest */,
+ 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */,
+ 40C84997101A36A60083642A /* sample1_unittest-static */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* gtest */ = {
+ isa = PBXGroup;
+ children = (
+ 40D4CDF00E30E07400294801 /* Config */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 40D4CF4E0E30F5E200294801 /* Resources */,
+ 403EE37B0E377822004BD1E2 /* Scripts */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = gtest;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 404884A90E2F7CD900CF7658 /* CHANGES */,
+ 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */,
+ 404884AB0E2F7CD900CF7658 /* LICENSE */,
+ 404883F60E2F799B00CF7658 /* README */,
+ 404883D90E2F799B00CF7658 /* include */,
+ 4089A02F0FFACF84000B29AE /* samples */,
+ 404884070E2F799B00CF7658 /* src */,
+ 3B238BF00E7FE13B00846E11 /* test */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 3B238BF00E7FE13B00846E11 /* test */ = {
+ isa = PBXGroup;
+ children = (
+ 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */,
+ );
+ name = test;
+ path = ../test;
+ sourceTree = SOURCE_ROOT;
+ };
+ 403EE37B0E377822004BD1E2 /* Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 403EE37C0E377822004BD1E2 /* versiongenerate.py */,
+ 3B87D2100E96B92E000D1852 /* runtests.sh */,
+ );
+ path = Scripts;
+ sourceTree = "<group>";
+ };
+ 404883D90E2F799B00CF7658 /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 404883DA0E2F799B00CF7658 /* gtest */,
+ );
+ name = include;
+ path = ../include;
+ sourceTree = SOURCE_ROOT;
+ };
+ 404883DA0E2F799B00CF7658 /* gtest */ = {
+ isa = PBXGroup;
+ children = (
+ 404883E10E2F799B00CF7658 /* internal */,
+ 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */,
+ 404883DB0E2F799B00CF7658 /* gtest-death-test.h */,
+ 404883DC0E2F799B00CF7658 /* gtest-message.h */,
+ 4539C9330EC280AE00A70F4C /* gtest-param-test.h */,
+ 4567C8171264FF71007740BE /* gtest-printers.h */,
+ 404883DD0E2F799B00CF7658 /* gtest-spi.h */,
+ 404883DE0E2F799B00CF7658 /* gtest.h */,
+ 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */,
+ 404883E00E2F799B00CF7658 /* gtest_prod.h */,
+ 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */,
+ );
+ path = gtest;
+ sourceTree = "<group>";
+ };
+ 404883E10E2F799B00CF7658 /* internal */ = {
+ isa = PBXGroup;
+ children = (
+ 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */,
+ 404883E30E2F799B00CF7658 /* gtest-filepath.h */,
+ 404883E40E2F799B00CF7658 /* gtest-internal.h */,
+ 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */,
+ 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */,
+ 4539C9370EC280E200A70F4C /* gtest-param-util.h */,
+ 404883E50E2F799B00CF7658 /* gtest-port.h */,
+ 404883E60E2F799B00CF7658 /* gtest-string.h */,
+ 40899F4D0FFA7271000B29AE /* gtest-tuple.h */,
+ 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */,
+ );
+ path = internal;
+ sourceTree = "<group>";
+ };
+ 404884070E2F799B00CF7658 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 224A12A10E9EADA700BD17FD /* gtest-all.cc */,
+ 4048840D0E2F799B00CF7658 /* gtest_main.cc */,
+ );
+ name = src;
+ path = ../src;
+ sourceTree = SOURCE_ROOT;
+ };
+ 4089A02F0FFACF84000B29AE /* samples */ = {
+ isa = PBXGroup;
+ children = (
+ 4089A02C0FFACF7F000B29AE /* sample1.cc */,
+ 4089A02D0FFACF7F000B29AE /* sample1.h */,
+ 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */,
+ );
+ name = samples;
+ path = ../samples;
+ sourceTree = SOURCE_ROOT;
+ };
+ 40D4CDF00E30E07400294801 /* Config */ = {
+ isa = PBXGroup;
+ children = (
+ 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */,
+ 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */,
+ 40D4CDF30E30E07400294801 /* General.xcconfig */,
+ 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */,
+ 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */,
+ );
+ path = Config;
+ sourceTree = "<group>";
+ };
+ 40D4CF4E0E30F5E200294801 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 40D4CF510E30F5E200294801 /* Info.plist */,
+ );
+ path = Resources;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */,
+ 404884390E2F799B00CF7658 /* gtest-message.h in Headers */,
+ 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */,
+ 4567C8181264FF71007740BE /* gtest-printers.h in Headers */,
+ 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */,
+ 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */,
+ 4048843B0E2F799B00CF7658 /* gtest.h in Headers */,
+ 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */,
+ 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */,
+ 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 40899F420FFA7184000B29AE /* gtest_unittest-framework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */;
+ buildPhases = (
+ 40899F400FFA7184000B29AE /* Sources */,
+ 40899F410FFA7184000B29AE /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C849A0101A36F10083642A /* PBXTargetDependency */,
+ );
+ name = "gtest_unittest-framework";
+ productName = gtest_unittest;
+ productReference = 40899F430FFA7184000B29AE /* gtest_unittest-framework */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */;
+ buildPhases = (
+ 4089A0100FFACEFC000B29AE /* Sources */,
+ 4089A0110FFACEFC000B29AE /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C8499E101A36E50083642A /* PBXTargetDependency */,
+ );
+ name = "sample1_unittest-framework";
+ productName = sample1_unittest;
+ productReference = 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */;
+ productType = "com.apple.product-type.tool";
+ };
+ 40C848F9101A209C0083642A /* gtest-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */;
+ buildPhases = (
+ 40C848F7101A209C0083642A /* Sources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "gtest-static";
+ productName = "gtest-static";
+ productReference = 40C848FA101A209C0083642A /* libgtest.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 40C8490A101A217E0083642A /* gtest_main-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */;
+ buildPhases = (
+ 40C84908101A217E0083642A /* Sources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "gtest_main-static";
+ productName = "gtest_main-static";
+ productReference = 40C8490B101A217E0083642A /* libgtest_main.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 40C8497A101A36850083642A /* gtest_unittest-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */;
+ buildPhases = (
+ 40C8497F101A36850083642A /* Sources */,
+ 40C84981101A36850083642A /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C8497B101A36850083642A /* PBXTargetDependency */,
+ 40C8497D101A36850083642A /* PBXTargetDependency */,
+ );
+ name = "gtest_unittest-static";
+ productName = gtest_unittest;
+ productReference = 40C84987101A36850083642A /* gtest_unittest */;
+ productType = "com.apple.product-type.tool";
+ };
+ 40C84989101A36A60083642A /* sample1_unittest-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */;
+ buildPhases = (
+ 40C8498E101A36A60083642A /* Sources */,
+ 40C84991101A36A60083642A /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C8498A101A36A60083642A /* PBXTargetDependency */,
+ 40C8498C101A36A60083642A /* PBXTargetDependency */,
+ );
+ name = "sample1_unittest-static";
+ productName = sample1_unittest;
+ productReference = 40C84997101A36A60083642A /* sample1_unittest-static */;
+ productType = "com.apple.product-type.tool";
+ };
+ 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */;
+ buildPhases = (
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 404884A50E2F7C0400CF7658 /* Copy Headers Internal */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C44AE60E379922008FCC51 /* PBXTargetDependency */,
+ 408BEC101046CFE900DEF522 /* PBXTargetDependency */,
+ 40C8499C101A36DC0083642A /* PBXTargetDependency */,
+ );
+ name = "gtest-framework";
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = gtest;
+ productReference = 4539C8FF0EC27F6400A70F4C /* gtest.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ en,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* gtest */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */,
+ 40C848F9101A209C0083642A /* gtest-static */,
+ 40C8490A101A217E0083642A /* gtest_main-static */,
+ 40899F420FFA7184000B29AE /* gtest_unittest-framework */,
+ 40C8497A101A36850083642A /* gtest_unittest-static */,
+ 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */,
+ 40C84989101A36A60083642A /* sample1_unittest-static */,
+ 3B238F5F0E828B5400846E11 /* Check */,
+ 40C44ADC0E3798F4008FCC51 /* Version Info */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 404884500E2F799B00CF7658 /* README in Resources */,
+ 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */,
+ 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */,
+ 404884AE0E2F7CD900CF7658 /* LICENSE in Resources */,
+ 40C84978101A36540083642A /* libgtest_main.a in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B238F5E0E828B5400846E11 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/bin/bash Scripts/runtests.sh";
+ };
+ 40C44ADB0E3798F4008FCC51 /* Generate Version.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/Scripts/versiongenerate.py",
+ "$(SRCROOT)/../configure.ac",
+ );
+ name = "Generate Version.h";
+ outputPaths = (
+ "$(PROJECT_TEMP_DIR)/Version.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/usr/bin/python Scripts/versiongenerate.py ../ $PROJECT_TEMP_DIR";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 40899F400FFA7184000B29AE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4089A0100FFACEFC000B29AE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */,
+ 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C848F7101A209C0083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C848FF101A21150083642A /* gtest-all.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C84908101A217E0083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84915101A21DF0083642A /* gtest_main.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C8497F101A36850083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84980101A36850083642A /* gtest_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C8498E101A36A60083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C8498F101A36A60083642A /* sample1.cc in Sources */,
+ 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 40899F9D0FFA740F000B29AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40899F420FFA7184000B29AE /* gtest_unittest-framework */;
+ targetProxy = 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */;
+ };
+ 4089A0980FFAD34A000B29AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */;
+ targetProxy = 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */;
+ };
+ 408BEC101046CFE900DEF522 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C848F9101A209C0083642A /* gtest-static */;
+ targetProxy = 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */;
+ };
+ 40C44AE60E379922008FCC51 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C44ADC0E3798F4008FCC51 /* Version Info */;
+ targetProxy = 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */;
+ };
+ 40C8497B101A36850083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C848F9101A209C0083642A /* gtest-static */;
+ targetProxy = 40C8497C101A36850083642A /* PBXContainerItemProxy */;
+ };
+ 40C8497D101A36850083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8490A101A217E0083642A /* gtest_main-static */;
+ targetProxy = 40C8497E101A36850083642A /* PBXContainerItemProxy */;
+ };
+ 40C8498A101A36A60083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C848F9101A209C0083642A /* gtest-static */;
+ targetProxy = 40C8498B101A36A60083642A /* PBXContainerItemProxy */;
+ };
+ 40C8498C101A36A60083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8490A101A217E0083642A /* gtest_main-static */;
+ targetProxy = 40C8498D101A36A60083642A /* PBXContainerItemProxy */;
+ };
+ 40C8499C101A36DC0083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8490A101A217E0083642A /* gtest_main-static */;
+ targetProxy = 40C8499B101A36DC0083642A /* PBXContainerItemProxy */;
+ };
+ 40C8499E101A36E50083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */;
+ targetProxy = 40C8499D101A36E50083642A /* PBXContainerItemProxy */;
+ };
+ 40C849A0101A36F10083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */;
+ targetProxy = 40C8499F101A36F10083642A /* PBXContainerItemProxy */;
+ };
+ 40C849F7101A43440083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8497A101A36850083642A /* gtest_unittest-static */;
+ targetProxy = 40C849F6101A43440083642A /* PBXContainerItemProxy */;
+ };
+ 40C849F9101A43490083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C84989101A36A60083642A /* sample1_unittest-static */;
+ targetProxy = 40C849F8101A43490083642A /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 3B238F600E828B5400846E11 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = Check;
+ };
+ name = Debug;
+ };
+ 3B238F610E828B5400846E11 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = Check;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 40899F450FFA7185000B29AE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = ../;
+ PRODUCT_NAME = "gtest_unittest-framework";
+ };
+ name = Debug;
+ };
+ 40899F460FFA7185000B29AE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = ../;
+ PRODUCT_NAME = "gtest_unittest-framework";
+ };
+ name = Release;
+ };
+ 4089A0150FFACEFD000B29AE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-framework";
+ };
+ name = Debug;
+ };
+ 4089A0160FFACEFD000B29AE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-framework";
+ };
+ name = Release;
+ };
+ 40C44ADF0E3798F4008FCC51 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest;
+ TARGET_NAME = gtest;
+ };
+ name = Debug;
+ };
+ 40C44AE00E3798F4008FCC51 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest;
+ TARGET_NAME = gtest;
+ };
+ name = Release;
+ };
+ 40C848FB101A209D0083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ HEADER_SEARCH_PATHS = (
+ ../,
+ ../include/,
+ );
+ PRODUCT_NAME = gtest;
+ };
+ name = Debug;
+ };
+ 40C848FC101A209D0083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ HEADER_SEARCH_PATHS = (
+ ../,
+ ../include/,
+ );
+ PRODUCT_NAME = gtest;
+ };
+ name = Release;
+ };
+ 40C8490E101A217F0083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ ../,
+ ../include/,
+ );
+ PRODUCT_NAME = gtest_main;
+ };
+ name = Debug;
+ };
+ 40C8490F101A217F0083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ ../,
+ ../include/,
+ );
+ PRODUCT_NAME = gtest_main;
+ };
+ name = Release;
+ };
+ 40C84985101A36850083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = ../;
+ PRODUCT_NAME = gtest_unittest;
+ };
+ name = Debug;
+ };
+ 40C84986101A36850083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = ../;
+ PRODUCT_NAME = gtest_unittest;
+ };
+ name = Release;
+ };
+ 40C84995101A36A60083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-static";
+ };
+ name = Debug;
+ };
+ 40C84996101A36A60083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-static";
+ };
+ name = Release;
+ };
+ 4FADC24308B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ HEADER_SEARCH_PATHS = (
+ ../,
+ ../include/,
+ );
+ INFOPLIST_FILE = Resources/Info.plist;
+ INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h";
+ INFOPLIST_PREPROCESS = YES;
+ PRODUCT_NAME = gtest;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ HEADER_SEARCH_PATHS = (
+ ../,
+ ../include/,
+ );
+ INFOPLIST_FILE = Resources/Info.plist;
+ INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h";
+ INFOPLIST_PREPROCESS = YES;
+ PRODUCT_NAME = gtest;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ 4FADC24708B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3B238F600E828B5400846E11 /* Debug */,
+ 3B238F610E828B5400846E11 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40899F450FFA7185000B29AE /* Debug */,
+ 40899F460FFA7185000B29AE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4089A0150FFACEFD000B29AE /* Debug */,
+ 4089A0160FFACEFD000B29AE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C44ADF0E3798F4008FCC51 /* Debug */,
+ 40C44AE00E3798F4008FCC51 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C848FB101A209D0083642A /* Debug */,
+ 40C848FC101A209D0083642A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C8490E101A217F0083642A /* Debug */,
+ 40C8490F101A217F0083642A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C84985101A36850083642A /* Debug */,
+ 40C84986101A36850083642A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C84995101A36A60083642A /* Debug */,
+ 40C84996101A36A60083642A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24308B4156D00ABE55E /* Debug */,
+ 4FADC24408B4156D00ABE55E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24708B4156D00ABE55E /* Debug */,
+ 4FADC24808B4156D00ABE55E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/extras/README.md b/extras/README.md
new file mode 100644
index 0000000..36aceb4
--- /dev/null
+++ b/extras/README.md
@@ -0,0 +1,26 @@
+# Additional resources
+
+
+## Cheatsheet
+
+A short reference for the use of the library can be generated by executing
+`make` in the [cheatsheet](./cheatsheet) directory.
+
+
+## Debugging
+
+Sometimes even the best coder produces bugs. For this case we provide a
+useful resource for the [GNU Debugger][gdb].
+Copy the content of `sdsl.gdb` into your .gdbinit file an you can display the
+elements of `sdsl::vector<>` (and `sdsl::bitvector`) with the command `pv` in
+gdb.
+
+## Code style
+
+The install script will copy the [pre-commit](./pre-commit) file into the
+`.git/hooks` directory of your library clone. It will run [astyle][as]
+before code gets committed. Please make sure that you have it installed
+[astyle][as], if you plan to push your changes to the project.
+
+[gdb]: http://www.gnu.org/software/gdb/ "GDB: The GNU Project Debugger"
+[as]: http://astyle.sourceforge.net/ "Astyle"
diff --git a/extras/cheatsheet/.gitignore b/extras/cheatsheet/.gitignore
new file mode 100644
index 0000000..8ba13fd
--- /dev/null
+++ b/extras/cheatsheet/.gitignore
@@ -0,0 +1,6 @@
+*
+!.gitignore
+!Makefile
+!sdsl-cheatsheet.tex
+!hyperendnotes.sty
+!viz.pdf
diff --git a/extras/cheatsheet/Makefile b/extras/cheatsheet/Makefile
new file mode 100644
index 0000000..1cd04e9
--- /dev/null
+++ b/extras/cheatsheet/Makefile
@@ -0,0 +1,7 @@
+
+sdsl-cheatsheet.pdf: sdsl-cheatsheet.tex
+ pdflatex sdsl-cheatsheet.tex
+
+clean:
+ rm -f sdsl-cheatsheet.pdf \
+ sdsl-cheatsheet.aux
diff --git a/extras/cheatsheet/hyperendnotes.sty b/extras/cheatsheet/hyperendnotes.sty
new file mode 100644
index 0000000..a6cf2fb
--- /dev/null
+++ b/extras/cheatsheet/hyperendnotes.sty
@@ -0,0 +1,156 @@
+%%% hyperendnotes.sty
+\makeatletter
+\newif\ifenotelinks
+\newcounter{Hendnote}
+% Redefining portions of endnotes-package:
+\let\savedhref\href
+\let\savedurl\url
+\def\endnotemark{%
+\@ifnextchar[\@xendnotemark{%
+\stepcounter{endnote}%
+\protected at xdef\@theenmark{\theendnote}%
+\protected at xdef\@theenvalue{\number\c at endnote}%
+\@endnotemark
+}%
+}%
+\def\@xendnotemark[#1]{%
+\begingroup\c at endnote#1\relax
+\unrestored at protected@xdef\@theenmark{\theendnote}%
+\unrestored at protected@xdef\@theenvalue{\number\c at endnote}%
+\endgroup
+\@endnotemark
+}%
+\def\endnotetext{%
+\@ifnextchar[\@xendnotenext{%
+\protected at xdef\@theenmark{\theendnote}%
+\protected at xdef\@theenvalue{\number\c at endnote}%
+\@endnotetext
+}%
+}%
+\def\@xendnotenext[#1]{%
+\begingroup
+\c at endnote=#1\relax
+\unrestored at protected@xdef\@theenmark{\theendnote}%
+\unrestored at protected@xdef\@theenvalue{\number\c at endnote}%
+\endgroup
+\@endnotetext
+}%
+\def\endnote{%
+\@ifnextchar[\@xendnote{%
+\stepcounter{endnote}%
+\protected at xdef\@theenmark{\theendnote}%
+\protected at xdef\@theenvalue{\number\c at endnote}%
+\@endnotemark\@endnotetext
+}%
+}%
+\def\@xendnote[#1]{%
+\begingroup
+\c at endnote=#1\relax
+\unrestored at protected@xdef\@theenmark{\theendnote}%
+\unrestored at protected@xdef\@theenvalue{\number\c at endnote}%
+\show\@theenvalue
+\endgroup
+\@endnotemark\@endnotetext
+}%
+\def\@endnotemark{%
+\leavevmode
+\ifhmode
+\edef\@x at sf{\the\spacefactor}\nobreak
+\fi
+\ifenotelinks
+\expandafter\@firstofone
+\else
+\expandafter\@gobble
+\fi
+{%
+\Hy at raisedlink{%
+\hyper@@anchor{Hendnotepage.\@theenvalue}{\empty}%
+}%
+}%
+\hyper at linkstart{link}{Hendnote.\@theenvalue}%
+\makeenmark
+\hyper at linkend
+\ifhmode
+\spacefactor\@x at sf
+\fi
+\relax
+}%
+\long\def\@endnotetext#1{%
+\if at enotesopen
+\else
+\@openenotes
+\fi
+\immediate\write\@enotes{%
+\@doanenote{\@theenmark}{\@theenvalue}%
+}%
+\begingroup
+\def\next{#1}%
+\newlinechar='40
+\immediate\write\@enotes{\meaning\next}%
+\endgroup
+\immediate\write\@enotes{%
+\@endanenote
+}%
+}%
+\def\theendnotes{%
+\immediate\closeout\@enotes
+\global\@enotesopenfalse
+\begingroup
+\makeatletter
+\edef\@tempa{`\string>}%
+\ifnum\catcode\@tempa=12
+\let\@ResetGT\relax
+\else
+\edef\@ResetGT{\noexpand\catcode\@tempa=\the\catcode\@tempa}%
+\@makeother\>%
+\fi
+\def\@doanenote##1##2##3>{%
+\def\@theenmark{##1}%
+\def\@theenvalue{##2}%
+\par
+\smallskip %<-small vertical gap between endnotes
+\begingroup
+\def\href{\expandafter\savedhref}%
+\def\url{\expandafter\savedurl}%
+\@ResetGT
+\edef\@currentlabel{\csname p at endnote\endcsname\@theenmark}%
+\enoteformat
+}%
+\def\@endanenote{%
+\par\endgroup
+}%
+% Redefine, how numbers are formatted in the endnotes-section:
+\renewcommand*\@makeenmark{%
+\hbox{\normalfont\@theenmark~}%
+}%
+% header of endnotes-section
+\enoteheading
+% font-size of endnotes
+\enotesize
+\input{\jobname.ent}%
+\endgroup
+}%
+\def\enoteformat{%
+\rightskip\z@
+\leftskip1.8em
+\parindent\z@
+\leavevmode\llap{%
+\setcounter{Hendnote}{\@theenvalue}%
+\addtocounter{Hendnote}{-1}%
+\refstepcounter{Hendnote}%
+\ifenotelinks
+\expandafter\@secondoftwo
+\else
+\expandafter\@firstoftwo
+\fi
+{\@firstofone}%
+{\hyperlink{Hendnotepage.\@theenvalue}}%
+{\makeenmark}%
+}%
+}%
+% stop redefining portions of endnotes-package:
+\makeatother
+% Toggle switch in order to turn on/off back-links in the
+% endnote-section:
+\enotelinkstrue
+%\enotelinksfalse
diff --git a/extras/cheatsheet/sdsl-cheatsheet.tex b/extras/cheatsheet/sdsl-cheatsheet.tex
new file mode 100644
index 0000000..41f1b25
--- /dev/null
+++ b/extras/cheatsheet/sdsl-cheatsheet.tex
@@ -0,0 +1,774 @@
+\documentclass[10pt,landscape]{article}
+% next two lines required for sdsl command
+\usepackage[T1]{fontenc}
+\newcommand{\changefont}[3]{\fontfamily{#1}\fontseries{#2}\fontshape{#3}\selectfont}
+\usepackage{amsfonts}
+
+\usepackage{color}
+\usepackage{multicol}
+\usepackage{calc}
+\usepackage{ifthen}
+\usepackage[landscape]{geometry}
+
+\usepackage{amsmath}
+\usepackage[colorlinks]{hyperref}
+\usepackage{xcolor}
+
+
+\usepackage{tikz}
+\usepackage{endnotes} % see http://tex.stackexchange.com/questions/56145/is-there-a-way-to-move-all-footnotes-to-the-end-of-the-document
+\usepackage{hyperendnotes} % see http://tex.stackexchange.com/questions/8452/making-endnotes-clickable-links-with-hyperref
+\let\footnote=\endnote
+
+\definecolor{githublink}{HTML}{4183c4}
+
+% TODO: Add header information for classes:
+% Almost done, since abbreviations contain link to header
+%
+
+\hypersetup{
+bookmarks=true, % show bookmarks bar?
+unicode=false, % non-Latin characters in Acrobat’s bookmarks
+pdftoolbar=true, % show Acrobat’s toolbar?
+pdfmenubar=true, % show Acrobat’s menu?
+pdffitwindow=false, % window fit to page when opened
+pdfstartview={FitH}, % fits the width of the page to the window
+pdftitle={sdsl cheat sheet}, % title
+pdfauthor={Simon Gog}, % author
+pdfsubject={sdsl short reference}, % subject of the document
+pdfcreator={Creator}, % creator of the document
+pdfproducer={Producer}, % producer of the document
+pdfkeywords={keyword1} {key2} {key3}, % list of keywords
+pdfnewwindow=true, % links in new window
+colorlinks=true, % false: boxed links; true: colored links
+linkcolor=red, % color of internal links (change box color with linkbordercolor)
+citecolor=green, % color of links to bibliography
+filecolor=magenta, % color of file links
+urlcolor=githublink % color of external links
+}
+% link color #4183c4
+% To make this come out properly in landscape mode, do one of the following
+% 1.
+% pdflatex latexsheet.tex
+%
+% 2.
+% latex latexsheet.tex
+% dvips -P pdf -t landscape latexsheet.dvi
+% ps2pdf latexsheet.ps
+
+
+% If you're reading this, be prepared for confusion. Making this was
+% a learning experience for me, and it shows. Much of the placement
+% was hacked in; if you make it better, let me know...
+
+
+% 2008-04
+% Changed page margin code to use the geometry package. Also added code for
+% conditional page margins, depending on paper size. Thanks to Uwe Ziegenhagen
+% for the suggestions.
+
+% 2006-08
+% Made changes based on suggestions from Gene Cooperman. <gene at ccs.neu.edu>
+
+
+% To Do:
+% \listoffigures \listoftables
+% \setcounter{secnumdepth}{0}
+
+
+% This sets page margins to .5 inch if using letter paper, and to 1cm
+% if using A4 paper. (This probably isn't strictly necessary.)
+% If using another size paper, use default 1cm margins.
+\ifthenelse{\lengthtest { \paperwidth = 11in}}
+ { \geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} }
+ {\ifthenelse{ \lengthtest{ \paperwidth = 297mm}}
+ {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
+ {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
+ }
+
+% Turn off header and footer
+\pagestyle{empty}
+
+
+% Redefine section commands to use less space
+\makeatletter
+\renewcommand{\section}{\@startsection{section}{1}{0mm}%
+ {-1ex plus -.5ex minus -.2ex}%
+ {0.5ex plus .2ex}%x
+ {\normalfont\large\bfseries}}
+\renewcommand{\subsection}{\@startsection{subsection}{2}{0mm}%
+ {-1explus -.5ex minus -.2ex}%
+ {0.5ex plus .2ex}%
+ {\normalfont\normalsize\bfseries}}
+\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{0mm}%
+ {-1ex plus -.5ex minus -.2ex}%
+ {1ex plus .2ex}%
+ {\normalfont\small\bfseries}}
+\makeatother
+
+% Define BibTeX command
+\def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em
+ T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}}
+
+% Don't print section numbers
+\setcounter{secnumdepth}{0}
+
+
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{0pt plus 0.5ex}
+
+% -----------------------------------------------------------------------
+
+\DeclareMathOperator*{\argmin}{arg\!\min}
+
+\begin{document}
+\newlength{\MyLen}
+\newlength{\MidLen}
+
+\raggedright
+\footnotesize
+\begin{multicols}{3}
+
+
+% multicol parameters
+% These lengths are set only within the two main columns
+%\setlength{\columnseprule}{0.25pt}
+\setlength{\premulticols}{1pt}
+\setlength{\postmulticols}{1pt}
+\setlength{\multicolsep}{1pt}
+\setlength{\columnsep}{2pt}
+
+\newcommand{\Order}[1]{\ensuremath{{\mathcal O}(#1)}}
+
+
+\newcommand{\sdslgit}{https://github.com/simongog/sdsl-lite/blob/master}
+\newcommand{\sdslgitinc}{\sdslgit/include/sdsl}
+\newcommand{\pizzachili}{http://pizzachili.di.unipi.it/texts.html}
+\newcommand{\code}[1]{\texttt{#1}}
+
+%\newcommand{\sdsl}{\ensuremath{\mathit{sdsl}}}
+\newcommand{\sdsl}{%
+{\changefont{cmss}{bx}{n}\href{\sdslgit}{sdsl}%
+}%\changefont{cmr}{m}{n}%
+}
+%%% int vector representations
+\newcommand{\sdslintvector}{\code{int\_vector}}
+\newcommand{\sdslintvectorZ}{\code{int\_vector\textless\textgreater}}
+\newcommand{\sdslencvector}{\code{enc\_vector}}
+\newcommand{\sdslvlcvector}{\code{vlc\_vector}}
+\newcommand{\sdsldacvector}{\code{dac\_vector}}
+%%% coder
+\newcommand{\sdslcodereliasdelta}{\code{coder::elias\_delta}}
+\newcommand{\sdslcodereliasgamma}{\code{coder::elias\_gamma}}
+\newcommand{\sdslcoderfibonacci}{\code{coder::fibonacci}}
+%%% bit vector representations
+\newcommand{\sdslbitvector}{\code{bit\_vector}}
+\newcommand{\sdslbitvectoril}{\code{bit\_vector\_il}}
+\newcommand{\sdslrrrvector}{\code{rrr\_vector}}
+\newcommand{\sdslsdvector}{\code{sd\_vector}}
+%%%% rank support structures
+\newcommand{\sdslranksupportv}{\code{rank\_support\_v}}
+\newcommand{\sdslranksupportvV}{\code{rank\_support\_v5}}
+\newcommand{\sdslranksupportil}{\code{rank\_support\_il}}
+\newcommand{\sdslranksupportrrr}{\code{rank\_support\_rrr}}
+\newcommand{\sdslranksupportsd}{\code{rank\_support\_sd}}
+\newcommand{\sdslranksupportscan}{\code{rank\_support\_scan}}
+%%%% select support structures
+\newcommand{\sdslselectsupportmcl}{\code{select\_support\_mcl}}
+\newcommand{\sdslselectsupportscan}{\code{select\_support\_scan}}
+\newcommand{\sdslselectsupportil}{\code{select\_support\_il}}
+\newcommand{\sdslselectsupportrrr}{\code{select\_support\_rrr}}
+\newcommand{\sdslselectsupportsd}{\code{select\_support\_sd}}
+%%%% WTs
+\newcommand{\sdslwthuff}{\code{wt\_huff}}
+\newcommand{\sdslwthutu}{\code{wt\_hutu}}
+\newcommand{\sdslwtblcd}{\code{wt\_blcd}}
+\newcommand{\sdslwtint}{\code{wt\_int}}
+\newcommand{\sdslwmint}{\code{wm\_int}}
+\newcommand{\sdslwtgmr}{\code{wt\_gmr}}
+\newcommand{\sdslwtrlmn}{\code{wt\_rlmn}}
+%%%% CSAs
+\newcommand{\sdslcsabitcompressed}{\code{csa\_bitcompressed}}
+\newcommand{\sdslcsasada}{\code{csa\_sada}}
+\newcommand{\sdslcsawt}{\code{csa\_wt}}
+%%%% Alphabet strategy (policy parametrization see Stroustrup C++ 24.4.1)
+\newcommand{\sdslbytealphabetstrategy}{\code{byte\_alphabet}}
+\newcommand{\sdslsuccinctbytealphabetstrategy}{\code{succinct\_byte\_alphabet}}
+\newcommand{\sdslintalphabetstrategy}{\code{int\_alphabet}}
+%%%% Alphabet strategy (policy parametrization see Stroustrup C++ 24.4.1)
+\newcommand{\sdslsaordersasampling}{\code{sa\_order\_sa\_sampling}}
+\newcommand{\sdsltextordersasampling}{\code{text\_order\_sa\_sampling}}
+
+%%%% LCPs
+\newcommand{\sdsllcpbitcompressed}{\code{lcp\_bitcompressed}}
+\newcommand{\sdsllcpdac}{\code{lcp\_dac}}
+\newcommand{\sdsllcpvlc}{\code{lcp\_vlc}}
+\newcommand{\sdsllcpbyte}{\code{lcp\_byte}}
+\newcommand{\sdsllcpsupportsada}{\code{lcp\_support\_sada}}
+\newcommand{\sdsllcpwt}{\code{lcp\_wt}}
+\newcommand{\sdsllcpsupporttree}{\code{lcp\_support\_tree}}
+\newcommand{\sdsllcpsupporttreeII}{\code{lcp\_support\_tree2}}
+%%%% PBSs
+\newcommand{\sdslbpsupportg}{\code{bp\_support\_g}}
+\newcommand{\sdslbpsupportgg}{\code{bp\_support\_gg}}
+\newcommand{\sdslbpsupportsada}{\code{bp\_support\_sada}}
+%%%% CSTs
+\newcommand{\sdslcstsada}{\code{cst\_sada}}
+\newcommand{\sdslcstsctIII}{\code{cst\_sct3}}
+%%%% RMQs
+\newcommand{\sdslrmqsupportsparsetable}{\code{rmq\_support\_sparse\_table}}
+\newcommand{\sdslrmqsuccinctsada}{\code{rmq\_succint\_sada}}
+\newcommand{\sdslrmqsuccinctsct}{\code{rmq\_succint\_sct}}
+
+\newcommand{\myYES}{$\checkmark$}
+\newcommand{\myNO}{$\times$}
+
+\begin{center}
+ \Large{\textbf{\sdsl\ Cheat Sheet}} \\
+\end{center}
+
+\section{Data structures}
+The library code is in the \code{sdsl} namespace. Either import
+the namespace in your program (\code{using~namespace~sdsl;}) or
+qualify all identifieres by a \code{sdsl::}-prefix.
+
+Each section corresponds to a header file. The file
+is hyperlinked as part of the section heading.
+
+We have two types of data structures in \sdsl.
+\emph{Self-contained} and \emph{support}
+structures. A support object \code{s} can extend
+a self-contained object \code{o} (e.g. add functionality), but
+requires access to \code{o}. Support structures contain
+the substring \code{support} in their class names.
+
+\subsection{Integer Vectors (\href{\sdslgitinc/vectors.hpp}{IV})}
+The core of the library is the class
+\href{\sdslgitinc/int_vector.hpp}{\sdslintvector\textless$w$\textgreater}.
+Parameter $w$ corresponds to the fixed length of each
+element in bits. For $w=8,16,32,64,1$ the length is
+fixed during compile time and the vectors
+correspond to \href{http://www.sgi.com/tech/stl/Vector.html}{\code{std::vector\textless uint$w$\_t\textgreater}}
+resp. \code{std::vector<bool>}.
+If $w=0$ (default) the length can be set during runtime.
+\textit{Constructor:} \sdslintvectorZ\code{($n$,$x$,$\ell$)}, with
+$n$ equals size, $x$ default integer value, $\ell$ width
+of integer (has no effect for $w>0$).
+
+\textit{Public~methods:} \code{operator[i]}, \code{size()}, \code{width()},
+\code{data()}.
+
+\subsubsection{Manipulating \sdslintvector\textless$w$\textgreater\ \code{v}}
+\settowidth{\MyLen}{\code{set\_random\_bits(v)}\quad}
+\begin{tabular}{@{}p{\the\MyLen}%
+ @{}p{\linewidth-\the\MyLen}@{}}
+\textit{Method} & \textit{Description} \\
+\code{v[$i$]=$x$} & Set entry \code{v[$i$]} to $x$. \\
+\code{v.width($\ell$)} & Set width to $\ell$, if $w=0$.\\
+\code{v.resize($n$)} & Resize \code{v} to $n$ elements. \\
+\multicolumn{2}{@{}l@{}}{Useful methods in namespace \code{sdsl::util}:} \\
+\code{set\_to\_value(v,$k$)} & Set \code{v[$i$]=$k$} for each $i$.\\
+\code{set\_to\_id(v)} & Set \code{v[$i$]=$i$} for each $i$.\\
+\code{set\_random\_bits(v)} & Set elements to random bits. \\
+\code{mod(v,$m$)} & Set \code{v[$i$]=v[$i$]$\bmod m$} for each $i$.\\
+\code{bit\_compress(v)} & Gets \code{$x\!=\!\max_i$v[$i$]} and
+ $\ell\!=\!\lceil\log(x\!-\!1)\rceil\!+\!1$
+ and packs the entries in $\ell$-bit integers.\\
+% and call \code{v.width($\ell$)}.\\
+\code{expand\_width(v,$\ell$)} & Expands the width of each integer to
+ $\ell$ bits, if \code{$\ell\geq$~v.width().}\\
+\end{tabular}
+
+\subsubsection{Compressed Integer Vectors (\href{\sdslgitinc/vectors.hpp}{CIV})}
+For a vector \code{v}, \href{\sdslgitinc/enc_vector.hpp}{\sdslencvector} stores the
+self-delimiting coded deltas (\code{v[$i\!+\!1$]$-$v[$i$]}). Fast random access is
+achieved by sampling values of \code{v} at rate \code{t\_dens}. Available coder
+are
+\href{\sdslgitinc/coder_elias_delta.hpp}{\sdslcodereliasdelta},
+\href{\sdslgitinc/coder_elias_gamma.hpp}{\sdslcodereliasgamma},
+and
+\href{\sdslgitinc/coder_fibonacci.hpp}{\sdslcoderfibonacci}.
+
+Class \href{\sdslgitinc/vlc_vector.hpp}{\sdslvlcvector} stores each
+\code{v[i]} as self-delimiting codeword. Samples at rate
+\code{t\_dens} are inserted for fast random access.
+
+Class \href{\sdslgitinc/dac_vector.hpp}{\sdsldacvector} stores
+for each value $x$ the least $(\code{t\_b}-1)$
+significant bits
+plus a bit which is set if $x\geq 2^{b-1}$. In the latter case,
+the process is repeated with $x'=x/2^{b-1}$.
+
+\subsection{Bitvectors (\href{\sdslgitinc/bit_vectors.hpp}{BV})}
+Representations for a bitvector of length $n$ with $m$ set bits.
+\begin{tabular}{@{}lll@{}}
+\textit{Class} & \textit{Description} & \textit{Space} \\
+\href{\sdslgitinc/int_vector.hpp}{\sdslbitvector} &
+plain bitvector & 64$\lceil n/64\!+\!1\rceil$ \\
+\href{\sdslgitinc/bit_vector_il.hpp}{\sdslbitvectoril} &
+interleaved bitvector & $\approx n(1+K/64)$ \\
+\href{\sdslgitinc/rrr_vector.hpp}{\sdslrrrvector} &
+$H_0$-compressed bitvector & $\approx \lceil \log {n\choose m} \rceil$ \\
+\href{\sdslgitinc/sd_vector.hpp}{\sdslsdvector} & sparse bitvector
+& $\approx\ m\cdot(2\!+\!\log\frac{n}{m})$ \\
+\end{tabular}
+\sdslbitvector\ equals \sdslintvector\code{\textless1\textgreater} and
+is therefore dynamic.\\
+\textit{Public Methods:} \code{operator[$i$]}, \code{size()}, \code{begin()}, \code{end()}\\
+\textit{Public Types:} \code{rank\_1\_type}, \code{select\_1\_type},
+ \code{select\_0\_type}\footnote{\code{select\_0\_type} not defined for \sdslsdvector.}.
+Each bitvector can be constructed out of a \sdslbitvector\ object.
+
+\subsection{Rank Supports (\href{\sdslgitinc/rank_support.hpp}{RS})}
+RSs add rank functionality to BV. Methods
+\code{rank($i$)} and \code{operator($i$)} return the number
+of set bits\footnote{It is also possible to rank \code{0} or
+the patterns \code{10} and \code{01}.} in the prefix $[0..i)$ of the
+supported BV for $i \in [0,n]$.
+\begin{tabular}{@{}llll@{}}
+\textit{Class} & \textit{Compatible BV} & \textit{+Bits} & \textit{Time} \\
+\href{\sdslgitinc/rank_support_v.hpp}{\sdslranksupportv} &
+\sdslbitvector & $0.25 n$ & \Order{1} \\
+\href{\sdslgitinc/rank_support_v5.hpp}{\sdslranksupportvV} &
+\sdslbitvector & $0.0625 n$ & \Order{1} \\
+\href{\sdslgitinc/rank_support_scan.hpp}{\sdslranksupportscan} &
+\sdslbitvector & 64 & \Order{n} \\
+\href{\sdslgitinc/rank_support_il.hpp}{\sdslranksupportil} &
+\sdslbitvectoril & 128 & \Order{1} \\
+\href{\sdslgitinc/rrr_vector.hpp}{\sdslranksupportrrr} &
+\sdslrrrvector & 80 & \Order{k} \\
+\href{\sdslgitinc/sd_vector.hpp}{\sdslranksupportsd} &
+\sdslsdvector & 64 & \Order{\log{\frac{n}{m}}} \\
+\end{tabular}
+Call~\code{util::init\_support(rs,bv)}~to initialize rank
+structure \code{rs} to bitvector \code{bv}. Call \code{rs($i$)} to get $\code{rank(}i\code{)}=\sum_{k=0}^{k<i}\code{bv[}k\code{]}$
+
+\subsection{Select Supports (\href{\sdslgitinc/select_support.hpp}{SLS})}\label{sec-SLS}
+SLSs add select functionality to BV. Let $m$ be the number of set bits
+in BV. Methods \code{select($i$)} and \code{operator($i$)} return the
+position of the $i$-th set bit%
+\footnote{It is also possible to select \code{0} or
+the patterns \code{10} and \code{01}.}
+in BV for $i\in [1..m]$.
+\begin{tabular}{@{~}l@{~}l@{~~}p{9ex}l@{}}
+\textit{Class} &\textit{Compatible BV} &\textit{+Bits}&\textit{Time}\\
+\href{\sdslgitinc/select_support_mcl.hpp}{\sdslselectsupportmcl} &
+\sdslbitvector & $\leq\!0.2 n$ & \Order{1}\\
+\href{\sdslgitinc/select_support_scan.hpp}{\sdslselectsupportscan} &
+\sdslbitvector & $64$ & \Order{n}\\
+\href{\sdslgitinc/select_support_il.hpp}{\sdslselectsupportil} &
+\sdslbitvectoril & $64$ & \Order{\log n}\\
+\href{\sdslgitinc/rrr_select_support.hpp}{\sdslselectsupportrrr} &
+\sdslrrrvector & $64$ & $\Order{\log n}$ \\
+\href{\sdslgitinc/sd_select_support.hpp}{\sdslselectsupportsd} &
+\sdslsdvector & $64$ & \Order{1} \\
+\end{tabular}
+Call~\code{util::init\_support(sls,bv)}~to initialize \code{sls}
+to bitvector \code{bv}. Call \code{sls($i$)} to get
+$\code{select(}i\code{)}=\min\{j\mid \code{rank(}j\!+\!1\code{)}=i\}$.
+
+\subsection{Wavelet Trees (\href{\sdslgitinc/wavelet_trees.hpp}{WT}=BV+RS+SLS)}
+Wavelet trees represent sequences over byte or integer alphabets of size $\sigma$
+and consist of a tree of BVs. Rank and select on the sequences is reduced to rank and select on BVs,
+and the runtime is multiplied by a factor in $[H_0,\log\sigma]$.
+\begin{tabular}{@{}llccc@{}}
+\textit{Class} &\textit{Shape} & \code{lex\_ordered} & \textit{Default} & Travers- \\
+ & & & \textit{alphabet} & able \\
+\href{\sdslgitinc/wt_rlmn.hpp}{\sdslwtrlmn} & \multicolumn{3}{c}{underlying WT dependent}& \myNO \\
+\href{\sdslgitinc/wt_gmr.hpp}{\sdslwtgmr} & \multicolumn{1}{c}{none} & \myNO & integer & \myNO \\
+\href{\sdslgitinc/wt_huff.hpp}{\sdslwthuff} & Huffman & \myNO & byte & \myYES \\
+\href{\sdslgitinc/wm_int.hpp}{\sdslwmint} & Balanced & \myNO & integer & \myYES \\
+\href{\sdslgitinc/wt_blcd.hpp}{\sdslwtblcd} & Balanced & \myYES & byte & \myYES \\
+\href{\sdslgitinc/wt_hutu.hpp}{\sdslwthutu} & Hu-Tucker & \myYES & byte & \myYES \\
+\href{\sdslgitinc/wt_int.hpp}{\sdslwtint} & Balanced & \myYES & integer & \myYES \\
+% TODO: \verb!wt_rlg!
+\end{tabular}
+\textit{Public~types:} \code{value\_type}, \code{size\_type}, and \code{node\_type}
+(if WT is traversable).
+In the following let $c$ be a symbol, $i$,$j$,$k$, and $q$ integers,
+$v$ a node, and $r$ a range.\\
+\textit{Public~methods:}
+\code{size()},
+\code{operator[$i$]},
+\code{rank($i$,c)},
+\code{select($i$,c)},
+\code{inverse\_select($i$)},
+\code{begin()}, \code{end()}.
+\\
+Traversable WTs provide also:
+\code{root()}, \code{is\_leaf($v$)},
+\code{empty($v$)}, \code{sym($v$)},
+\code{expand($v$)},
+\code{expand($v$,$r$)},
+\code{expand($v$,std::vector<$r$>)}.\\
+\code{lex\_ordered} WTs provide also:
+\code{lex\_count($i$,$j$,$c$)} and
+\code{lex\_smaller\_count($i$,$c$)}.
+\sdslwtint\ provides:
+\code{range\_search\_2d}.\\
+\href{\sdslgitinc/wt_algorithm.hpp}{wt\_algorithm.hpp}
+contains the following generic WT method (let $wt$ be
+a WT object):
+\code{intersect($wt$, vector<$r$>)},
+\code{quantile\_freq($wt$,$i$,$j$,$q$)},
+\code{interval\_symbols($wt$,$i$,$j$,$k$,...)},
+\code{symbol\_lte($wt$,$c$)},
+\code{symbol\_gte($wt$,$c$)},
+\code{restricted\_unique\_range\_values($wt$,$x_i$,$x_j$,$y_i$,$y_j$)}.
+
+\subsection{Suffix Arrays (\href{\sdslgitinc/suffix_arrays.hpp}{CSA}=IV+WT)}
+Compressed suffix arrays use CIVs or WTs to represent
+the suffix arrays (SA), its inverse (ISA), BWT, $\Psi$, and
+LF. CSAs can be built over byte and integer alphabets.
+\begin{tabular}{@{}ll@{}}
+\textit{Class} &\textit{Description} \\
+\href{\sdslgitinc/csa_bitcompressed.hpp}{\sdslcsabitcompressed} &
+Based on SA and ISA stored in a IV.\\
+\href{\sdslgitinc/csa_sada.hpp}{\sdslcsasada} &
+Based on $\Psi$ stored in a CIV.\\
+\href{\sdslgitinc/csa_wt.hpp}{\sdslcsawt} &
+Based on the BWT stored in a WT.\\
+\end{tabular}
+\textit{Public~methods:}
+\code{operator[$i$]},
+\code{size()},
+\code{begin()},
+\code{end()}.
+\\
+\textit{Public~members:}
+\code{isa},
+\code{bwt},
+\code{lf},
+\code{psi},
+\code{text},
+\code{L},
+\code{F},
+\code{C}, \code{char2comp}, \code{comp2char}, \code{sigma}.\\
+\textit{Policy classes: } alphabet strategy
+(e.g.
+\href{\sdslgitinc/csa_alphabet_strategy.hpp}{\sdslbytealphabetstrategy},
+\href{\sdslgitinc/csa_alphabet_strategy.hpp}{\sdslsuccinctbytealphabetstrategy},
+\href{\sdslgitinc/csa_alphabet_strategy.hpp}{\sdslintalphabetstrategy})
+and SA sampling strategy
+(e.g.
+ \href{\sdslgitinc/csa_sampling_strategy.hpp}{\sdslsaordersasampling},
+ \href{\sdslgitinc/csa_sampling_strategy.hpp}{\sdsltextordersasampling}
+)
+
+
+\subsection{Longest Common Prefix (\href{\sdslgitinc/lcp.hpp}{LCP}) Arrays}
+\begin{tabular}{@{}ll@{}}
+\textit{Class} &\textit{Description} \\
+\href{\sdslgitinc/lcp_bitcompressed.hpp}{\sdsllcpbitcompressed} &
+Values in a \href{\sdslgitinc/int_vector.hpp}{\sdslintvectorZ}.\\
+\href{\sdslgitinc/lcp_dac.hpp}{\sdsllcpdac} &
+Direct accessible codes used.\\
+\href{\sdslgitinc/lcp_byte.hpp}{\sdsllcpbyte} &
+Small values in a byte; 2 words per large.\\
+\href{\sdslgitinc/lcp_wt.hpp}{\sdsllcpwt} &
+Small values in a WT; 1 word per large.\\
+\href{\sdslgitinc/lcp_vlc.hpp}{\sdsllcpvlc} &
+Values in a \href{\sdslgitinc/vlc_vector.hpp}{vlc\_vector}. \\
+\href{\sdslgitinc/lcp_support_sada.hpp}{\sdsllcpsupportsada} &
+Values stored permuted. CSA needed. \\
+\href{\sdslgitinc/lcp_support_tree.hpp}{\sdsllcpsupporttree} &
+Only depths of CST inner nodes stored.\\
+\href{\sdslgitinc/lcp_support_tree2.hpp}{\sdsllcpsupporttreeII} &
+~+ large values are sampled using LF.\\
+\end{tabular}
+\textit{Public~methods:}
+\code{operator[$i$]},
+\code{size()},
+\code{begin()},
+\code{end()} \\
+
+\subsection{Balanced Parentheses Supports (\href{\sdslgitinc/bp_support.hpp}{BPS})}
+We represent a sequence of parentheses as a \code{bit\_vector}.
+An opening/closing parenthesis corresponds to \code{1}/\code{0}.\\
+\begin{tabular}{@{}ll@{}}
+\textit{Class} &\textit{Description} \\
+\href{\sdslgitinc/bp_support_g.hpp}{\sdslbpsupportg} &
+Two-level pioneer structure.\\
+\href{\sdslgitinc/bp_support_gg.hpp}{\sdslbpsupportgg} &
+Multi-level pioneer structure.\\
+\href{\sdslgitinc/bp_support_sada.hpp}{\sdslbpsupportsada} &
+Min-max-tree over excess sequence.\\
+\end{tabular}
+\textit{Public~methods:} \code{find\_open($i$)}, \code{find\_close($i$)},
+\code{enclode($i$)}, \code{double\_enclose($i$,$j$)}, \code{excess($i$)},
+\code{rr\_enclose($i$,$j$)}, \code{rank($i$)}\footnote{For PBS the
+bits are counted in the prefix $[0..i]$.}, \code{select($i$)}.
+\\
+
+Call~\code{util::init\_support(bps,bv)}~to initialize a BPS
+\code{bps} to \code{bit\_vector} \code{bv}.
+
+
+\subsection{Suffix Trees (\href{\sdslgitinc/suffix_trees.hpp}{CST}=CSA+LCP+BPS)}
+A CST can be parametrized by any combination of CSA ,LCP, and BPS.
+The operation of each part can still be accessed through member varaibles.
+The additional operations are listed below.
+CSTs can be built for byte or integer alphabets.
+\settowidth{\MyLen}{\sdslcstsada\quad}
+\begin{tabular}{@{}p{\the\MyLen}%
+ @{}p{\linewidth-\the\MyLen}@{}}
+
+\textit{Class} & \textit{Description} \\
+\href{\sdslgitinc/cst_sada.hpp}{\sdslcstsada} &
+Represents a node as position in BPS. Navigational operations
+are fast (they are directly translated in BPS operations on
+the DFS-BPS). Space: $4n\!+\!o(n)\!+\!|CSA|\!+\!|LCP|$ bits.\\
+\href{\sdslgitinc/cst_sct3.hpp}{\sdslcstsctIII} &
+Represents nodes as intervals. Fast construction, but
+slower navigational operations. Space: $3n\!+\!o(n)\!+\!|CSA|\!+\!|LCP|$ \\
+\end{tabular}
+\textit{Public~types:} \code{node\_type}.
+In the following let $v$ and $w$ be nodes
+and $i$, $d$, $lb$, $rb$ integers.\\
+\textit{Public~methods:}
+% CST global information
+\code{size()},
+\code{nodes()},
+\code{root()},
+\code{begin()},
+\code{end()},
+\code{begin\_bottom\_up()},
+\code{end\_bottom\_up},
+% CST node info
+\code{size($v$)},
+\code{is\_leaf($v$)},
+\code{degree($v$)},
+\code{depth($v$)},
+\code{node\_depth(v)},
+\code{edge($v$, $d$)},
+\code{lb($v$)},
+\code{rb($v$)},
+\code{id($v$)},
+\code{inv\_id($i$)},
+\code{sn($v$)},
+% CST global navigation
+\code{select\_leaf($i$)},
+\code{node($lb$, $rb$)},
+% CST node navigation
+\code{parent($v$)},
+\code{sibling($v$)},
+\code{lca($v$, $w$)},
+\code{select\_child($v$, $i$)},
+\code{child($v$, $c$)},
+\code{children($v$)},
+\code{sl($v$)},
+\code{wl($v$, $c$)},
+\code{leftmost\_leaf($v$)},
+\code{rightmost\_leaf($v$)}
+\\
+\textit{Public~members:} \code{csa}, \code{lcp}.\\
+The \href{\sdslgit/tutorial/cst-traversal.cpp}{traversal example}
+shows how to use the DFS-iterator.
+%\textit{Iterators methods:} \code{operator++},
+%\code{visit()}, \code{skip\_subtree()}
+
+\subsection{Range Min/Max Query (\href{\sdslgitinc/rmq_support.hpp}{RMQ})}
+A RMQ \code{rmq} can be used to determine the position of the miniumum
+value\footnote{Or maximum value; can be set by a template parameter.}
+in an arbitrary subrange $[i,j]$ of an preprocessed vector \code{v}.
+Operator \code{operator($i$,$j$)} returns $x=\min\{$r$\mid r\in [i,j] \wedge \mbox{\code{v}[$r$]}\leq\mbox{\code{v[$k$]}}\ \forall k\in[i,j]\}$
+
+\settowidth{\MyLen}{\sdslrmqsupportsparsetable\quad }
+\settowidth{\MidLen}{$4n+o(n)$\quad}
+\begin{tabular}{@{}p{\the\MyLen}%
+ @{}p{\linewidth-\the\MidLen-\the\MyLen}@{}p{\the\MidLen}@{}}
+\textit{Class} & \textit{Space} & \textit{Time} \\
+\href{\sdslgitinc/rmq_support_sparse_table.hpp}{\sdslrmqsupportsparsetable} &
+$n \log^2 n$ & \Order{1} \\
+\href{\sdslgitinc/rmq_succinct_sada.hpp}{\sdslrmqsuccinctsada} &
+$4n+o(n)$ & \Order{1} \\
+\href{\sdslgitinc/rmq_succinct_sct.hpp}{\sdslrmqsuccinctsct} &
+$2n+o(n)$ & \Order{1} \\
+\end{tabular}
+
+\section{Constructing data structures}
+Let \code{o} be a WT-, CSA-, or CST-object.
+Object \code{o} is built with \code{construct(o,file,num\_bytes=$0$)}
+from a sequence stored in \code{file}. File is interpreted
+dependent on the value of \code{num\_bytes}:
+\settowidth{\MyLen}{\code{num\_bytes=$1$} }
+\begin{tabular}{@{}p{\the\MyLen}%
+ @{}p{\linewidth-\the\MyLen}@{}}
+%\begin{tabular}{@{}ll@{}}
+\textit{Value} & \textit{File interpreted as} \\
+\code{num\_bytes=$0$} & serialized \code{int\_vector<>}.\\
+\code{num\_bytes=$1$} & byte sequence of length \code{util::file\_size(file)}.\\
+\code{num\_bytes=$2$} & 16-bit word sequence.\\
+\code{num\_bytes=$4$} & 32-bit word sequence.\\
+\code{num\_bytes=$8$} & 64-bit word sequence.\\
+\code{num\_bytes=d} & Parse decimal numbers.\\
+\end{tabular}
+Note: \code{construct} writes/reads data to/from
+disk during construction. Accessing disk for small
+instances is a considerable overhead. \code{construct\_im(o,data,num\_bytes=$0$)} will
+build \code{o} using only main memory. Have a look
+at \href{\sdslgit/tutorial/csx-printf.cpp}{this handy tool for an example}.
+
+\subsection{Configuring construction}
+The locations and names of the intermediate files
+can be configured by a \code{cache\_config} object.
+It is constructed by
+\code{cache\_config(del,tmp\_dir,id, map)}
+where
+\code{del} is a boolean variable which specifies
+if the intermediate files should be deleted after construction,
+\code{tmp\_dir} is a path to the directory where
+the intermediate files should be stored,
+\code{id} is used as part of the file names,
+and \code{map} contains a mapping of keys
+(e.g. \href{\sdslgitinc/config.hpp}{\code{conf::KEY\_BWT}},
+ \href{\sdslgitinc/config.hpp}{\code{conf::KEY\_SA}},\ldots)
+to file paths.\\
+The \code{cache\_config} parameter extends the construction method to:
+\code{construct(o,file,config,num\_bytes)}.\\
+The following methods (\code{key} is a key string, \code{config} represenet a
+\code{cache\_config} object, and \code{o} a \sdsl\ object) should be handy
+in customized construction processes:\\
+\code{cache\_file\_name(key,config)}\\
+\code{cache\_file\_exists(key,config)}\\
+\code{register\_cache\_file(key,config)}\\
+\code{load\_from\_cache(o,key,config)}\\
+\code{store\_to\_cache(o,key,config)}\\
+
+\subsection{Resource requirements}
+\textit{Memory}: The memory peak of CSA and CST construction occurs during the SA
+construction, which is $5$ times the texts size for byte-alphabets
+and inputs $<2$ GiB (see the Figure below for a $200$ MB text)
+and $9$ times for larger inputs. For integer
+alphabets the construction takes about twice the space of
+the resulting output.\\
+\textit{Time}: A CST construction processes at about $2\mbox{ MB}/s$.
+The Figure below shows the resource consumption during the construction
+of a \code{cst\_sct3<>} CST for \href{\pizzachili}{$200$ MB English text}.
+For a detailed description of the phases click on the figure.
+\href{http://simongog.github.io/assets/data/cst-construction.html}{%
+\scalebox{0.18}{%
+\includegraphics{viz.pdf}%
+}%
+}
+This diagram was generated using the sample program
+\href{\sdslgit/examples/memory-visualization.cpp}{memory-visualization.cpp}.
+
+\section{Reading and writing data}
+\subsection{Importing data into \sdsl\ structures}
+\begin{tabular}{@{}p{0.9\linewidth}@{}}
+\code{load\_vector\_from\_file(v, file, num\_bytes)} \\
+Load \code{file} into an \code{int\_vector}~\code{v}. Interpretation
+of \code{file} depends on \code{num\_bytes}; see method \code{construct}.
+\end{tabular}
+%TODO: mention io wrappers
+
+
+\subsection{Store \sdsl\ structures}
+Use \code{store\_to\_file(o, file)}
+to store an \sdsl\ object \code{o} to \code{file}.
+Object \code{o} can also be serialized
+into a \code{std::ostream}-object \code{out}
+by the call \code{o.serialize(out)}.
+
+%\code{write\_member($x$,out)}
+%\code{read\_member($x$,in)}
+
+\subsection{Load \sdsl\ structures}
+Use \code{load\_from\_file(o, file)} to load
+an \sdsl\ object \code{o}, which is stored in \code{file}.
+Call \code{o.load(in)} reads \code{o} from
+\code{std::istream}-object \code{in}.
+
+%TODO: mention io wrappers
+
+\section{Utility methods}
+More useful methods in the \code{sdsl::util} namespace:
+
+
+\settowidth{\MyLen}{\code{assign(t1,t2)}~}
+\begin{tabular}{@{}p{\the\MyLen}%
+ @{}p{\linewidth-\the\MyLen}@{}}
+%\begin{tabular}{@{}ll@{}}
+\textit{Method} & \textit{Description} \\
+\code{pid()} & Id of current process. \\
+\code{id()} & Get unique id inside the process. \\
+\code{basename(p)} & Get filename part of a path \code{p}. \\
+\code{dirname(p)} & Get directory part of a path \code{p}. \\
+\code{demangle(o)} & Demangles output of \code{typeid(o).name()}.\\
+\code{demangle2(o)} & Simplifies output of \code{demangle}. E.g. removes \code{sdsl::}-prefixes, \ldots \\
+\code{to\_string(o)} & Transform object \code{o} to a string. \\
+\code{assign(o1,o2)} & Assign \code{o1} to \code{o2}, or swap \code{o1} and \code{o2} if
+ the objects are of the same type.\\
+\code{clear(o)} & Set o to the empty object.\\
+%\code{swap\_support(s1, s2, t1, t2)}\\
+\end{tabular}
+
+\section{Measuring and Visualizing Space}
+\code{size\_in\_bytes(o)} returns the space used by an
+\sdsl\ object \code{o}. Call
+\code{write\_structure<JSON\_FORMAT>(o,out)} to get
+a detailed space breakdown written in
+\href{http://www.json.org/}{JSON} format to stream \code{out}.
+\code{<HTML\_FORMAT>} will write a HTML page
+(\href{http://simongog.github.io/assets/data/space-vis.html}{like this}),
+which includes an interactive SVG-figure.
+
+
+\section{Methods on words}
+Class \code{bits} contains various fast methods
+on a $64$-bit word $x$. Here the most important ones.
+\settowidth{\MyLen}{\code{bits::sel($x$, $i$)}~}
+\begin{tabular}{@{}p{\the\MyLen}%
+ @{}p{\linewidth-\the\MyLen}@{}}
+%\begin{tabular}{@{}ll@{}}
+\textit{Method} & \textit{Description} \\
+\code{bits::cnt($x$)} & Number of set bits in $x$.\\
+\code{bits::sel($x$,$i$)}& Position of $i$-th set bit, $i\in[0,\code{cnt($x$)}\!-\!1)$. \\
+\code{bits::lo($x$)} & Position of least significant set bit.\\
+\code{bits::hi($x$)} & Position of most significant set bit.\\
+\end{tabular}
+\textit{Note}: Positions in $x$ start at $0$.
+\code{lo} and \code{hi} return $0$ for $x=0$.
+
+\section{Tests}
+A \code{make test} call in the \href{\sdslgit/test}{test}
+directory, downloads test inputs, compiles tests,
+and executes them.
+
+\section{Benchmarks}
+Directory \href{\sdslgit/benachmark}{benchmark}
+contains configurable benchmarks for various
+data structure, like WTs, CSAs/FM-indexes (measuring
+time and space for operations
+\href{\sdslgit/benchmark/indexing_count}{count},
+\href{\sdslgit/benchmark/indexing_locate}{locate}, and
+\href{\sdslgit/benchmark/indexing_extract}{extract}).
+
+\section{Debugging}
+You get the gdb command \code{pv <int\_vector> <idx1> <idx2>},
+which displays the elements of an \sdslintvector\ in the
+range $[\code{idx1},\code{idx2}]$ by appending the file
+\href{\sdslgit/extras/sdsl.gdb}{sdsl.gdb} to your
+\code{.gdbinit}.
+
+%\section{Acknowledgements}
+%Yuta Mori for implementing libdivsufsort, which
+%is used to construct SAs.
+%
+%Jesper Larsson for integer-alphabet SA construction.
+%
+\rule{0.3\linewidth}{0.25pt}
+\scriptsize
+
+\copyright\ Simon Gog
+
+Cheatsheet template provided by Winston Chang
+http://www.stdout.org/$\sim$winston/latex/
+
+\theendnotes
+
+\end{multicols}
+%\newpage
+%~
+\end{document}
diff --git a/extras/cheatsheet/viz.pdf b/extras/cheatsheet/viz.pdf
new file mode 100644
index 0000000..c2bc8e8
Binary files /dev/null and b/extras/cheatsheet/viz.pdf differ
diff --git a/extras/literature.bib b/extras/literature.bib
new file mode 100644
index 0000000..e69c29c
--- /dev/null
+++ b/extras/literature.bib
@@ -0,0 +1,569 @@
+Literature list of implemented data structures in SDSL
+(not complete yet)
+
+// used in include/sdsl/k2_treap.hpp
+ at INPROCEEDINGS{BRI:BER:KON:NAV:2014,
+author = {N. Brisaboa and G. de Bernardo and R. Konow and G. Navarro},
+title = {$K^2$-Treaps: Range Top-$k$ Queries in Compact Space},
+booktitle = {Proceedings of String Processing and Information Retrieval, 21th International
+ Symposium (SPIRE 2014)},
+year = {2014},
+pages = {215--226}
+}
+
+// used in include/sdsl/construct_sa.hpp
+ at inproceedings{BEL:ZWE:GOG:OHL:2013,
+author = {Timo Beller and Maike Zwerger and Simon Gog and Enno Ohlebusch},
+title = {Space-Efficient Construction of the Burrows-Wheeler Transform},
+booktitle = {Proceedings of String Processing and Information Retrieval, 20th International
+ Symposium, (SPIRE 2013)},
+year = {2013},
+pages = {5-16},
+ee = {http://dx.doi.org/10.1007/978-3-319-02432-5_5},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/wt_gmr.hpp
+ at inproceedings{GOL:MUN:RAO:2006,
+author = {Alexander Golynski and J. Ian Munro and S. Srinivasa Rao},
+title = {Rank/select operations on large alphabets: a tool for text
+ indexing},
+booktitle = {Proceedings of the 17th Annual ACM-SIAM Symposium
+ on Discrete Algorithms (SODA 2006)},
+year = {2006},
+pages = {368-373},
+ee = {http://dl.acm.org/citation.cfm?id=1109557.1109599},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/wm_int.hpp
+ at inproceedings{CLA:NAV:2012,
+author = {Francisco Claude and Gonzalo Navarro},
+title = {The Wavelet Matrix},
+booktitle = {Proceedings of String Processing and Information Retrieval, 19th
+ International Symposium, (SPIRE 2012)},
+year = {2012},
+pages = {167-179},
+ee = {http://dx.doi.org/10.1007/978-3-642-34109-0_18},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/inv_perm_support.hpp
+// used in include/sdsl/wt_gmr.hpp
+ at inproceedings{MUN:RAM:RAM:RAO:2003,
+ author = {J. Ian Munro and Rajeev Raman and Venkatesh Raman and S. Srinivasa Rao},
+ title = {Succinct Representations of Permutations},
+ booktitle = {Proceedings of the 30th International Colloquium on Automata, Languages
+ and Programming (ICALP2003)},
+ year = {2003},
+ pages = {345-356}
+}
+
+// used in include/sdsl/wt_int.hpp
+ at article{GAG:NAV:PUG:2012,
+author = {Travis Gagie and Gonzalo Navarro and Simon J. Puglisi},
+title = {New algorithms on wavelet trees and applications to information retrieval},
+journal = {Theoretical Computer Science},
+volume = {426},
+year = {2012},
+pages = {25-41},
+ee = {http://dx.doi.org/10.1016/j.tcs.2011.12.002},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/algorithms_for_compressed_suffix_trees.hpp
+ at inproceedings{FIS:2010,
+author = {Johannes Fischer},
+title = {Optimal Succinctness for Range Minimum Queries},
+booktitle = {Proceedings of the 9th Latin American Symposium
+ on Theoretical Informatics (LATIN 2010)},
+year = {2010},
+pages = {158-169},
+ee = {http://dx.doi.org/10.1007/978-3-642-12200-2_16},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/wt_int.hpp
+ at inproceedings{CUL:NAV:PUG:TUR:2010,
+author = {J. Shane Culpepper and Gonzalo Navarro and Simon J. Puglisi and Andrew Turpin},
+title = {Top-{\it k} Ranked Document Search in General Text Databases},
+booktitle = {Proceedings Part II of the 18th Annual European Symposium on Algorithms (ESA 2010)},
+year = {2010},
+pages = {194-205},
+ee = {http://dx.doi.org/10.1007/978-3-642-15781-3_17},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/construct_lcp.hpp
+ at inproceedings{KAR:MAN:PUG:2009,
+author = {Juha K{\"a}rkk{\"a}inen and Giovanni Manzini and Simon J. Puglisi},
+title = {Permuted Longest-Common-Prefix Array},
+booktitle = {Proceedings of the 20th Annual Symposium on Combinatorial Pattern Matching,
+ (CPM 2009)},
+year = {2009},
+pages = {181-192},
+ee = {http://dx.doi.org/10.1007/978-3-642-02441-2_17},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/construct_lcp.hpp
+ at inproceedings{KAS:LEE:ARI:ARI:PAR:2001,
+author = {Toru Kasai and Gunho Lee and Hiroki Arimura and Setsuo Arikawa and Kunsoo Park},
+title = {Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Applications},
+booktitle = {Proceedings of the 12th Annual Symposium on Combinatorial Pattern Matching,
+ (CPM 2001)},
+year = {2001},
+pages = {181-192},
+ee = {http://link.springer.de/link/service/series/0558/bibs/2089/20890181.htm},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/construct_lcp.hpp
+ at inproceedings{GOG:OHL:2011,
+author = {Simon Gog and Enno Ohlebusch},
+title = {Fast and Lightweight LCP-Array Construction Algorithms},
+booktitle = {Proceedings of the 13th Workshop on Algorithm Engineering and Experiments,
+ (ALENEX 2011)},
+year = {2011},
+pages = {25-34},
+ee = {http://www.siam.org/proceedings/alenex/2011/alx11_03_gogs.pdf},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/construct_lcp.hpp
+ at article{GOG:OHL:2010,
+author = {Simon Gog and Enno Ohlebusch},
+title = {Lightweight LCP-Array Construction in Linear Time},
+journal = {CoRR},
+volume = {abs/1012.4263},
+year = {2010},
+ee = {http://arxiv.org/abs/1012.4263},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/construct_lcp.hpp
+ at inproceedings{BEL:GOG:OHL:SCH:2011,
+author = {Timo Beller and Simon Gog and Enno Ohlebusch and Thomas Schnattinger},
+title = {Computing the Longest Common Prefix Array Based on the Burrows-Wheeler Transform},
+booktitle = {Proceedings of String Processing and Information Retrieval, 18th International
+ Symposium, (SPIRE 2011)},
+year = {2011},
+pages = {197-208},
+ee = {http://dx.doi.org/10.1007/978-3-642-24583-1_20},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/construct_lcp.hpp
+ at article{BEL:GOG:OHL:SCH:2013,
+author = {Timo Beller and Simon Gog and Enno Ohlebusch and Thomas Schnattinger},
+title = {Computing the Longest Common Prefix Array Based on the Burrows-Wheeler Transform},
+journal = {Journal of Discrete Algorithms},
+issue_date = {January, 2013},
+volume = {18},
+number = {0},
+month = {January},
+year = {2013},
+issn = {1570-8667},
+pages = {22-31},
+numpages = {10},
+url = {http://dx.doi.org/10.1016/j.jda.2012.07.007},
+doi = {10.1016/j.jda.2012.07.007},
+acmid = {2428912},
+publisher = {Elsevier Science Publishers B. V.},
+address = {Amsterdam, The Netherlands, The Netherlands},
+}
+
+// used in include/sdsl/rrr_vector.hpp
+ at inproceedings{RAM:RAM:RAO:2002,
+author = {Rajeev Raman and Venkatesh Raman and S. Srinivasa Rao},
+title = {Succinct indexable dictionaries with applications to encoding k-ary trees and multisets},
+booktitle = {Proceedings of the 13th Annual ACM-SIAM Symposium
+ on Discrete Algorithms (SODA 2002)},
+year = {2002},
+pages = {233-242},
+ee = {http://dl.acm.org/citation.cfm?id=545381.545411},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/csa_sampling_strategy.hpp
+ at inproceedings{FER:SIR:VEN:2011,
+author = {Paolo Ferragina and Jouni Sir{\'e}n and Rossano Venturini},
+title = {Distribution-Aware Compressed Full-Text Indexes},
+booktitle = {Proceedings of the 19th Annual European Symposium on Algorithms (ESA 2011)},
+year = {2011},
+pages = {760-771},
+ee = {http://dx.doi.org/10.1007/978-3-642-23719-5_64},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/rmq_support_sparse_table.hpp
+ at inproceedings{BEN:FAR:2000,
+author = {Michael A. Bender and Martin Farach-Colton},
+title = {The LCA Problem Revisited},
+booktitle = {Proceedings of the 4th Latin American Symposium
+ on Theoretical Informatics (LATIN 2000)},
+year = {2000},
+pages = {88-94},
+ee = {http://dx.doi.org/10.1007/10719839_9},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/bp_support_gg.hpp
+ at article{GEA:RAH:RAM:RAM:2006,
+author = {Richard F. Geary and Naila Rahman and Rajeev Raman and Venkatesh Raman},
+title = {A simple optimal representation for balanced parentheses},
+journal = {Theoretical Computer Science},
+volume = {368},
+number = {3},
+year = {2006},
+pages = {231-246},
+ee = {http://dx.doi.org/10.1016/j.tcs.2006.09.014},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/rank_support_v.hpp
+ at inproceedings{VIG:2008,
+author = {Sebastiano Vigna},
+title = {Broadword Implementation of Rank/Select Queries},
+booktitle = {Proceedings of the 7th Workshop on Experimental Algorithms,
+ WEA (2008 WEA)},
+year = {2008},
+pages = {154-168},
+ee = {http://dx.doi.org/10.1007/978-3-540-68552-4_12},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/wt.hpp
+ at inproceedings{GRO:VIT:2003,
+author = {Roberto Grossi and Ankur Gupta and Jeffrey Scott Vitter},
+title = {High-order entropy-compressed text indexes},
+booktitle = {Proceedings of the 14th Annual ACM-SIAM Symposium
+ on Discrete Algorithms (SODA 2003)},
+year = {2003},
+pages = {841-850},
+ee = {http://dl.acm.org/citation.cfm?id=644108.644250},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/wt_rlmn.hpp
+// used in include/sdsl/wt_huff.hpp
+ at inproceedings{MAK:NAV:2005,
+author = {Veli M{\"a}kinen and Gonzalo Navarro},
+title = {Succinct Suffix Arrays Based on Run-Length Encoding},
+booktitle = {Proceedings of the 16th Annual Symposium on Combinatorial Pattern Matching,
+ (CPM 2005)},
+year = {2005},
+pages = {45-56},
+ee = {http://dx.doi.org/10.1007/11496656_5},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/rrr_vector_15.hpp
+ at inproceedings{CLA:NAV:2008,
+author = {Francisco Claude and Gonzalo Navarro},
+title = {Practical Rank/Select Queries over Arbitrary Sequences},
+booktitle = {Proceedings of String Processing and Information Retrieval, 15th International
+ Symposium, (SPIRE 2008)},
+year = {2008},
+pages = {176-187},
+ee = {http://dx.doi.org/10.1007/978-3-540-89097-3_18},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/lcp_dac.hpp
+ at inproceedings{BRI:LAD:NAV:2009,
+author = {Nieves R. Brisaboa and Susana Ladra and Gonzalo Navarro},
+title = {Directly Addressable Variable-Length Codes},
+booktitle = {Proceedings of String Processing and Information Retrieval, 16th International
+ Symposium, (SPIRE 2009)},
+year = {2009},
+pages = {122-130},
+ee = {http://dx.doi.org/10.1007/978-3-642-03784-9_12},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/lcp_sada.hpp
+ at inproceedings{SAD:2002,
+author = {Kunihiko Sadakane},
+title = {Succinct representations of {LCP} information and improvements
+ in the compressed suffix arrays},
+booktitle = {Proceedings of the 13th Annual ACM-SIAM Symposium
+ on Discrete Algorithms (SODA 2002)},
+year = {2002},
+pages = {225-232},
+ee = {http://dl.acm.org/citation.cfm?id=545381.545410},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/bp_support_sada.hpp
+ at techreport{SAD:2008,
+author = {Kunihiko Sadakane},
+title = {The Ultimate Balanced Parentheses},
+institution = {Dept. of Computer Science and Communication Engineering,
+ Kyushu University, Japan},
+year = {2008}
+}
+
+// used in include/sdsl/bp_support_g.hpp
+ at inproceedings{GOG:FIS:2010,
+author = {Simon Gog and Johannes Fischer},
+title = {Advantages of Shared Data Structures for Sequences of Balanced
+ Parentheses},
+booktitle = {Proceedings of 2010 Data Compression Conference (DCC 2010)},
+year = {2010},
+pages = {406-415},
+ee = {http://doi.ieeecomputersociety.org/10.1109/DCC.2010.43},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/rrr_vector.hpp
+ at inproceedings{NAV:PRO:2012,
+author = {Gonzalo Navarro and Eliana Providel},
+title = {Fast, Small, Simple Rank/Select on Bitmaps},
+booktitle = {Proceedings of the 11th International Symposium on Experimental Algorithms
+ (SEA 2013)},
+year = {2012},
+pages = {295-306},
+ee = {http://dx.doi.org/10.1007/978-3-642-30850-5_26},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in qsufsort.hpp
+ at article{LAR:SAD:2007,
+author = {N. Jesper Larsson and Kunihiko Sadakane},
+title = {Faster suffix sorting},
+journal = {Theoretical Computer Science},
+volume = {387},
+number = {3},
+year = {2007},
+pages = {258-272},
+ee = {http://dx.doi.org/10.1016/j.tcs.2007.07.017},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/sd_vector.hpp
+ at inproceedings{OKA:SAD:2007,
+author = {Daisuke Okanohara and Kunihiko Sadakane},
+title = {Practical Entropy-Compressed Rank/Select Dictionary},
+booktitle = {Proceedings of the 9th Workshop on Algorithm Engineering and Experiments
+ (ALENEX 2007)},
+year = {2007},
+ee = {http://www.siam.org/proceedings/alenex/2007/alx07_007okanoharad2.pdf},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/csa_sada.hpp
+ at article{SAD:2003,
+author = {Kunihiko Sadakane},
+title = {New text indexing functionalities of the compressed suffix arrays},
+journal = {Journal of Algorithms},
+volume = {48},
+number = {2},
+year = {2003},
+pages = {294-313},
+ee = {http://dx.doi.org/10.1016/S0196-6774(03)00087-7},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/cst_sada.hpp
+ at article{SAD:2007,
+author = {Kunihiko Sadakane},
+title = {Compressed Suffix Trees with Full Functionality},
+journal = {Theory of Computing Systems},
+volume = {41},
+number = {4},
+year = {2007},
+pages = {589-607},
+ee = {http://dx.doi.org/10.1007/s00224-006-1198-x},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in include/sdsl/cst_sct3.hpp
+ at inproceedings{OHL:FIS:GOG:2010,
+author = {Enno Ohlebusch and Johannes Fischer and Simon Gog},
+title = {CST++},
+booktitle = {Proceedings of String Processing and Information Retrieval, 17th International
+ Symposium, (SPIRE 2010)},
+year = {2010},
+pages = {322-333},
+ee = {http://dx.doi.org/10.1007/978-3-642-16321-0_34},
+bibsource = {DBLP, http://dblp.uni-trier.de}
+}
+
+// used in tutorial/document_listing/document_listing_sada.hpp
+ at article{SAD:JDA:2007,
+author = {Kunihiko Sadakane},
+title = {Succinct data structures for flexible text retrieval systems},
+journal = {Journal of Discrete Algorithms},
+issue_date = {March, 2007},
+volume = {5},
+number = {1},
+month = {March},
+year = {2007},
+issn = {1570-8667},
+pages = {12-22},
+numpages = {11},
+url = {http://dx.doi.org/10.1016/j.jda.2006.03.011},
+doi = {10.1016/j.jda.2006.03.011},
+acmid = {1224678},
+publisher = {Elsevier Science Publishers B. V.},
+address = {Amsterdam, The Netherlands, The Netherlands},
+}
+
+// used in include/sdsl/lcp_dac.hpp
+ at article{TRA:SAN:2010,
+author = {Frederik Transier and Peter Sanders},
+title = {Engineering Basic Algorithms of an In-Memory Text Search Engine},
+journal = {ACM Transactions on Information Systems},
+issue_date = {December 2010},
+volume = {29},
+number = {1},
+month = {December},
+year = {2010},
+issn = {1046-8188},
+pages = {2:1-2:37},
+articleno = {2},
+numpages = {37},
+url = {http://doi.acm.org/10.1145/1877766.1877768},
+doi = {10.1145/1877766.1877768},
+acmid = {1877768},
+publisher = {ACM},
+address = {New York, NY, USA},
+}
+
+// used in include/sdsl/lcp_dac.hpp
+ at article{WIL:ZOB:1999,
+author = {Hugh E. Williams and Justin Zobel},
+title = {Compressing Integers for Fast File Access},
+journal = {The Computer Journal},
+volume = {42},
+number = {3},
+year = {1999},
+pages = {193-201},
+url = {http://comjnl.oxfordjournals.org/content/42/3/193.abstract},
+doi = {10.1093/comjnl/42.3.193},
+}
+
+// used in include/sdsl/sd_vector.hpp
+ at article{ELI:1974,
+author = {Elias, Peter},
+title = {Efficient Storage and Retrieval by Content and Address of Static Files},
+journal = {Journal of the ACM},
+issue_date = {April 1974},
+volume = {21},
+number = {2},
+month = {April},
+year = {1974},
+issn = {0004-5411},
+pages = {246-260},
+numpages = {15},
+url = {http://doi.acm.org/10.1145/321812.321820},
+doi = {10.1145/321812.321820},
+acmid = {321820},
+publisher = {ACM},
+address = {New York, NY, USA},
+}
+
+// used in include/sdsl/sd_vector.hpp
+ at book{FAN:1971,
+title = {On the Number of Bits Required to Implement an Associative Memory},
+author = {Robert Mario Fano},
+series = {Computation Structures Group Memo},
+year = {1971},
+publisher = {Massachusetts Institute of Technology, Project MAC},
+}
+
+// used in include/sdsl/bp_support_g.hpp
+// used in include/sdsl/bp_support_gg.hpp
+ at inproceedings{GEA:RAH:RAM:RAM:2004,
+author = {Richard F. Geary and Naila Rahman and Rajeev Raman and Venkatesh Raman},
+title = {A Simple Optimal Representation for Balanced Parentheses},
+booktitle = {Proceedings of the 15th Annual Symposium on Combinatorial Pattern Matching,
+ (CPM 2004)},
+year = {2004},
+pages = {159-172},
+ee = {http://dx.doi.org/10.1007/978-3-540-27801-6_12},
+bibsource = {DBLP, http://dblp.uni-trier.de},
+}
+
+// used in include/sdsl/suffix_array_algorithm.hpp
+ at inproceedings{FER:MAN:2000,
+author = {Paolo Ferragina and Giovanni Manzini},
+title = {Opportunistic Data Structures with Applications},
+booktitle = {Proceedings of the 41st Annual Symposium on Foundations of Computer Science,
+ (FOCS 2000)},
+year = {2000},
+pages = {390-398},
+ee = {http://doi.ieeecomputersociety.org/10.1109/SFCS.2000.892127},
+bibsource = {DBLP, http://dblp.uni-trier.de},
+}
+
+// used in include/sdsl/suffix_array_algorithm.hpp
+ at article{SCH:OHL:GOG:2013,
+author = {Thomas Schnattinger and Enno Ohlebusch and Simon Gog},
+title = {Bidirectional search in a string with wavelet trees and bidirectional matching statistics},
+journal = {Information and Computation},
+volume = {213},
+year = {2012},
+issn = {0890-5401},
+pages = {13-22},
+ee = {http://dx.doi.org/10.1016/j.ic.2011.03.007},
+bibsource = {DBLP, http://dblp.uni-trier.de},
+}
+
+// used in include/sdsl/lcp_byte.hpp
+ at article{ABO:KUR:OHL:2004,
+author = {Mohamed Ibrahim Abouelhoda and Stefan Kurtz and Enno Ohlebusch},
+title = {Replacing suffix trees with enhanced suffix arrays},
+journal = {Journal of Discrete Algorithms},
+volume = {2},
+number = {1},
+year = {2004},
+issn = {1570-8667},
+pages = {53-86},
+ee = {http://dx.doi.org/10.1016/S1570-8667(03)00065-0},
+bibsource = {DBLP, http://dblp.uni-trier.de},
+}
+
+// used in include/sdsl/rrr_vector.hpp
+ at inproceedings{PAG:1999,
+author = {Rasmus Pagh},
+title = {Low Redundancy in Static Dictionaries with O(1) Worst Case Lookup Time},
+booktitle = {Proceedings of the 26th International Colloquium on Automata, Languages and Programming
+ (ICALP 1999)},
+year = {1999},
+pages = {595-604},
+ee = {http://dx.doi.org/10.1007/3-540-48523-6_56},
+bibsource = {DBLP, http://dblp.uni-trier.de},
+}
+
+// used in include/sdsl/bp_support_gg.hpp
+ at inproceedings{OHL:GOG:2009,
+author = {Enno Ohlebusch and Simon Gog},
+title = {A Compressed Enhanced Suffix Array Supporting Fast String Matching},
+booktitle = {Proceedings of String Processing and Information Retrieval, 16th International
+ Symposium, (SPIRE 2009)},
+year = {2009},
+pages = {51-62},
+ee = {http://dx.doi.org/10.1007/978-3-642-03784-9_6},
+bibsource = {DBLP, http://dblp.uni-trier.de},
+}
+
+// used in include/sdsl/select_support_mcl.hpp
+ at phdthesis{CLA:1996,
+title = {Compact Pat Trees},
+author = {David Clark},
+year = {1996},
+school = {Department of Computer Science, University of Waterloo},
+ee = {http://www.nlc-bnc.ca/obj/s4/f2/dsk3/ftp04/nq21335.pdf},
+}
+
+// use gamma code for csa_sada
+ at inproceedings{GRO:GUP:VIT:2004,
+author = {Roberto Grossi and Ankur Gupta and Jeffrey Scott Vitter},
+title = {When indexing equals compression: experiments with compressing suffix arrays and applications},
+booktitle = {Processings of the Fifteenth Annual ACM-SIAM Symposium on Discrete Algorithms (SODA 2004)},
+year = {2004},
+pages = {636-645},
+ee = {http://dl.acm.org/citation.cfm?id=982792.982888},
+}
diff --git a/extras/pre-commit b/extras/pre-commit
new file mode 100644
index 0000000..9023a35
--- /dev/null
+++ b/extras/pre-commit
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Astyle code formatting. This file is an adapted version of the pre-commit
+# file of the SDF3 project. It can be found here:
+# http://www.es.ele.tue.nl/sdf3/manuals/development/files/pre-commit
+#
+# Changes by Matthias Petri.
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+ # Note that the use of brackets around a tr range is ok here, (it's
+ # even required, for portability to Solaris 10's /usr/bin/tr), since
+ # the square bracket bytes happen to fall in the designated range.
+ test "$(git diff --cached --name-only --diff-filter=A -z $against |
+ LC_ALL=C tr -d '[ -~]\0')"
+then
+ echo "Error: Attempt to add a non-ascii file name."
+ echo
+ echo "This can cause problems if you want to work"
+ echo "with people on other platforms."
+ echo
+ echo "To be portable it is advisable to rename the file ..."
+ echo
+ echo "If you know what you are doing you can disable this"
+ echo "check using:"
+ echo
+ echo " git config hooks.allownonascii true"
+ echo
+ exit 1
+fi
+
+version=`astyle --version 2> /dev/null`
+if test "x$version" != "x"; then
+echo "git pre-receive hook:"
+echo "Did not find astyle, please install it before continuing."
+exit 1
+fi
+ASTYLE=astyle
+
+case `$ASTYLE --version 2> /dev/null` in
+ Artistic*)
+ ;;
+ default)
+ echo "git pre-commit hook:"
+ echo "Did not find astyle, please install it before continuing."
+ exit 1
+ ;;
+esac
+
+ASTYLE_PARAMETERS="--suffix=none \
+ --style=linux \
+ --indent=spaces=4 \
+ --indent-switches \
+ --indent-classes \
+ --unpad-paren \
+ --align-pointer=type \
+ --keep-one-line-statements\
+ --keep-one-line-blocks\
+ --pad-header"
+
+echo "--Formatting source code--"
+
+files=`git-diff-index --diff-filter=ACMR --name-only -r --cached $against --`
+for file in $files; do
+ x=`echo $file |grep -E '^.*(\.cc|\.h|\.cpp|\.c|\.hpp)$'`
+ if test "x$x" != "x"; then
+ $ASTYLE ${ASTYLE_PARAMETERS} $file
+ git add $file
+ fi
+done
+
+echo "--Formatting source code done--"
+
diff --git a/extras/resources/space-vis.png b/extras/resources/space-vis.png
new file mode 100644
index 0000000..38713a0
Binary files /dev/null and b/extras/resources/space-vis.png differ
diff --git a/extras/sdsl.gdb b/extras/sdsl.gdb
new file mode 100644
index 0000000..55bfeb9
--- /dev/null
+++ b/extras/sdsl.gdb
@@ -0,0 +1,70 @@
+#
+# SDSL data structure inspector for GDB
+#
+# Inspired by the STL equivalent from
+# http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt
+#
+# Copy the content of this file in your .gdbinit file to
+# use the functions.
+#
+# The following SDSL containers are currently supported:
+#
+# sdsl::int_vector<w> -- via the pv command
+
+#
+# sdsl::int_vector
+#
+
+define pv
+ if $argc == 0
+ help pv
+ else
+ set $width= $arg0.m_width
+ set $size = $arg0.m_size / $width
+ end
+ set $i = 0
+ set $end = $size-1
+ if $argc == 2
+ set $i = $arg1
+ set $end = $arg1
+ end
+ if $argc == 3
+ set $i = $arg1
+ set $end = $arg2
+ if $end > $size-1
+ printf "ERROR: end=%u > %u=size-1. Please specify a valid range.", $end, $size-1
+ set $i=1
+ set $end=1
+ end
+ end
+ while $i <= $end
+ set $offset = ($i*$width)%64
+ set $word = ($arg0.m_data+(($i*$width)/64))
+ set $value = 0
+ if $width > 0
+ set $w1=(*$word)>>$offset
+ if $offset+$width > 64
+ set $s=64-(($offset+$width)&0x3F)
+ set $value = $w1 | ((((*($word+1))<<$s)>>$s)<<(64-$offset))
+ else
+ set $s=64-$width
+ set $value = ($w1<<$s)>>$s
+ end
+ end
+ printf "elem[%u]: %u\n ", $i, $value
+ set $i++
+ end
+ if $argc > 0
+ printf "int_vector size = %u\n", $size
+ end
+end
+
+document pv
+ Prints std::int_vector<width> information.
+ Syntax: pv <int_vector> <idx1> <idx2>
+ Note: idx, idx1 and idx2 must be in the range [0..<int_vector>.size()-1].
+ Examples:
+ pv v - Prints vector content, size, capacity and T typedef
+ pv v 0 - Prints element[idx] from int_vector
+ pv v 1 2 - Prints elements in range [idx1..idx2] from int_vector
+end
diff --git a/extras/sdsl_definitions.sty b/extras/sdsl_definitions.sty
new file mode 100644
index 0000000..3d7f9f1
--- /dev/null
+++ b/extras/sdsl_definitions.sty
@@ -0,0 +1,13 @@
+\newcommand{\Order}[1]{\mathcal{O}(#1)} % big O-Notation
+\newcommand{\order}[1]{\mathcal{o}(#1)} % small o-Notation
+
+\newcommand{\lcpaccess}[0]{\ensuremath{t_{LCP}}}
+\newcommand{\saaccess}[0]{\ensuremath{t_{SA}}}
+\newcommand{\isaaccess}[0]{\ensuremath{t_{SA^{-1}}}}
+\newcommand{\rrenclose}[0]{\ensuremath{t_{\mathit{rr-enclose}}}}
+
+\newcommand{\CSA}[0]{\ensuremath{\mathcal{CSA}}}
+\newcommand{\CST}[0]{\ensuremath{\mathcal{CST}}}
+
+\newcommand{\SUF}[0]{\ensuremath{\mathcal{SA}}}
+\newcommand{\ISA}[0]{\ensuremath{\mathcal{SA}^{-1}}}
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
new file mode 100644
index 0000000..a42a4cc
--- /dev/null
+++ b/include/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(sdsl)
diff --git a/include/sdsl/.gitignore b/include/sdsl/.gitignore
new file mode 100644
index 0000000..bdccc78
--- /dev/null
+++ b/include/sdsl/.gitignore
@@ -0,0 +1,6 @@
+*
+!experimental/
+!CMakeLists.txt
+!.gitignore
+!*.hpp
+!*.cmake
diff --git a/include/sdsl/CMakeLists.txt b/include/sdsl/CMakeLists.txt
new file mode 100644
index 0000000..ef921f0
--- /dev/null
+++ b/include/sdsl/CMakeLists.txt
@@ -0,0 +1,17 @@
+include(CheckIncludeFile)
+include(CheckIncludeFileCXX)
+include(CheckTypeSize)
+
+## Check for header files ##
+check_include_file_CXX(cstdio HAVE_STDIO)
+
+## copy hpp files to the binary tree ##
+
+file(GLOB hppFiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") # select all .hpp-files
+
+foreach(hppFile ${hppFiles}) # copy each file
+ configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/${hppFile}" "${CMAKE_CURRENT_BINARY_DIR}/${hppFile}" COPYONLY )
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${hppFile}" DESTINATION include/sdsl)
+# MESSAGE(${hppFile})
+endforeach(hppFile)
+
diff --git a/include/sdsl/bit_vector_il.hpp b/include/sdsl/bit_vector_il.hpp
new file mode 100644
index 0000000..9ebf63e
--- /dev/null
+++ b/include/sdsl/bit_vector_il.hpp
@@ -0,0 +1,488 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog, Matthias Petri
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*!\file bit_vector_il.hpp
+ \brief bit_vector_il.hpp contains the sdsl::bit_vector_il class, and
+ classes which support rank and select for bit_vector_il.
+ \author Matthias Petri, Simon Gog
+*/
+#ifndef SDSL_BIT_VECTOR_IL
+#define SDSL_BIT_VECTOR_IL
+
+#include "int_vector.hpp"
+#include "util.hpp"
+#include "iterators.hpp"
+
+#include <queue>
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+
+template<uint8_t t_b=1,uint32_t t_bs=512>// forward declaration needed for friend declaration
+class rank_support_il; // in bit_vector_il
+
+template<uint8_t t_b=1,uint32_t t_bs=512>// forward declaration needed for friend declaration
+class select_support_il; // in bit_vector_il
+
+template<class T>
+constexpr bool power_of_two(T x)
+{
+ return std::is_integral<T>::value and x > 1 and
+ !(x&(x-1));
+}
+
+//! A bit vector which interleaves the original bit_vector with rank information.
+/*!
+ * This class is a uncompressed bit vector representation. It copies the original
+ * bit_vector and interleaves the data every t_bs bits with a cumulative
+ * sum of set bits before the current position. Each cumulative sum is stored
+ * in a 64 bit word.
+ *
+ * \tparam t_bs Block size in bits. t_bs has to be a power of 2 and t_bs >= 64.
+ */
+template<uint32_t t_bs=512>
+class bit_vector_il
+{
+ static_assert(t_bs >= 64 , "bit_vector_il: blocksize must be be at least 64 bits.");
+ static_assert(power_of_two(t_bs), "bit_vector_il: blocksize must be a power of two.");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef size_type value_type;
+ typedef bit_vector::difference_type difference_type;
+ typedef random_access_const_iterator<bit_vector_il> iterator;
+ typedef bv_tag index_category;
+
+ friend class rank_support_il<1,t_bs>;
+ friend class rank_support_il<0,t_bs>;
+ friend class select_support_il<1,t_bs>;
+ friend class select_support_il<0,t_bs>;
+
+ typedef rank_support_il<1,t_bs> rank_1_type;
+ typedef rank_support_il<0,t_bs> rank_0_type;
+ typedef select_support_il<1,t_bs> select_1_type;
+ typedef select_support_il<0,t_bs> select_0_type;
+ private:
+ size_type m_size = 0; //!< Size of the original bitvector
+ size_type m_block_num = 0; //!< Total size of m_data in uint64_t ss
+ size_type m_superblocks = 0; //!< Number of superblocks
+ size_type m_block_shift = 0;
+ int_vector<64> m_data; //!< Data container
+ int_vector<64> m_rank_samples;//!< Space for additional rank samples
+
+ // precondition: m_rank_samples.size() <= m_superblocks
+ void init_rank_samples() {
+ uint32_t blockSize_U64 = bits::hi(t_bs>>6);
+ size_type idx = 0;
+ std::queue<size_type> lbs, rbs;
+ lbs.push(0); rbs.push(m_superblocks);
+ while (!lbs.empty()) {
+ size_type lb = lbs.front(); lbs.pop();
+ size_type rb = rbs.front(); rbs.pop();
+ if (/*lb < rb and*/ idx < m_rank_samples.size()) {
+ size_type mid = lb + (rb-lb)/2; // select mid \in [lb..rb)
+ size_type pos = (mid << blockSize_U64) + mid;
+ m_rank_samples[ idx++ ] = m_data[pos];
+ lbs.push(lb); rbs.push(mid);
+ lbs.push(mid+1); rbs.push(rb);
+ }
+ }
+ }
+
+ public:
+ bit_vector_il() {}
+ bit_vector_il(const bit_vector_il&) = default;
+ bit_vector_il(bit_vector_il&&) = default;
+ bit_vector_il& operator=(const bit_vector_il&) = default;
+ bit_vector_il& operator=(bit_vector_il&&) = default;
+
+ bit_vector_il(const bit_vector& bv) {
+ m_size = bv.size();
+ /* calculate the number of superblocks */
+// each block of size > 0 gets suberblock in which we store the cumulative sum up to this block
+ m_superblocks = (m_size+t_bs) / t_bs;
+ m_block_shift = bits::hi(t_bs);
+ /* allocate new data */
+ size_type blocks = (m_size+64)/64;
+ size_type mem = blocks + m_superblocks + 1;
+// ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^
+// bit vector data | cum. sum data | sum after last block
+ m_data = int_vector<64>(mem);
+ m_block_num = mem;
+
+ /* assign data and calculate super block values */
+ const uint64_t* bvp = bv.data();
+
+ size_type j = 0; // 64-bit word counter in the m_data
+ size_type cum_sum = 0;
+ size_type sample_rate = t_bs/64;
+ for (size_type i=0, sample_cnt=sample_rate; i < blocks; ++i, ++sample_cnt) {
+ if (sample_cnt == sample_rate) {
+ m_data[j] = cum_sum;
+ sample_cnt = 0;
+ j++;
+ }
+ m_data[j] = bvp[i];
+ cum_sum += bits::cnt(m_data[j]);
+ j++;
+ }
+ m_data[j] = cum_sum; /* last superblock so we can always
+ get num_ones fast */
+ if (m_block_num > 1024*64) {
+ // we store at most m_superblocks+1 rank_samples:
+ // we do a cache efficient binary search for the select on X=1024
+ // or X=the smallest power of two smaller than m_superblock
+ m_rank_samples.resize(std::min(1024ULL, 1ULL << bits::hi(m_superblocks)));
+ }
+ init_rank_samples();
+ }
+
+ //! Accessing the i-th element of the original bit_vector
+ /*! \param i An index i with \f$ 0 \leq i < size() \f$.
+ * \return The i-th bit of the original bit_vector
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < m_size);
+ size_type bs = i >> m_block_shift;
+ size_type block = bs + (i>>6) + 1;
+ return ((m_data[block] >> (i&63)) & 1ULL);
+ }
+
+ //! Get the integer value of the binary string of length len starting at position idx.
+ /*! \param idx Starting index of the binary representation of the integer.
+ * \param len Length of the binary representation of the integer. Default value is 64.
+ * \returns The integer value of the binary string of length len starting at position idx.
+ *
+ * \pre idx+len-1 in [0..size()-1]
+ * \pre len in [1..64]
+ */
+ uint64_t get_int(size_type idx, uint8_t len=64)const {
+ assert(idx+len-1 < m_size);
+ size_type bs = idx >> m_block_shift;
+ size_type b_block = bs + (idx>>6) + 1;
+ bs = (idx+len-1) >> m_block_shift;
+ size_type e_block = bs + ((idx+len-1)>>6) + 1;
+ if (b_block == e_block) { // spans on block
+ return (m_data[b_block] >> (idx&63)) & bits::lo_set[len];
+ } else { // spans two blocks
+ uint8_t b_len = 64-(idx&63);
+ return (m_data[b_block] >> (idx&63))
+ | (m_data[e_block] & bits::lo_set[len-b_len]) << b_len;
+ }
+ }
+
+ //! Returns the size of the original bit vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_block_num, out, child, "block_num");
+ written_bytes += write_member(m_superblocks, out, child, "superblocks");
+ written_bytes += write_member(m_block_shift, out, child, "block_shift");
+ written_bytes += m_data.serialize(out, child, "data");
+ written_bytes += m_rank_samples.serialize(out, child, "rank_samples");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_block_num, in);
+ read_member(m_superblocks, in);
+ read_member(m_block_shift, in);
+ m_data.load(in);
+ m_rank_samples.load(in);
+ }
+
+ void swap(bit_vector_il& bv) {
+ if (this != &bv) {
+ std::swap(m_size, bv.m_size);
+ std::swap(m_block_num, bv.m_block_num);
+ std::swap(m_superblocks, bv.m_superblocks);
+ std::swap(m_block_shift, bv.m_block_shift);
+ m_data.swap(bv.m_data);
+ m_rank_samples.swap(bv.m_rank_samples);
+ }
+ }
+
+ iterator begin() const {
+ return iterator(this, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, size());
+ }
+};
+
+template<uint8_t t_b, uint32_t t_bs>
+class rank_support_il
+{
+ static_assert(t_b == 1 or t_b == 0 , "rank_support_il only supports bitpatterns 0 or 1.");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef bit_vector_il<t_bs> bit_vector_type;
+ enum { bit_pat = t_b };
+ private:
+ const bit_vector_type* m_v;
+ size_type m_block_shift;
+ size_type m_block_mask;
+ size_type m_block_size_U64; //! Size of superblocks in 64-bit words
+
+ inline size_type rank1(size_type i) const {
+ size_type SBlockNum = i >> m_block_shift;
+ size_type SBlockPos = (SBlockNum << m_block_size_U64) + SBlockNum;
+ uint64_t resp = m_v->m_data[SBlockPos];
+ const uint64_t* B = (m_v->m_data.data() + (SBlockPos+1));
+ uint64_t rem = i&63;
+ uint64_t bits = (i&m_block_mask) - rem;
+ while (bits) {
+ resp += bits::cnt(*B++);
+ bits -= 64;
+ }
+ resp += bits::cnt(*B & bits::lo_set[rem]);
+ return resp;
+ }
+
+
+ inline size_type rank0(size_type i) const {
+ size_type SBlockNum = i >> m_block_shift;
+ size_type SBlockPos = (SBlockNum << m_block_size_U64) + SBlockNum;
+ uint64_t resp = (SBlockNum << m_block_shift) - m_v->m_data[SBlockPos];
+ const uint64_t* B = (m_v->m_data.data() + (SBlockPos+1));
+ uint64_t rem = i&63;
+ uint64_t bits = (i&m_block_mask) - rem;
+ while (bits) {
+ resp += bits::cnt(~(*B)); B++;
+ bits -= 64;
+ }
+ resp += bits::cnt((~(*B)) & bits::lo_set[rem]);
+ return resp;
+ }
+
+ public:
+
+ rank_support_il(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ m_block_shift = bits::hi(t_bs);
+ m_block_mask = t_bs - 1;
+ m_block_size_U64 = bits::hi(t_bs>>6);
+ }
+
+ //! Returns the position of the i-th occurrence in the bit vector.
+ size_type rank(size_type i) const {
+ if (t_b) return rank1(i);
+ return rank0(i);
+ }
+
+ size_type operator()(size_type i)const {
+ return rank(i);
+ }
+
+ size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ rank_support_il& operator=(const rank_support_il& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(rank_support_il&) { }
+
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return serialize_empty_object(out, v, name, this);
+ }
+};
+
+
+template<uint8_t t_b, uint32_t t_bs>
+class select_support_il
+{
+ static_assert(t_b == 1 or t_b == 0 , "select_support_il only supports bitpatterns 0 or 1.");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef bit_vector_il<t_bs> bit_vector_type;
+ enum { bit_pat = t_b };
+ private:
+ const bit_vector_type* m_v;
+ size_type m_superblocks;
+ size_type m_block_shift;
+ size_type m_block_size_U64;
+
+ //! Returns the position of the i-th occurrence in the bit vector.
+ size_type select1(size_type i) const {
+ size_type lb = 0, rb = m_v->m_superblocks; // search interval [lb..rb)
+ size_type res = 0;
+ size_type idx = 0; // index in m_rank_samples
+ /* binary search over super blocks */
+ // invariant: lb==0 or m_data[ pos(lb-1) ] < i
+ // m_data[ pos(rb) ] >= i, initial since i < rank(size())
+ while (lb < rb) {
+ size_type mid = (lb+rb)/2; // select mid \in [lb..rb)
+#ifndef NOSELCACHE
+ if (idx < m_v->m_rank_samples.size()) {
+ if (m_v->m_rank_samples[idx] >= i) {
+ idx = (idx<<1) + 1;
+ rb = mid;
+ } else {
+ idx = (idx<<1) + 2;
+ lb = mid + 1;
+ }
+ } else {
+#endif
+ size_type pos = (mid << m_block_size_U64) + mid;
+// ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
+// data blocks to jump superblock position
+ if (m_v->m_data[pos] >= i) {
+ rb = mid;
+ } else {
+ lb = mid + 1;
+ }
+#ifndef NOSELCACHE
+ }
+#endif
+ }
+ res = (rb-1) << m_block_shift;
+ /* iterate in 64 bit steps */
+ const uint64_t* w = m_v->m_data.data() + ((rb-1) << m_block_size_U64) + (rb-1);
+ i -= *w; // subtract the cumulative sum before the superblock
+ ++w; /* step into the data */
+ size_type ones = bits::cnt(*w);
+ while (ones < i) {
+ i -= ones; ++w;
+ ones = bits::cnt(*w);
+ res += 64;
+ }
+ /* handle last word */
+ res += bits::sel(*w, i);
+ return res;
+ }
+
+ //! Returns the position of the i-th occurrence in the bit vector.
+ size_type select0(size_type i)const {
+ size_type lb = 0, rb = m_v->m_superblocks; // search interval [lb..rb)
+ size_type res = 0;
+ size_type idx = 0; // index in m_rank_samples
+ /* binary search over super blocks */
+ // invariant: lb==0 or m_data[ pos(lb-1) ] < i
+ // m_data[ pos(rb) ] >= i, initial since i < rank(size())
+ while (lb < rb) {
+ size_type mid = (lb+rb)/2; // select mid \in [lb..rb)
+#ifndef NOSELCACHE
+ if (idx < m_v->m_rank_samples.size()) {
+ if (((mid << m_block_shift) - m_v->m_rank_samples[idx]) >= i) {
+ idx = (idx<<1) + 1;
+ rb = mid;
+ } else {
+ idx = (idx<<1) + 2;
+ lb = mid + 1;
+ }
+ } else {
+#endif
+ size_type pos = (mid << m_block_size_U64) + mid;
+// ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
+// data blocks to jump superblock position
+ if (((mid << m_block_shift) - m_v->m_data[pos]) >= i) {
+ rb = mid;
+ } else {
+ lb = mid + 1;
+ }
+#ifndef NOSELCACHE
+ }
+#endif
+ }
+ res = (rb-1) << m_block_shift;
+
+ /* iterate in 64 bit steps */
+ const uint64_t* w = m_v->m_data.data() + ((rb-1) << m_block_size_U64) + (rb-1);
+ i = i - (res - *w); // substract the cumulative sum before the superblock
+ ++w; /* step into the data */
+ size_type zeros = bits::cnt(~ *w);
+ while (zeros < i) {
+ i -= zeros; ++w;
+ zeros = bits::cnt(~ *w);
+ res += 64;
+ }
+ /* handle last word */
+ res += bits::sel(~ *w, i);
+ return res;
+ }
+
+ public:
+
+ select_support_il(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ m_block_shift = bits::hi(t_bs);
+ m_block_size_U64 = bits::hi(t_bs>>6);
+
+ }
+
+ //! Returns the position of the i-th occurrence in the bit vector.
+ size_type select(size_type i) const {
+ if (t_b) return select1(i);
+ return select0(i);
+ }
+
+ size_type operator()(size_type i)const {
+ return select(i);
+ }
+
+ size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ select_support_il& operator=(const select_support_il& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(select_support_il&) { }
+
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return serialize_empty_object(out, v, name, this);
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/bit_vectors.hpp b/include/sdsl/bit_vectors.hpp
new file mode 100644
index 0000000..06e0b4f
--- /dev/null
+++ b/include/sdsl/bit_vectors.hpp
@@ -0,0 +1,13 @@
+/*! \file bit_vectors.hpp
+ \brief bit_vectors.hpp contains classes for uncompressed and compressed bit vector representations.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_BITVECTORS
+#define INCLUDED_SDSL_BITVECTORS
+
+#include "int_vector.hpp"
+#include "bit_vector_il.hpp"
+#include "rrr_vector.hpp"
+#include "sd_vector.hpp"
+
+#endif
diff --git a/include/sdsl/bits.hpp b/include/sdsl/bits.hpp
new file mode 100644
index 0000000..b13fe79
--- /dev/null
+++ b/include/sdsl/bits.hpp
@@ -0,0 +1,624 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file bits.hpp
+ \brief bits.hpp contains the sdsl::bits class.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_BITS
+#define INCLUDED_SDSL_BITS
+
+#include <stdint.h> // for uint64_t uint32_t declaration
+#include <iostream>// for cerr
+#include <cassert>
+#ifdef __SSE4_2__
+#include <xmmintrin.h>
+#endif
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A helper class for bitwise tricks on 64 bit words.
+/*!
+ bits is a helper class for bitwise tricks and
+ techniques. For the basic tricks and techiques we refer to Donald E. Knuth's
+ "The Art of Computer Programming", Volume 4A, Chapter 7.1.3 and
+ the informative website of Sean E. Anderson about the topic:
+ http://www-graphics.stanford.edu/~seander/bithacks.html .
+
+ We have added new functions like: cnt11 and sel11.
+
+ All members of this class are static variables or methods.
+ This class cannot be instantiated.
+
+ \author Simon Gog
+ */
+struct bits {
+ bits() = delete;
+ //! 64bit mask with all bits set to 1.
+ constexpr static int64_t all_set {-1LL};
+
+ //! This constant represents a de Bruijn sequence B(k,n) for k=2 and n=6.
+ /*! Details for de Bruijn sequences see
+ http://en.wikipedia.org/wiki/De_bruijn_sequence
+ deBruijn64 is used in combination with the
+ array lt_deBruijn_to_idx.
+ */
+ constexpr static uint64_t deBruijn64 {0x0218A392CD3D5DBFULL};
+
+ //! This table maps a 6-bit subsequence S[idx...idx+5] of constant deBruijn64 to idx.
+ /*! \sa deBruijn64
+ */
+ static const uint32_t lt_deBruijn_to_idx[64];
+
+ //! Array containing Fibonacci numbers less than \f$2^64\f$.
+ static const uint64_t lt_fib[92];
+
+ //! Lookup table for byte popcounts.
+ static const uint8_t lt_cnt[256];
+
+ //! Lookup table for most significant set bit in a byte.
+ static const uint32_t lt_hi[256];
+
+ //! lo_set[i] is a 64-bit word with the i least significant bits set and the high bits not set.
+ /*! lo_set[0] = 0ULL, lo_set[1]=1ULL, lo_set[2]=3ULL...
+ */
+ static const uint64_t lo_set[65];
+
+ //! lo_unset[i] is a 64-bit word with the i least significant bits not set and the high bits set.
+ /*! lo_unset[0] = FFFFFFFFFFFFFFFFULL, lo_unset_set[1]=FFFFFFFFFFFFFFFEULL, ...
+ */
+ static const uint64_t lo_unset[65];
+
+ //! Lookup table for least significant set bit in a byte.
+ static const uint8_t lt_lo[256];
+
+ //! Lookup table for select on bytes.
+ /*! Entry at idx = 256*j + i equals the position of the
+ (j+1)-th set bit in byte i. Positions lie in the range \f$[0..7]\f$.
+ */
+ static const uint8_t lt_sel[256*8];
+
+ //! Use to help to decide if a prefix sum stored in a byte overflows.
+ static const uint64_t ps_overflow[65];
+
+ //! Counts the number of set bits in x.
+ /*! \param x 64-bit word
+ \return Number of set bits.
+ */
+ static uint64_t cnt(uint64_t x);
+
+ //! Position of the most significant set bit the 64-bit word x
+ /*! \param x 64-bit word
+ \return The position (in 0..63) of the least significant set bit
+ in `x` or 0 if x equals 0.
+ \sa sel, lo
+ */
+ static uint32_t hi(uint64_t x);
+
+ //! Calculates the position of the rightmost 1-bit in the 64bit integer x if it exists
+ /*! \param x 64 bit integer.
+ \return The position (in 0..63) of the rightmost 1-bit in the 64bit integer x if
+ x>0 and 0 if x equals 0.
+ \sa sel, hi
+ */
+ static uint32_t lo(uint64_t x);
+
+ //! Counts the number of 1-bits in the 32bit integer x.
+ /*! This function is a variant of the method cnt. If
+ 32bit multiplication is fast, this method beats the cnt.
+ for 32bit integers.
+ \param x 64bit integer to count the bits.
+ \return The number of 1-bits in x.
+ */
+ static uint32_t cnt32(uint32_t x);
+
+ //! Count the number of consecutive and distinct 11 in the 64bit integer x.
+ /*!
+ \param x 64bit integer to count the terminating sequence 11 of a Fibonacci code.
+ \param c Carry equals msb of the previous 64bit integer.
+ */
+ static uint32_t cnt11(uint64_t x, uint64_t& c);
+
+ //! Count the number of consecutive and distinct 11 in the 64bit integer x.
+ /*!
+ \param x 64bit integer to count the terminating sequence 11 of a Fibonacci code.
+ */
+ static uint32_t cnt11(uint64_t x);
+
+ //! Count 10 bit pairs in the word x.
+ /*!
+ * \param x 64bit integer to count the 10 bit pairs.
+ * \param c Carry equals msb of the previous 64bit integer.
+ */
+ static uint32_t cnt10(uint64_t x, uint64_t& c);
+
+ //! Count 01 bit pairs in the word x.
+ /*!
+ * \param x 64bit integer to count the 01 bit pairs.
+ * \param c Carry equals msb of the previous 64bit integer.
+ */
+ static uint32_t cnt01(uint64_t x, uint64_t& c);
+
+ //! Map all 10 bit pairs to 01 or 1 if c=1 and the lsb=0. All other pairs are mapped to 00.
+ static uint64_t map10(uint64_t x, uint64_t c=0);
+
+ //! Map all 01 bit pairs to 01 of 1 if c=1 and the lsb=0. All other pairs are mapped to 00.
+ static uint64_t map01(uint64_t x, uint64_t c=1);
+
+ //! Calculate the position of the i-th rightmost 1 bit in the 64bit integer x
+ /*!
+ \param x 64bit integer.
+ \param i Argument i must be in the range \f$[1..cnt(x)]\f$.
+ \pre Argument i must be in the range \f$[1..cnt(x)]\f$.
+ \sa hi, lo
+ */
+ static uint32_t sel(uint64_t x, uint32_t i);
+ static uint32_t _sel(uint64_t x, uint32_t i);
+
+ //! Calculates the position of the i-th rightmost 11-bit-pattern which terminates a Fibonacci coded integer in x.
+ /*! \param x 64 bit integer.
+ \param i Index of 11-bit-pattern. \f$i \in [1..cnt11(x)]\f$
+ \param c Carry bit from word before
+ \return The position (in 1..63) of the i-th 11-bit-pattern which terminates a Fibonacci coded integer in x if
+ x contains at least i 11-bit-patterns and a undefined value otherwise.
+ \sa cnt11, hi11, sel
+
+ */
+ static uint32_t sel11(uint64_t x, uint32_t i, uint32_t c=0);
+
+ //! Calculates the position of the leftmost 11-bit-pattern which terminates a Fibonacci coded integer in x.
+ /*! \param x 64 bit integer.
+ \return The position (in 1..63) of the leftmost 1 of the leftmost 11-bit-pattern which
+ terminates a Fibonacci coded integer in x if x contains a 11-bit-pattern
+ and 0 otherwise.
+ \sa cnt11, sel11
+ */
+ static uint32_t hi11(uint64_t x);
+
+ //! Writes value x to an bit position in an array.
+ static void write_int(uint64_t* word, uint64_t x, const uint8_t offset=0, const uint8_t len=64);
+
+ //! Writes value x to an bit position in an array and moves the bit-pointer.
+ static void write_int_and_move(uint64_t*& word, uint64_t x, uint8_t& offset, const uint8_t len);
+
+ //! Reads a value from a bit position in an array.
+ static uint64_t read_int(const uint64_t* word, uint8_t offset=0, const uint8_t len=64);
+
+ //! Reads a value from a bit position in an array and moved the bit-pointer.
+ static uint64_t read_int_and_move(const uint64_t*& word, uint8_t& offset, const uint8_t len=64);
+
+ //! Reads an unary decoded value from a bit position in an array.
+ static uint64_t read_unary(const uint64_t* word, uint8_t offset=0);
+
+ //! Reads an unary decoded value from a bit position in an array and moves the bit-pointer.
+ static uint64_t read_unary_and_move(const uint64_t*& word, uint8_t& offset);
+
+ //! Move the bit-pointer (=uint64_t word and offset) `len` to the right.
+ /*!\param word 64-bit word part of the bit pointer
+ * \param offset Offset part of the bit pointer
+ * \param len Move distance. \f$ len \in [0..64] \f$
+ * \sa move_left
+ */
+ static void move_right(const uint64_t*& word, uint8_t& offset, const uint8_t len);
+
+ //! Move the bit-pointer (=uint64_t word and offset) `len` to the left.
+ /*!\param word 64-bit word part of the bit pointer
+ * \param offset Offset part of the bit pointer
+ * \param len Move distance. \f$ len \in [0..64] \f$
+ * \sa move_right
+ */
+ static void move_left(const uint64_t*& word, uint8_t& offset, const uint8_t len);
+
+ //! Get the first one bit in the interval \f$[idx..\infty )\f$
+ static uint64_t next(const uint64_t* word, uint64_t idx);
+
+ //! Get the one bit with the greatest position in the interval \f$[0..idx]\f$
+ static uint64_t prev(const uint64_t* word, uint64_t idx);
+
+ //! reverses a given 64 bit word
+ static uint64_t rev(uint64_t x);
+};
+
+
+// ============= inline - implementations ================
+
+// see page 11, Knuth TAOCP Vol 4 F1A
+inline uint64_t bits::cnt(uint64_t x)
+{
+#ifdef __SSE4_2__
+ return __builtin_popcountll(x);
+#else
+#ifdef POPCOUNT_TL
+ return lt_cnt[x&0xFFULL] + lt_cnt[(x>>8)&0xFFULL] +
+ lt_cnt[(x>>16)&0xFFULL] + lt_cnt[(x>>24)&0xFFULL] +
+ lt_cnt[(x>>32)&0xFFULL] + lt_cnt[(x>>40)&0xFFULL] +
+ lt_cnt[(x>>48)&0xFFULL] + lt_cnt[(x>>56)&0xFFULL];
+#else
+ x = x-((x>>1) & 0x5555555555555555ull);
+ x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull);
+ x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0full;
+ return (0x0101010101010101ull*x >> 56);
+#endif
+#endif
+}
+
+inline uint32_t bits::cnt32(uint32_t x)
+{
+ x = x-((x>>1) & 0x55555555);
+ x = (x & 0x33333333) + ((x>>2) & 0x33333333);
+ return (0x10101010*x >>28)+(0x01010101*x >>28);
+}
+
+
+inline uint32_t bits::cnt11(uint64_t x, uint64_t& c)
+{
+ // extract "11" 2bit blocks
+ uint64_t ex11 = (x&(x>>1))&0x5555555555555555ULL, t;
+ // extract "10" 2bit blocks
+ uint64_t ex10or01 = (ex11|(ex11<<1))^x;
+
+ x = ex11 | ((t=(ex11|(ex11<<1))+(((ex10or01<<1)&0x5555555555555555ULL)|c))&(ex10or01&0x5555555555555555ULL));
+ c = (ex10or01>>63) or(t < (ex11|(ex11<<1)));
+
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ return (0x0101010101010101ULL*x >> 56);
+}
+
+inline uint32_t bits::cnt11(uint64_t x)
+{
+ // extract "11" 2bit blocks
+ uint64_t ex11 = (x&(x>>1))&0x5555555555555555ULL;
+ // extract "10" 2bit blocks
+ uint64_t ex10or01 = (ex11|(ex11<<1))^x;
+
+ x = ex11 | (((ex11|(ex11<<1))+((ex10or01<<1)&0x5555555555555555ULL))&(ex10or01&0x5555555555555555ULL));
+
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ return (0x0101010101010101ULL*x >> 56);
+}
+
+inline uint32_t bits::cnt10(uint64_t x, uint64_t& c)
+{
+ uint32_t res = cnt((x ^((x<<1) | c)) & (~x));
+ c = (x >> 63);
+ return res;
+}
+
+inline uint64_t bits::map10(uint64_t x, uint64_t c)
+{
+ return ((x ^((x << 1) | c)) & (~x));
+}
+
+inline uint32_t bits::cnt01(uint64_t x, uint64_t& c)
+{
+ uint32_t res = cnt((x ^((x<<1) | c)) & x);
+ c = (x >> 63);
+ return res;
+}
+inline uint64_t bits::map01(uint64_t x, uint64_t c)
+{
+ return ((x ^((x << 1) | c)) & x);
+}
+
+inline uint32_t bits::sel(uint64_t x, uint32_t i)
+{
+#ifdef __SSE4_2__
+ uint64_t s = x, b;
+ s = s-((s>>1) & 0x5555555555555555ULL);
+ s = (s & 0x3333333333333333ULL) + ((s >> 2) & 0x3333333333333333ULL);
+ s = (s + (s >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ s = 0x0101010101010101ULL*s;
+// now s contains 8 bytes s[7],...,s[0]; s[j] contains the cumulative sum
+// of (j+1)*8 least significant bits of s
+ b = (s+ps_overflow[i]) & 0x8080808080808080ULL;
+// ps_overflow contains a bit mask x consisting of 8 bytes
+// x[7],...,x[0] and x[j] is set to 128-j
+// => a byte b[j] in b is >= 128 if cum sum >= j
+
+// __builtin_ctzll returns the number of trailing zeros, if b!=0
+ int byte_nr = __builtin_ctzll(b) >> 3; // byte nr in [0..7]
+ s <<= 8;
+ i -= (s >> (byte_nr<<3)) & 0xFFULL;
+ return (byte_nr << 3) + lt_sel[((i-1) << 8) + ((x>>(byte_nr<<3))&0xFFULL) ];
+#endif
+ return _sel(x, i);
+}
+
+inline uint32_t bits::_sel(uint64_t x, uint32_t i)
+{
+ uint64_t s = x, b; // s = sum
+ s = s-((s>>1) & 0x5555555555555555ULL);
+ s = (s & 0x3333333333333333ULL) + ((s >> 2) & 0x3333333333333333ULL);
+ s = (s + (s >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ s = 0x0101010101010101ULL*s;
+ b = (s+ps_overflow[i]);//&0x8080808080808080ULL;// add something to the partial sums to cause overflow
+ i = (i-1)<<8;
+ if (b&0x0000000080000000ULL) // byte <=3
+ if (b&0x0000000000008000ULL) //byte <= 1
+ if (b&0x0000000000000080ULL)
+ return lt_sel[(x&0xFFULL) + i];
+ else
+ return 8 +lt_sel[(((x>>8)&0xFFULL) + i - ((s&0xFFULL)<<8))&0x7FFULL];//byte 1;
+ else//byte >1
+ if (b&0x0000000000800000ULL) //byte <=2
+ return 16+lt_sel[(((x>>16)&0xFFULL) + i - (s&0xFF00ULL))&0x7FFULL];//byte 2;
+ else
+ return 24+lt_sel[(((x>>24)&0xFFULL) + i - ((s>>8)&0xFF00ULL))&0x7FFULL];//byte 3;
+ else// byte > 3
+ if (b&0x0000800000000000ULL) // byte <=5
+ if (b&0x0000008000000000ULL) //byte <=4
+ return 32+lt_sel[(((x>>32)&0xFFULL) + i - ((s>>16)&0xFF00ULL))&0x7FFULL];//byte 4;
+ else
+ return 40+lt_sel[(((x>>40)&0xFFULL) + i - ((s>>24)&0xFF00ULL))&0x7FFULL];//byte 5;
+ else// byte >5
+ if (b&0x0080000000000000ULL) //byte<=6
+ return 48+lt_sel[(((x>>48)&0xFFULL) + i - ((s>>32)&0xFF00ULL))&0x7FFULL];//byte 6;
+ else
+ return 56+lt_sel[(((x>>56)&0xFFULL) + i - ((s>>40)&0xFF00ULL))&0x7FFULL];//byte 7;
+ return 0;
+}
+
+// using built-in method or
+// 64-bit version of 32-bit proposal of
+// http://www-graphics.stanford.edu/~seander/bithacks.html
+inline uint32_t bits::hi(uint64_t x)
+{
+#ifdef __SSE4_2__
+ if (x == 0)
+ return 0;
+ return 63 - __builtin_clzll(x);
+#else
+ uint64_t t,tt; // temporaries
+ if ((tt = x >> 32)) { // hi >= 32
+ if ((t = tt >> 16)) { // hi >= 48
+ return (tt = t >> 8) ? 56 + lt_hi[tt] : 48 + lt_hi[t];
+ } else { // hi < 48
+ return (t = tt >> 8) ? 40 + lt_hi[t] : 32 + lt_hi[tt];
+ }
+ } else { // hi < 32
+ if ((t = x >> 16)) { // hi >= 16
+ return (tt = t >> 8) ? 24 + lt_hi[tt] : 16 + lt_hi[t];
+ } else { // hi < 16
+ return (tt = x >> 8) ? 8 + lt_hi[tt] : lt_hi[x];
+ }
+ }
+#endif
+}
+
+// details see: http://citeseer.ist.psu.edu/leiserson98using.html
+// or page 10, Knuth TAOCP Vol 4 F1A
+inline uint32_t bits::lo(uint64_t x)
+{
+#ifdef __SSE4_2__
+ if (x==0)
+ return 0;
+ return __builtin_ctzll(x);
+#else
+ if (x&1) return 0;
+ if (x&3) return 1;
+ if (x&7) return 2;
+ if (x&0x7F) { // in average every second random number x can be answered this way
+ return lt_lo[(x&0x7F)>>3]+3;
+ }
+ // x&-x equals x with only the lsb set
+ return lt_deBruijn_to_idx[((x&-x)*deBruijn64)>>58];
+#endif
+}
+
+inline uint32_t bits::hi11(uint64_t x)
+{
+ // extract "11" 2bit blocks
+ uint64_t ex11 = (x&(x>>1))&0x5555555555555555ULL;
+ // extract "10" 2bit blocks
+ uint64_t ex10or01 = (ex11|(ex11<<1))^x;
+ // extract "10" 2bit blocks
+ ex11 += (((ex11|(ex11<<1))+((ex10or01<<1)&0x5555555555555555ULL)) & ((ex10or01&0x5555555555555555ULL)|ex11));
+ return hi(ex11);
+}
+
+
+inline uint32_t bits::sel11(uint64_t x, uint32_t i, uint32_t c)
+{
+ uint64_t ex11 = (x&(x>>1))&0x5555555555555555ULL;
+ uint64_t ex10or01 = (ex11|(ex11<<1))^x;
+ ex11 += (((ex11|(ex11<<1))+(((ex10or01<<1)&0x5555555555555555ULL)|c)) & ((ex10or01&0x5555555555555555ULL)|ex11));
+ return sel(ex11,i);
+}
+
+inline void bits::write_int(uint64_t* word, uint64_t x, uint8_t offset, const uint8_t len)
+{
+ x &= bits::lo_set[len];
+ if (offset + len < 64) {
+ *word &=
+ ((bits::all_set << (offset+len)) | bits::lo_set[offset]); // mask 1..10..01..1
+ *word |= (x << offset);
+// *word ^= ((*word ^ x) & (bits::lo_set[len] << offset) );
+// surprisingly the above line is slower than the lines above
+ } else {
+ *word &=
+ ((bits::lo_set[offset])); // mask 0....01..1
+ *word |= (x << offset);
+ if ((offset = (offset+len)&0x3F)) { // offset+len > 64
+ *(word+1) &= (~bits::lo_set[offset]); // mask 1...10..0
+// *(word+1) &= bits::lo_unset[offset]; // mask 1...10..0
+// surprisingly the above line is slower than the line above
+ *(word+1) |= (x >> (len-offset));
+ }
+ }
+}
+
+inline void bits::write_int_and_move(uint64_t*& word, uint64_t x, uint8_t& offset, const uint8_t len)
+{
+ x &= bits::lo_set[len];
+ if (offset + len < 64) {
+ *word &=
+ ((bits::all_set << (offset+len)) | bits::lo_set[offset]); // mask 1..10..01..1
+ *word |= (x << offset);
+ offset += len;
+ } else {
+ *word &=
+ ((bits::lo_set[offset])); // mask 0....01..1
+ *word |= (x << offset);
+ if ((offset= (offset+len))>64) {// offset+len >= 64
+ offset &= 0x3F;
+ *(++word) &= (~bits::lo_set[offset]); // mask 1...10..0
+ *word |= (x >> (len-offset));
+ } else {
+ offset = 0;
+ ++word;
+ }
+ }
+}
+
+inline uint64_t bits::read_int(const uint64_t* word, uint8_t offset, const uint8_t len)
+{
+ uint64_t w1 = (*word)>>offset;
+ if ((offset+len) > 64) { // if offset+len > 64
+ return w1 | // w1 or w2 adepted:
+ ((*(word+1) & bits::lo_set[(offset+len)&0x3F]) // set higher bits zero
+ << (64-offset)); // move bits to the left
+ } else {
+ return w1 & bits::lo_set[len];
+ }
+}
+
+inline uint64_t bits::read_int_and_move(const uint64_t*& word, uint8_t& offset, const uint8_t len)
+{
+ uint64_t w1 = (*word)>>offset;
+ if ((offset = (offset+len))>=64) { // if offset+len > 64
+ if (offset==64) {
+ offset &= 0x3F;
+ ++word;
+ return w1;
+ } else {
+ offset &= 0x3F;
+ return w1 |
+ (((*(++word)) & bits::lo_set[offset]) << (len-offset));
+ }
+ } else {
+ return w1 & bits::lo_set[len];
+ }
+}
+
+inline uint64_t bits::read_unary(const uint64_t* word, uint8_t offset)
+{
+ uint64_t w = *word >> offset;
+ if (w) {
+ return bits::lo(w);
+ } else {
+ if (0!=(w=*(++word)))
+ return bits::lo(w)+64-offset;
+ uint64_t cnt=2;
+ while (0==(w=*(++word)))
+ ++cnt;
+ return bits::lo(w)+(cnt<<6)-offset;
+ }
+ return 0;
+}
+
+inline uint64_t bits::read_unary_and_move(const uint64_t*& word, uint8_t& offset)
+{
+ uint64_t w = (*word) >> offset; // temporary variable is good for the performance
+ if (w) {
+ uint8_t r = bits::lo(w);
+ offset = (offset + r+1)&0x3F;
+ // we know that offset + r +1 <= 64, so if the new offset equals 0 increase word
+ word += (offset==0);
+ return r;
+ } else {
+ uint8_t rr=0;
+ if (0!=(w=*(++word))) {
+ rr = bits::lo(w)+64-offset;
+ offset = (offset+rr+1)&0x3F;
+ word += (offset==0);
+ return rr;
+ } else {
+ uint64_t cnt_1=1;
+ while (0==(w=*(++word)))
+ ++cnt_1;
+ rr = bits::lo(w)+64-offset;
+ offset = (offset+rr+1)&0x3F;
+ word += (offset==0);
+ return ((cnt_1)<<6) + rr;
+ }
+ }
+ return 0;
+}
+
+inline void bits::move_right(const uint64_t*& word, uint8_t& offset, const uint8_t len)
+{
+ if ((offset+=len)&0xC0) { // if offset >= 65
+ offset&=0x3F;
+ ++word;
+ }
+}
+
+inline void bits::move_left(const uint64_t*& word, uint8_t& offset, const uint8_t len)
+{
+ if ((offset-=len)&0xC0) { // if offset-len<0
+ offset&=0x3F;
+ --word;
+ }
+}
+
+inline uint64_t bits::next(const uint64_t* word, uint64_t idx)
+{
+ word += (idx>>6);
+ if (*word & ~lo_set[idx&0x3F]) {
+ return (idx & ~((size_t)0x3F)) + lo(*word & ~lo_set[idx&0x3F]);
+ }
+ idx = (idx & ~((size_t)0x3F)) + 64;
+ ++word;
+ while (*word==0) {
+ idx += 64;
+ ++word;
+ }
+ return idx + lo(*word);
+}
+
+inline uint64_t bits::prev(const uint64_t* word, uint64_t idx)
+{
+ word += (idx>>6);
+ if (*word & lo_set[(idx&0x3F)+1]) {
+ return (idx & ~((size_t)0x3F)) + hi(*word & lo_set[(idx&0x3F)+1]);
+ }
+ idx = (idx & ~((size_t)0x3F)) - 64;
+ --word;
+ while (*word==0) {
+ idx -= 64;
+ --word;
+ }
+ return idx + hi(*word);
+}
+
+inline uint64_t bits::rev(uint64_t x)
+{
+ x = ((x & 0x5555555555555555ULL) << 1) | ((x & 0xAAAAAAAAAAAAAAAAULL) >> 1);
+ x = ((x & 0x3333333333333333ULL) << 2) | ((x & 0xCCCCCCCCCCCCCCCCULL) >> 2);
+ x = ((x & 0x0F0F0F0F0F0F0F0FULL) << 4) | ((x & 0xF0F0F0F0F0F0F0F0ULL) >> 4);
+ x = ((x & 0x00FF00FF00FF00FFULL) << 8) | ((x & 0xFF00FF00FF00FF00ULL) >> 8);
+ x = ((x & 0x0000FFFF0000FFFFULL) <<16) | ((x & 0xFFFF0000FFFF0000ULL) >>16);
+ x = ((x & 0x00000000FFFFFFFFULL) <<32) | ((x & 0xFFFFFFFF00000000ULL) >>32);
+ return x;
+}
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/bp_support.hpp b/include/sdsl/bp_support.hpp
new file mode 100644
index 0000000..fed80d5
--- /dev/null
+++ b/include/sdsl/bp_support.hpp
@@ -0,0 +1,41 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file bp_support.hpp
+ \brief bp_support.hpp contains several classed which support find_open, find_close, enclose and rr-enclose queries.
+ \author Simon Gog
+*/
+
+#ifndef INCLUDED_SDSL_BP_SUPPORT
+#define INCLUDED_SDSL_BP_SUPPORT
+
+/** \defgroup bps Balanced Parentheses Supports (BPS)
+ * This group contains data structures which supports a sdsl::bit_vector with the following methods:
+ * - find_open
+ * - find_close
+ * - enclose
+ * - double_enclose
+ * - rank
+ * - select
+ * - excess
+ * - rr_enclose
+ */
+
+#include "bp_support_g.hpp"
+#include "bp_support_gg.hpp"
+#include "bp_support_sada.hpp"
+
+#endif
diff --git a/include/sdsl/bp_support_algorithm.hpp b/include/sdsl/bp_support_algorithm.hpp
new file mode 100644
index 0000000..b1cc13b
--- /dev/null
+++ b/include/sdsl/bp_support_algorithm.hpp
@@ -0,0 +1,304 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file bp_support_algorithm.hpp
+ \brief bp_support_algorithm.hpp contains algorithms for balanced parentheses sequences.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_BP_SUPPORT_ALGORITHM
+#define INCLUDED_SDSL_BP_SUPPORT_ALGORITHM
+
+#include "int_vector.hpp" // for bit_vector
+#include <stack> // for calculate_pioneers_bitmap method
+#include <map> // for calculate_pioneers_bitmap method
+#include "sorted_stack_support.hpp"
+
+
+namespace sdsl
+{
+
+// This structure contains lookup tables
+struct excess {
+ static struct impl {
+ // Given an excess value x in [-8,8] and a 8-bit
+ // word w interpreted as parentheses sequence.
+ // near_fwd_pos[(x+8)<<8 | w] contains the minimal position
+ // p in [0..7] where the excess value x is reached, or 8
+ // if x is not reached in w.
+ uint8_t near_fwd_pos[(8-(-8))*256];
+
+ // Given an excess value of x in [-8,8] and a 8-bit
+ // word w interpreted as parentheses sequence.
+ // near_bwd_pos[(x+8)<<8 | w] contains the maximal position
+ // p in [0..7] where the excess value x is reached, or 8
+ // if x is not reached in w.
+ uint8_t near_bwd_pos[(8-(-8))*256];
+
+ // Given a 8-bit word w. word_sum[w] contains the
+ // excess value of w.
+ int8_t word_sum[256];
+
+ // Given a 8-bit word w. min[w] contains the
+ // minimal excess value in w.
+ int8_t min[256];
+
+ // Given a 8-bit word w. min_pos_max[w] contains
+ // the maximal position p in w, where min[w] is
+ // reached
+ int8_t min_pos_max[256];
+
+ // Given an excess value x in [1,8] and a 8-bit
+ // word w interpreted as parentheses sequence.
+ // min_match_pos_packed[w]:[(x-1)*4,x*4] contains
+ // the minimal position, where excess value
+ // -x is reached and 9, if there is no such position.
+ uint32_t min_match_pos_packed[256];
+
+ // Given an excess value x in [1,8] and a 8-bit
+ // word w interpreted as parentheses sequence.
+ // max_match_pos_packed[w]:[(x-1)*4,x*4] contains
+ // the maximal position, where excess value
+ // -x is reached and 9, if there is no such position.
+ uint32_t max_match_pos_packed[256];
+
+ // Given a 8-bit word w. x=min_and_info[w] contains
+ // the following information.
+ // * [0..7] the minimum excess value in w + 8 of an opening parenthesis
+ // * [8..11] the maximal position of the minimal excess value
+ // * [12..15] the number of ones in the word
+ // if w != 0, and 17 for w=0.
+ uint16_t min_open_excess_info[256];
+
+ impl() {
+ for (int32_t x = -8; x < 8; ++x) {
+ for (uint16_t w=0; w < 256; ++w) {
+ uint16_t i = (x+8)<<8|w;
+ near_fwd_pos[i] = 8;
+ int8_t p=0;
+ int8_t excess = 0;
+ do {
+ excess += 1-2*((w&(1<<p))==0);
+ if (excess == x) {
+ near_fwd_pos[i] = p;
+ break;
+ }
+ ++p;
+ } while (p < 8);
+
+ near_bwd_pos[i] = 8;
+ p = 7;
+ excess = 0;
+ do {
+ excess += 1-2*((w&(1<<p))>0);
+ if (excess == x) {
+ near_bwd_pos[i] = p;
+ break;
+ }
+ --p;
+ } while (p > -1);
+ }
+ }
+ int_vector<> packed_mins(1, 0, 32);
+ int_vector<> packed_maxs(1, 0, 32);
+ for (uint16_t w=0; w < 256; ++w) {
+ int8_t excess = 0;
+ int8_t rev_excess = 0;
+ int32_t min_excess_of_open = 17;
+ int32_t min_excess_of_open_pos = 0;
+ uint32_t ones = 0;
+ min[w] = 8;
+ packed_mins[0] = 0x99999999U;
+ packed_maxs[0] = 0x99999999U;
+ packed_mins.width(4);
+ packed_maxs.width(4);
+ for (uint16_t p=0; p<8; ++p) {
+ ones += (w&(1<<p))!=0;
+ excess += 1-2*((w&(1<<p))==0);
+ if (excess <= min[w]) {
+ min[w] = excess;
+ min_pos_max[w] = p;
+ }
+ if (excess < 0 and packed_mins[-excess-1] == 9) {
+ packed_mins[-excess-1] = p;
+ }
+ if (w&(1<<p) and excess+8 <= min_excess_of_open) {
+ min_excess_of_open = excess+8;
+ min_excess_of_open_pos = p;
+ }
+ rev_excess += 1-2*((w&(1<<(7-p)))>0);
+ if (rev_excess < 0 and packed_maxs[-rev_excess-1] == 9) {
+ packed_maxs[-rev_excess-1] = 7-p;
+ }
+ }
+ word_sum[w] = excess;
+ packed_mins.width(32);
+ min_match_pos_packed[w] = packed_mins[0];
+ packed_maxs.width(32);
+ max_match_pos_packed[w] = packed_maxs[0];
+ min_open_excess_info[w] = (min_excess_of_open) |
+ (min_excess_of_open_pos << 8) |
+ (ones << 12);
+ }
+ }
+ } data;
+};
+
+//! Calculate pioneers as defined in the paper of Geary et al. (CPM 2004)
+/*! \param bp The balanced parentheses sequence.
+ * \param block_size Block size.
+ * \return Bitvector which marks the pioneers in bp.
+ * \par Time complexity
+ * \f$ \Order{n \log n} \f$, where \f$ n=\f$bp.size()
+ * \par Space complexity
+ * \f$ \Order{2n + min(block\_size, \frac{n}{block\_size} )\cdot \log n } \f$
+ */
+bit_vector
+calculate_pioneers_bitmap(const bit_vector& bp, uint64_t block_size);
+
+//! Space-efficient version of calculate_pioneers_bitmap
+/*! \param bp The balanced parentheses sequence.
+ * \param block_size Block size.
+ * \return Bitvector which marks the pioneers in bp.
+ * \par Time complexity
+ * \f$ \Order{n} \f$, where \f$ n=\f$bp.size()
+ * \par Space complexity
+ * \f$ \Order{2n + n} \f$ bits: \f$n\f$ bits for input, \f$n\f$ bits for
+ * output, and \f$n\f$ bits for a succinct stack.
+ * \pre The parentheses sequence represented by bp has to be balanced.
+ */
+bit_vector
+calculate_pioneers_bitmap_succinct(const bit_vector& bp, uint64_t block_size);
+
+//! find_open/find_close for closing/opening parentheses.
+/*! \param bp The balanced parentheses sequence.
+ * \param matches Reference to the result.
+ * \pre bp represents a balanced parentheses sequence.
+ * \par Time complexity
+ * \f$ \Order{n} \f$, where \f$ n=\f$bp.size()
+ * \par Space complexity
+ * \f$ \Order{n + 2n\log n } \f$
+ */
+template<class int_vector>
+void calculate_matches(const bit_vector& bp, int_vector& matches)
+{
+ matches = int_vector(bp.size(), 0, bits::hi(bp.size())+1);
+ std::stack<uint64_t> opening_parenthesis;
+ for (uint64_t i=0; i < bp.size(); ++i) {
+ if (bp[i]) {// opening parenthesis
+ opening_parenthesis.push(i);
+ } else { // closing parenthesis
+ assert(!opening_parenthesis.empty());
+ uint64_t position = opening_parenthesis.top();
+ opening_parenthesis.pop();
+ matches[i] = position;
+ assert(matches[i]==position);
+ matches[position] = i;
+ assert(matches[position]==i);
+ }
+ }
+ // assert that the sequence is balanced
+ assert(opening_parenthesis.empty());
+}
+
+//! Calculates enclose answers for a balanced parentheses sequence.
+/*! \param bp A bit_vector representing a balanced parentheses sequence.
+ * \param enclose Reference to the result.
+ * \pre bp represents a balanced parentheses sequence.
+ * \par Time complexity
+ * \f$ \Order{n} \f$, where \f$ n=\f$bp.size()
+ * \par Space complexity
+ * \f$ \Order{n + 2n\log n } \f$
+ */
+template<class int_vector>
+void calculate_enclose(const bit_vector& bp, int_vector& enclose)
+{
+ enclose = int_vector(bp.size(), 0, bits::hi(bp.size())+1);
+ std::stack<uint64_t> opening_parenthesis;
+ for (uint64_t i=0; i < bp.size(); ++i) {
+ if (bp[i]) {// opening parenthesis
+ if (!opening_parenthesis.empty()) {
+ uint64_t position = opening_parenthesis.top();
+ enclose[i] = position;
+ assert(enclose[i]==position);
+ } else
+ enclose[i] = bp.size();
+ opening_parenthesis.push(i);
+ } else { // closing parenthesis
+ uint64_t position = opening_parenthesis.top();
+ enclose[i] = position; // find open answer if i is a closing parenthesis
+ opening_parenthesis.pop();
+ }
+ }
+ // assert that the sequence is balanced
+ assert(opening_parenthesis.empty());
+}
+
+uint64_t
+near_find_close(const bit_vector& bp, const uint64_t i,
+ const uint64_t block_size);
+
+uint64_t
+near_find_closing(const bit_vector& bp, uint64_t i,
+ uint64_t closings,
+ const uint64_t block_size);
+
+uint64_t
+near_fwd_excess(const bit_vector& bp, uint64_t i,
+ bit_vector::difference_type rel, const uint64_t block_size);
+
+//! Calculate the position with minimal excess value in the interval [l..r].
+/*! \param bp The bit_vector which represents the parentheses sequence
+ * \param l The left border of the interval.
+ * \param r The right border of the interval.
+ * \param min_rel_ex Reference to the relative minimal excess value with regards to excess(bp[l])
+ */
+uint64_t
+near_rmq(const bit_vector& bp, uint64_t l, uint64_t r,
+ bit_vector::difference_type& min_rel_ex);
+
+//! Near backward excess
+/* This method searches the maximal parenthesis j, with \f$ j\leq i \f$,
+ * such that \f$ excess(j) = excess(i+1)+rel \f$ and i < bp.size()-1
+ */
+uint64_t
+near_bwd_excess(const bit_vector& bp, uint64_t i,
+ bit_vector::difference_type rel, const uint64_t block_size);
+
+uint64_t
+near_find_open(const bit_vector& bp, uint64_t i, const uint64_t block_size);
+
+uint64_t
+near_find_opening(const bit_vector& bp, uint64_t i, const uint64_t openings,
+ const uint64_t block_size);
+
+//! Find the opening parenthesis of the enclosing pair if this parenthesis is near.
+/*!
+ * \param bp bit_vector containing the representation of the balanced parentheses sequence.
+ * \param i Position of the opening parenthesis for which we search the position of the opening parenthesis of the enclosing parentheses pair.
+ * \param block_size Number of entries to search for the corresponding opening parenthesis of the enclosing parentheses pair.
+ * \return If no near enclose exists return i, otherwise the position of the opening parenthesis of the enclosing pair.
+ * \pre We assert that \f$ bp[i]=1 \f$
+ */
+// TODO: implement a fast version using lookup-tables of size 8
+uint64_t
+near_enclose(const bit_vector& bp, uint64_t i, const uint64_t block_size);
+
+uint64_t
+near_rmq_open(const bit_vector& bp, const uint64_t begin, const uint64_t end);
+
+}// end namespace sdsl
+
+#endif
diff --git a/include/sdsl/bp_support_g.hpp b/include/sdsl/bp_support_g.hpp
new file mode 100644
index 0000000..fd275b6
--- /dev/null
+++ b/include/sdsl/bp_support_g.hpp
@@ -0,0 +1,650 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file bp_support_g.hpp
+ \brief bp_support_g.hpp contains an implementation of a balanced parentheses support data structure.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_BP_SUPPORT_G
+#define INCLUDED_SDSL_BP_SUPPORT_G
+
+#include "int_vector.hpp"
+#include "nearest_neighbour_dictionary.hpp"
+#include "rmq_support.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "bp_support_algorithm.hpp"
+#include "util.hpp"
+#include <stack>
+#include <map>
+#include <set>
+#include <utility>
+#include <stdexcept>
+
+namespace sdsl
+{
+
+//! A class that provides support for bit_vectors that represent a BP sequence.
+/*! This data structure supports the following operations:
+ * - find_open
+ * - find_close
+ * - enclose
+ * - double_enclose
+ * - rank
+ * - select
+ * - excess
+ * - rr_enclose
+ * An opening parenthesis in the balanced parentheses sequence is represented by a 1 in the bit_vector
+ * and a closing parenthesis by a 0.
+ *
+ * \tparam t_nnd Type which supports rank and select with little space on sparse populated bit_vectors.
+ * \tparam t_rank Type of rank support structure.
+ * \tparam t_select Type of select support structure.
+ * \tparam t_rmq Type which supports range maximum queries on a int_vector<>.
+ * \par Reference
+ * Richard F. Geary, Naila Rahman, Rajeev Raman, Venkatesh Raman:
+ * A Simple Optimal Representation for Balanced Parentheses.
+ * CPM 2004: 159-172
+ *
+ * @ingroup bps
+ */
+template<class t_nnd = nearest_neighbour_dictionary<30>,
+ class t_rank = rank_support_v5<>,
+ class t_select = select_support_mcl<>,
+ class t_rmq = range_maximum_support_sparse_table<>,
+ uint32_t t_bs=840>
+class bp_support_g
+{
+ static_assert(t_bs > 2, "bp_support_g: block size must be greater than 2.");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef t_nnd nnd_type;
+ typedef t_rank rank_type;
+ typedef t_select select_type;
+ typedef t_rmq rmq_type;
+ private:
+ const bit_vector* m_bp; // the supported BP sequence as bit_vector
+ rank_type m_rank_bp; // rank support for the BP sequence => see excess() and rank()
+ select_type m_select_bp; // select support for the BP sequence => see select()
+
+ nnd_type m_nnd; // nearest neighbour dictionary for pioneers bit_vector
+
+ bit_vector m_pioneer_bp; // first level of recursion: BP sequence of the pioneers
+ rank_type m_rank_pioneer_bp;// rank for the BP sequence of the pioneers
+ nnd_type m_nnd2; // nearest neighbour dictionary for pioneers of pioneers bit_vector
+ int_vector<> m_match; //
+ int_vector<> m_enclose; //
+ rmq_type m_range_max_match;// range maximum support for m_match
+
+ size_type m_size;
+ size_type m_blocks; // number of blocks
+
+ void copy(const bp_support_g& bp_support) {
+ m_bp = bp_support.m_bp;
+ m_rank_bp = bp_support.m_rank_bp;
+ m_rank_bp.set_vector(m_bp);
+ m_select_bp = bp_support.m_select_bp;
+ m_select_bp.set_vector(m_bp);
+
+ m_nnd = bp_support.m_nnd;
+
+ m_pioneer_bp = bp_support.m_pioneer_bp;
+ m_rank_pioneer_bp = bp_support.m_rank_pioneer_bp;
+ m_rank_pioneer_bp.set_vector(&m_pioneer_bp);
+ m_nnd2 = bp_support.m_nnd2;
+ m_match = bp_support.m_match;
+ m_enclose = bp_support.m_enclose;
+ m_range_max_match = bp_support.m_range_max_match;
+ m_range_max_match.set_vector(&m_match);
+
+ m_size = bp_support.m_size;
+ m_blocks = bp_support.m_blocks;
+ }
+
+ /*! Calculates the excess value at index i in the pioneer bitmap.
+ * \param i The index of which the excess value should be calculated.
+ */
+ inline size_type excess_pioneer(size_type i)const {
+ return (m_rank_pioneer_bp(i+1)<<1)-i-1;
+ }
+
+ public:
+ const rank_type& bp_rank = m_rank_bp;
+ const select_type& bp_select = m_select_bp;
+
+ //! Constructor
+ explicit
+ bp_support_g(const bit_vector* bp = nullptr) : m_bp(bp),
+ m_size(bp==nullptr?0:bp->size()), m_blocks((m_size+t_bs-1)/t_bs) {
+ if (bp == nullptr)
+ return;
+ util::init_support(m_rank_bp, bp);
+ util::init_support(m_select_bp, bp);
+ bit_vector pioneer = calculate_pioneers_bitmap(*m_bp, t_bs);
+ m_nnd = nnd_type(pioneer);
+ m_pioneer_bp.resize(m_nnd.ones());
+ for (size_type i=1; i<= m_nnd.ones(); ++i)
+ m_pioneer_bp[i-1] = (*m_bp)[m_nnd.select(i)];
+ util::init_support(m_rank_pioneer_bp, &m_pioneer_bp);
+ pioneer = calculate_pioneers_bitmap(m_pioneer_bp, t_bs);
+ m_nnd2 = nnd_type(pioneer);
+
+ bit_vector pioneer_bp2 = bit_vector(m_nnd2.ones());
+ for (size_type i=1; i<= m_nnd2.ones(); ++i)
+ pioneer_bp2[i-1] = m_pioneer_bp[m_nnd2.select(i)];
+ calculate_matches(pioneer_bp2, m_match);
+ calculate_enclose(pioneer_bp2, m_enclose);
+ m_range_max_match = rmq_type(&m_match);
+ }
+
+ //! Copy constructor
+ bp_support_g(const bp_support_g& bp_support) {
+ copy(bp_support);
+ }
+
+ //! Move constructor
+ bp_support_g(bp_support_g&& bp_support) {
+ *this = std::move(bp_support);
+ }
+
+ //! Assignment operator
+ bp_support_g& operator=(const bp_support_g& bp_support) {
+ if (this != &bp_support) {
+ copy(bp_support);
+ }
+ return *this;
+ }
+
+ //! Assignment operator
+ bp_support_g& operator=(bp_support_g&& bp_support) {
+ if (this != &bp_support) {
+ m_bp = std::move(bp_support.m_bp);
+ m_rank_bp = std::move(bp_support.m_rank_bp);
+ m_rank_bp.set_vector(m_bp);
+ m_select_bp = std::move(bp_support.m_select_bp);
+ m_select_bp.set_vector(m_bp);
+
+ m_nnd = std::move(bp_support.m_nnd);
+
+ m_pioneer_bp = std::move(bp_support.m_pioneer_bp);
+ m_rank_pioneer_bp = std::move(bp_support.m_rank_pioneer_bp);
+ m_rank_pioneer_bp.set_vector(&m_pioneer_bp);
+ m_nnd2 = std::move(bp_support.m_nnd2);
+ m_match = std::move(bp_support.m_match);
+ m_enclose = std::move(bp_support.m_enclose);
+ m_range_max_match = std::move(bp_support.m_range_max_match);
+ m_range_max_match.set_vector(&m_match);
+
+ m_size = std::move(bp_support.m_size);
+ m_blocks = std::move(bp_support.m_blocks);
+ }
+ return *this;
+ }
+
+ void swap(bp_support_g& bp_support) {
+ m_rank_bp.swap(bp_support.m_rank_bp);
+ m_select_bp.swap(bp_support.m_select_bp);
+
+ m_nnd.swap(bp_support.m_nnd);
+
+ m_pioneer_bp.swap(bp_support.m_pioneer_bp);
+ util::swap_support(m_rank_pioneer_bp, bp_support.m_rank_pioneer_bp,
+ &m_pioneer_bp, &(bp_support.m_pioneer_bp));
+
+ m_nnd2.swap(bp_support.m_nnd2);
+
+ m_match.swap(bp_support.m_match);
+ m_enclose.swap(bp_support.m_enclose);
+ util::swap_support(m_range_max_match, bp_support.m_range_max_match,
+ &m_match, &(bp_support.m_match));
+
+ std::swap(m_size, bp_support.m_size);
+ std::swap(m_blocks, bp_support.m_blocks);
+ }
+
+ void set_vector(const bit_vector* bp) {
+ m_bp = bp;
+ m_rank_bp.set_vector(bp);
+ m_select_bp.set_vector(bp);
+ }
+
+ /*! Calculates the excess value at index i.
+ * \param i The index of which the excess value should be calculated.
+ */
+ inline size_type excess(size_type i)const {
+ return (m_rank_bp(i+1)<<1)-i-1;
+ }
+
+ /*! Returns the number of opening parentheses up to and including index i.
+ * \pre{ \f$ 0\leq i < size() \f$ }
+ */
+ size_type rank(size_type i)const {
+ return m_rank_bp(i+1);
+ }
+
+ /*! Returns the index of the i-th opening parenthesis.
+ * \param i Number of the parenthesis to select.
+ * \pre{ \f$1\leq i < rank(size())\f$ }
+ * \post{ \f$ 0\leq select(i) < size() \f$ }
+ */
+ size_type select(size_type i)const {
+ return m_select_bp(i);
+ }
+
+ /*! Calculate the index of the matching closing parenthesis to the parenthesis at index i.
+ * \param i Index of an parenthesis. 0 <= i < size().
+ * \return * i, if the parenthesis at index i is closing,
+ * * the position j of the matching closing parenthesis, if a matching parenthesis exists,
+ * * size() if no matching closing parenthesis exists.
+ */
+ size_type find_close(size_type i)const {
+ assert(i < m_size);
+ if (!(*m_bp)[i]) {// if there is a closing parenthesis at index i return i
+ return i;
+ }
+ size_type mi = 0; // match for i
+ if ((mi=near_find_close(*m_bp, i, t_bs))==i) {
+ const size_type i2 = m_nnd.rank(i+1)-1; // lemma that this gives us an opening pioneer
+ assert(m_pioneer_bp[i2]==1); // assert that i2 is an opening parenthesis
+ size_type mi2 = 0; // match for i2
+ if ((mi2=near_find_close(m_pioneer_bp, i2, t_bs)) == i2) {
+ const size_type i3 = m_nnd2.rank(i2+1)-1;
+ const size_type mi3 = m_match[i3]; assert(mi3>i3); // assert that i3 is an opening parenthesis
+ mi2 = m_nnd2.select(mi3+1); // matching pioneer position in pioneer_bp
+ mi2 = (mi2/t_bs)*t_bs;
+ size_type epb = excess_pioneer(mi2);// excess of first parenthesis in the pioneer block
+ const size_type ei = excess_pioneer(i2);// excess of pioneer
+ /* invariant: epb >= ei-1 */ assert(epb+1 >= ei);
+ while (epb+1 != ei) {
+ assert(mi2 < m_pioneer_bp.size());
+ if (m_pioneer_bp[++mi2])
+ ++epb;
+ else
+ --epb;
+ }
+ }
+ mi = m_nnd.select(mi2+1); /* matching pioneer position in bp */ assert((*m_bp)[mi]==0);
+ mi = (mi/t_bs)*t_bs;
+ size_type epb = excess(mi); // excess of first parenthesis in the pioneer block
+ const size_type ei = excess(i); // excess at position i
+ /* invariant: epb >= ei-1 */ assert(epb+1 >= ei);
+ while (epb+1 != ei) {
+ assert(mi < m_size);
+ if ((*m_bp)[++mi])
+ ++epb;
+ else
+ --epb;
+ }
+ }
+ return mi;
+ }
+
+ //! Calculate the matching opening parenthesis to the closing parenthesis at position i
+ /*! \param i Index of a closing parenthesis.
+ * \return * i, if the parenthesis at index i is closing,
+ * * the position j of the matching opening parenthesis, if a matching parenthesis exists,
+ * * size() if no matching closing parenthesis exists.
+ */
+ size_type find_open(size_type i)const {
+ assert(i < m_size);
+ if ((*m_bp)[i]) {// if there is a opening parenthesis at index i return i
+ return i;
+ }
+ size_type mi = 0; // match for i
+ if ((mi=near_find_open(*m_bp, i, t_bs)) == i) {
+ const size_type i2 = m_nnd.rank(i); // lemma that this gives us an closing pioneer
+ assert(m_pioneer_bp[i2]==0); // assert that i2 is an opening parenthesis
+ const size_type mi2 = find_open_in_pioneers(i2); assert(m_pioneer_bp[mi2]==1);
+ mi = m_nnd.select(mi2+1); /* matching pioneer position in bp */ assert((*m_bp)[mi]==1);
+ mi = (mi/t_bs)*t_bs + t_bs - 1; assert(mi < i);
+ size_type epb = excess(mi); // excess of last parenthesis in the pioneer block
+ const size_type ei = excess(i); // excess at position i
+ /*invariant: epb >= ei+1*/ assert(epb >= ei+1);
+ while (epb != ei) {
+ assert(mi < m_size);
+ if ((*m_bp)[mi--])
+ --epb;
+ else
+ ++epb;
+ }
+ ++mi;
+ }
+ return mi;
+ }
+
+ inline size_type find_open_in_pioneers(size_type i)const {
+ size_type mi = 0; // match for i
+ if ((mi=near_find_open(m_pioneer_bp, i, t_bs))==i) {
+ const size_type i3 = m_nnd2.rank(i);
+ const size_type mi3 = m_match[i3]; assert(mi3<i3); // assert that i3 is an closing parenthesis
+ mi = m_nnd2.select(mi3+1); // matching pioneer position in pioneer_bp
+ mi = (mi/t_bs)*t_bs + t_bs - 1;
+ size_type epb2 = excess_pioneer(mi);// excess of last parenthesis in the pioneer block
+ const size_type ei = excess_pioneer(i);// excess of pioneer
+ /* invariant: epb2 >= ei+1 */ assert(epb2 >= ei+1);
+ while (epb2 != ei) {
+ assert(mi < m_pioneer_bp.size());
+ if (m_pioneer_bp[mi--])
+ --epb2;
+ else
+ ++epb2;
+ }
+ ++mi;
+ }
+ return mi;
+ }
+
+ //! Calculate the index of the opening parenthesis corresponding to the closest matching parenthesis pair enclosing i.
+ /*! \param i Index of an opening parenthesis.
+ * \return The index of the opening parenthesis corresponding to the closest matching parenthesis pair enclosing i,
+ * or size() if no such pair exists.
+ */
+ size_type enclose(size_type i)const {
+ assert(i < m_size);
+ if (!(*m_bp)[i]) { // if there is closing parenthesis at position i
+ return find_open(i);
+ }
+ const size_type exi = excess(i);
+ if (exi == 1) // if i is not enclosed by a parentheses pair..
+ return size();
+ size_type ei; // enclose for i
+ if ((ei=near_enclose(*m_bp, i, t_bs))==i) {
+ const size_type i2 = m_nnd.rank(i); // next parenthesis in the pioneer bitmap
+ size_type ei2; // enclose for i2
+ if (m_pioneer_bp[i2]) { // search enclose in the pioneer bp
+ if ((ei2=near_enclose(m_pioneer_bp, i2, t_bs))==i2) {
+ const size_type i3 = m_nnd2.rank(i2); // next parenthesis in the pioneer2 bitmap
+ const size_type ei3 = m_enclose[i3]; assert(ei3<i3); // assert that enclose answer is valid
+ ei2 = m_nnd2.select(ei3+1); assert(m_pioneer_bp[ei2] == 1);
+ ei2 = (ei2/t_bs)*t_bs + t_bs - 1; assert(ei2 < i2);
+ size_type epb2 = excess_pioneer(ei2);// excess of the last parenthesis in the pioneer block
+ const size_type exi2 = excess_pioneer(i2);// excess
+ /* invariant epb2+1 >= exi2 */ assert(epb2+1 >= exi2);
+ while (epb2+2 != exi2) {
+ if (m_pioneer_bp[ei2--])
+ --epb2;
+ else
+ ++epb2;
+ }
+ ++ei2;
+ }
+ } else {
+ // if the next parenthesis in the pioneer bitmap is an closing parenthesis findopen on m_pioneer_bp
+ ei2 = find_open_in_pioneers(i2);
+ }
+ assert(m_pioneer_bp[ei2]==1);
+ ei = m_nnd.select(ei2+1); assert((*m_bp)[ei]==1);
+ ei = (ei/t_bs)*t_bs + t_bs - 1; assert(ei < i);
+ size_type epb = excess(ei); // excess of the last parenthesis in the pioneer block
+ /* invariant epb+1 >= exi */ assert(epb+1 >= exi);
+ while (epb+2 != exi) {
+ if ((*m_bp)[ei--])
+ --epb;
+ else
+ ++epb;
+ }
+ ++ei;
+ }
+ return ei;
+ }
+
+ //! The range restricted enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis/ \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The smallest index, say k, of an opening parenthesis such that findclose(i) < k < j and
+ * findclose(j) < findclose(k). If such a k does not exists, restricted_enclose(i,j) returns size().
+ * \par Time complexity
+ * \f$ \Order{block\_size} \f$
+ */
+ size_type rr_enclose(const size_type i, const size_type j)const {
+ assert(j > i and j < m_size);
+ const size_type mip1 = find_close(i)+1;
+ if (mip1 >= j)
+ return size();
+ return rmq_open(mip1, j);
+ }
+
+ /*! Search the interval [l,r-1] for an opening parenthesis, say i, such that find_close(i) >= r.
+ * \param l The left end (inclusive) of the interval to search for the result.
+ * \param r The right end (exclusive) of the interval to search for the result.
+ * \return the minimal opening parenthesis i with \f$ \ell \leq i < r \f$ and \f$ find_close(i) \geq r \f$;
+ * if no such i exists size() is returned.
+ * The algorithm consists of 4 steps:
+ * 1. scan back from position r to the begin of that block
+ * 2. recursively scan back the pioneers of the blocks which lie in between the blocks of l and r
+ * 3. scan from position l to the end of the block, which contains l
+ * 4. check if there exists a valid solution and return
+ * \par Time complexity
+ * \f$ \Order{block\_size} \f$
+ */
+ size_type rmq_open(const size_type l, const size_type r)const {
+ if (l >= r)
+ return size();
+ size_type min_ex_pos = r;
+
+ if (l/t_bs == r/t_bs) {
+ min_ex_pos = near_rmq_open(*m_bp, l, r);
+ } else { // parentheses pair does not start in the same block
+// assert( l>1 ); // mi is at greater or equal than 1
+ // note: mi and r are not in the same block
+ size_type k, ex; // helper variables
+ size_type min_ex = excess(r);// + 2*((*m_bp[r])==0); // minimal excess
+ const size_type bl = (l/t_bs+1)*t_bs; // leftmost position of the leftmost block between the blocks of l and r
+ const size_type br = (r/t_bs)*t_bs; // leftmost position of the block of r
+
+
+ // 1.2
+ size_type l_ = m_nnd.rank(l); // l_ inclusive
+ size_type r_ = m_nnd.rank(r); // r_ exclusive
+
+ if (r_ > l_) {
+ size_type min_ex_pos_ = r_;
+ if (l_/t_bs == r_/t_bs) {
+ min_ex_pos_ = near_rmq_open(m_pioneer_bp, l_, r_);
+ } else if (r_ < m_pioneer_bp.size()) {
+ size_type min_ex_ = excess_pioneer(r_)+2*(m_pioneer_bp[r_]==0);
+ const size_type bl_ = (l_/t_bs+1)*t_bs;
+ const size_type br_ = (r_/t_bs)*t_bs;
+
+ // 2.2
+ size_type l__ = m_nnd2.rank(l_); // l__ inclusive
+ size_type r__ = m_nnd2.rank(r_); // r__ exclusive
+ if (r__ > l__) {
+ size_type max_match = 0;
+ k = m_range_max_match(l__, r__-1);
+ max_match = m_match[k];
+ if (max_match >= r__) {
+ k = m_nnd2.select(k+1);
+ if (k < r_ and(ex=excess_pioneer(k)) < min_ex_) {
+ min_ex_ = ex; min_ex_pos_ = k;
+ }
+ }
+ }
+ if (min_ex_pos_ == r_) {
+ // 2.1
+ k = near_rmq_open(m_pioneer_bp, br_, r_);
+ if (k < r_ and(ex=excess_pioneer(k)) < min_ex_) {
+ min_ex_ = ex; min_ex_pos_ = k;
+ }
+ }
+ // 2.3
+ k = near_rmq_open(m_pioneer_bp, l_, bl_);
+ if (k < bl_ and(ex=excess_pioneer(k)) < min_ex_) {
+ min_ex_ = ex; min_ex_pos_ = k;
+ }
+ }
+ // 2.4
+ if (min_ex_pos_ < r_) {
+ k = m_nnd.select(min_ex_pos_ + 1);
+ if ((ex=excess(k)) < min_ex) {
+ min_ex = ex; min_ex_pos = k;
+ }
+ }
+ }
+ if (min_ex_pos == r) {
+ // 1.1
+ k = near_rmq_open(*m_bp, br, r);
+ if (k < r and(ex=excess(k)) < min_ex) {
+ min_ex = ex; min_ex_pos = k;
+ }
+ }
+ // 1.3
+ k = near_rmq_open(*m_bp, l, bl);
+ if (k < bl and(ex=excess(k)) < min_ex) {
+ min_ex = ex; min_ex_pos = k;
+ }
+ }
+ // 1.4
+ if (min_ex_pos < r)
+ return min_ex_pos;
+ else
+ return size();
+ }
+
+ //! The range restricted enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis/ \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The smallest index, say k, of an opening parenthesis such that findclose(i) < k < j and
+ * findclose(j) < findclose(k). If such a k does not exists, restricted_enclose(i,j) returns size().
+ */
+ size_type rr_enclose_naive(size_type i, size_type j)const {
+ assert(j > i and j < m_size);
+ size_type mi = find_close(i); // matching parenthesis to i
+ assert(mi > i and mi < j);
+ assert(find_close(j) > j);
+ size_type k = enclose(j);
+ if (k == m_size or k < i) // there exists no opening parenthesis at position mi<k<j.
+ return m_size;
+ size_type kk;
+ do {
+ kk = k;
+ k = enclose(k);
+ } while (k != m_size and k > mi);
+ return kk;
+ }
+
+ //! The range minimum query (rmq) returns the index of the parenthesis with minimal excess in the range \f$[l..r]\f$
+ /*! \param l The left border of the interval \f$[l..r]\f$ (\f$l\leq r\f$).
+ * \param r The right border of the interval \f$[l..r]\f$ (\f$l \leq r\f$).
+ */
+ size_type rmq(size_type l, size_type r)const {
+ assert(l<=r);
+ size_type m = rmq_open(l, r+1);
+ if (m==l)
+ return l;
+ else { // m>l and m<=r
+ assert(0 == (*m_bp)[m-1]);
+ size_type prev_open = m_rank_bp(m);
+ if (prev_open == 0 or m_select_bp(prev_open) < l) { // if there exists no opening parenthesis to the left of m which is greater or equal than l
+ return l;
+ } else {
+ return m-1;
+ }
+ }
+ }
+
+ //! The double enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The maximal opening parenthesis, say k, such that \f$ k<j \wedge k>findclose(j) \f$.
+ * If such a k does not exists, double_enclose(i,j) returns size().
+ */
+ size_type double_enclose(size_type i, size_type j)const {
+ assert(j > i);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ size_type k = rr_enclose(i, j);
+ if (k == size())
+ return enclose(j);
+ else
+ return enclose(k);
+ }
+
+ //! Return the number of zeros which procede position i in the balanced parentheses sequence.
+ /*! \param i Index of an parenthesis.
+ */
+ size_type preceding_closing_parentheses(size_type i)const {
+ assert(i < m_size);
+ if (!i) return 0;
+ size_type ones = m_rank_bp(i);
+ if (ones) { // ones > 0
+ assert(m_select_bp(ones) < i);
+ return i - m_select_bp(ones) - 1;
+ } else {
+ return i;
+ }
+ }
+
+ /*! The size of the supported balanced parentheses sequence.
+ * \return the size of the supported balanced parentheses sequence.
+ */
+ size_type size() const {
+ return m_size;
+ }
+
+ //! Serializes the bp_support_g to a stream.
+ /*!
+ * \param out The outstream to which the data structure is written.
+ * \return The number of bytes written to out.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_rank_bp.serialize(out, child, "bp_rank");
+ written_bytes += m_select_bp.serialize(out, child, "bp_select");
+ written_bytes += m_nnd.serialize(out, child,"nearest_neighbor_dictionary");
+
+ written_bytes += m_pioneer_bp.serialize(out, child, "pioneer_bp");
+ written_bytes += m_rank_pioneer_bp.serialize(out, child, "pioneer_bp_rank");
+ written_bytes += m_nnd2.serialize(out, child, "nearest_neighbor_dictionary2");
+ written_bytes += m_match.serialize(out, child, "match_answers");
+ written_bytes += m_enclose.serialize(out, child, "enclose_answers");
+ written_bytes += m_range_max_match.serialize(out, child, "rmq_answers");
+
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_blocks, out, child, "block_cnt");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load the bp_support_g for a bit_vector v.
+ /*!
+ * \param in The instream from which the data strucutre is read.
+ * \param bp Bit vector representing a balanced parentheses sequence that is supported by this data structure.
+ */
+ void load(std::istream& in, const bit_vector* bp) {
+ m_bp = bp;
+ m_rank_bp.load(in, m_bp);
+ m_select_bp.load(in, m_bp);
+ m_nnd.load(in);
+
+ m_pioneer_bp.load(in);
+ m_rank_pioneer_bp.load(in, &m_pioneer_bp);
+ m_nnd2.load(in);
+ m_match.load(in);
+ m_enclose.load(in);
+ m_range_max_match.load(in, &m_match);
+ read_member(m_size, in);
+ assert(m_size == bp->size());
+ read_member(m_blocks, in);
+ }
+};
+
+}// end namespace
+
+
+
+
+#endif
diff --git a/include/sdsl/bp_support_gg.hpp b/include/sdsl/bp_support_gg.hpp
new file mode 100644
index 0000000..f4dec82
--- /dev/null
+++ b/include/sdsl/bp_support_gg.hpp
@@ -0,0 +1,545 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file bp_support_gg.hpp
+ \brief bp_support_gg.hpp contains an implementation of a BP support data structure.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_BP_SUPPORT_GG
+#define INCLUDED_SDSL_BP_SUPPORT_GG
+
+#include "int_vector.hpp"
+#include "nearest_neighbour_dictionary.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "bp_support_algorithm.hpp"
+#include "util.hpp"
+#include <stack>
+#include <map>
+#include <set>
+#include <utility>
+#include <stdexcept>
+
+namespace sdsl
+{
+
+//! A class that provides support for bit_vectors that represent a BP sequence.
+/*! This data structure supports the following operations:
+ * - find_open
+ * - find_close
+ * - enclose
+ * - double_enclose
+ * - rank
+ * - select
+ * - excess
+ * - rr_enclose
+ * An opening parenthesis in the balanced parentheses sequence is represented by a 1 in the bit_vector
+ * and a closing parenthesis by a 0.
+ *
+ * \tparam t_nnd A class which supports rank and select with little space on sparse populated bit_vectors.
+ * \tparam t_rank A rank support structure.
+ * \tparam t_select A select support structure.
+ *
+ * \par References
+ * - Richard F. Geary, Naila Rahman, Rajeev Raman, Venkatesh Raman:
+ * A Simple Optimal Representation for Balanced Parentheses.
+ * CPM 2004: 159-172
+ * - Enno Ohlebusch, Simon Gog:
+ * A Compressed Enhanced Suffix Array Supporting Fast String Matching.
+ * SPIRE 2009: 51-62
+ * @ingroup bps
+ */
+// TODO: can rrr_vector replace nearest_neighbour_dictionary?
+template<class t_nnd = nearest_neighbour_dictionary<30>,
+ class t_rank = rank_support_v5<>,
+ class t_select = select_support_mcl<>,
+ uint32_t t_bs=840>
+class bp_support_gg
+{
+ static_assert(t_bs > 2, "bp_support_gg: block size must be greater than 2.");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef t_nnd nnd_type;
+ typedef t_rank rank_type;
+ typedef t_select select_type;
+ typedef bp_support_gg<nnd_type, rank_type, select_support_scan<>, t_bs> bp_support_type;
+ private:
+ const bit_vector* m_bp; // balanced parentheses sequence
+ rank_type m_rank_bp; // rank support for m_bp => see excess() and rank()
+ select_type m_select_bp; // select support for m_bp => see select()
+
+ nnd_type m_nnd; // nearest neighbour dictionary for pioneers bit_vector
+
+ bit_vector m_pioneer_bp; // pioneer sequence
+ bp_support_type* m_pioneer_bp_support;
+
+ size_type m_size;
+ size_type m_blocks; // number of blocks
+
+ void copy(const bp_support_gg& bp_support) {
+ m_bp = bp_support.m_bp;
+ m_rank_bp = bp_support.m_rank_bp;
+ m_rank_bp.set_vector(m_bp);
+ m_select_bp = bp_support.m_select_bp;
+ m_select_bp.set_vector(m_bp);
+
+ m_nnd = bp_support.m_nnd;
+
+ m_size = bp_support.m_size;
+ m_blocks = bp_support.m_blocks;
+
+
+ m_pioneer_bp = bp_support.m_pioneer_bp;
+ if (bp_support.m_pioneer_bp_support == nullptr) {
+ if (m_pioneer_bp_support != nullptr)
+ delete m_pioneer_bp_support;
+ m_pioneer_bp_support = nullptr;
+ } else {
+ if (m_pioneer_bp_support != nullptr)
+ delete m_pioneer_bp_support;
+ m_pioneer_bp_support = new bp_support_type(*(bp_support.m_pioneer_bp_support));
+ assert(m_pioneer_bp_support != nullptr);
+ m_pioneer_bp_support->set_vector(&m_pioneer_bp);
+ }
+ }
+
+ public:
+
+ const rank_type& bp_rank;
+ const select_type& bp_select;
+
+ bp_support_gg(): m_bp(nullptr), m_pioneer_bp_support(nullptr),
+ m_size(0), m_blocks(0),bp_rank(m_rank_bp),
+ bp_select(m_select_bp) {}
+
+ //! Constructor
+ explicit bp_support_gg(const bit_vector* bp):m_bp(bp),
+ m_pioneer_bp_support(nullptr),
+ m_size(bp==nullptr?0:bp->size()),
+ m_blocks((m_size+t_bs-1)/t_bs),
+ bp_rank(m_rank_bp),bp_select(m_select_bp) {
+ if (bp == nullptr) { // -> m_bp == nullptr
+ return;
+ }
+ util::init_support(m_rank_bp, bp);
+ util::init_support(m_select_bp, bp);
+ {
+ bit_vector pioneer;
+ pioneer = calculate_pioneers_bitmap_succinct(*m_bp, t_bs);
+ util::assign(m_nnd, nnd_type(pioneer));
+ }
+
+ m_pioneer_bp.resize(m_nnd.ones());
+ if (m_nnd.ones() > 0 and m_nnd.ones() == m_bp->size()) { // m_bp != nullptr see above
+ throw std::logic_error(util::demangle(typeid(this).name())+": recursion in the construction does not terminate!");
+ }
+
+ for (size_type i=1; i<= m_nnd.ones(); ++i) {
+ m_pioneer_bp[i-1] = (*m_bp)[m_nnd.select(i)];
+ }
+
+ if (m_bp->size() > 0) { // m_bp != nullptr see above
+ m_pioneer_bp_support = new bp_support_type(&m_pioneer_bp);
+ }
+ }
+
+ //! Copy constructor
+ bp_support_gg(const bp_support_gg& bp_support) : bp_support_gg() {
+ copy(bp_support);
+ }
+
+ //! Move constructor
+ bp_support_gg(bp_support_gg&& bp_support) : bp_support_gg() {
+ *this = std::move(bp_support);
+ }
+
+ //! Destructor
+ ~bp_support_gg() {
+ if (m_pioneer_bp_support != nullptr)
+ delete m_pioneer_bp_support;
+ }
+
+ //! Swap operator
+ void swap(bp_support_gg& bp_support) {
+ m_rank_bp.swap(bp_support.m_rank_bp);
+ m_select_bp.swap(bp_support.m_select_bp);
+ m_nnd.swap(bp_support.m_nnd);
+
+ std::swap(m_size, bp_support.m_size);
+ std::swap(m_blocks, bp_support.m_blocks);
+
+ m_pioneer_bp.swap(bp_support.m_pioneer_bp);
+
+ std::swap(m_pioneer_bp_support, bp_support.m_pioneer_bp_support);
+ if (m_pioneer_bp_support != nullptr) {
+ m_pioneer_bp_support->set_vector(&m_pioneer_bp);
+ }
+ if (bp_support.m_pioneer_bp_support != nullptr) {
+ bp_support.m_pioneer_bp_support->set_vector(&(bp_support.m_pioneer_bp));
+ }
+ }
+
+ //! Assignment operator
+ bp_support_gg& operator=(const bp_support_gg& bp_support) {
+ if (this != &bp_support) {
+ copy(bp_support);
+ }
+ return *this;
+ }
+
+ //! Assignment Move operator
+ bp_support_gg& operator=(bp_support_gg&& bp_support) {
+ if (this != &bp_support) {
+ m_bp = std::move(bp_support.m_bp);
+ bp_support.m_bp = nullptr;
+ m_rank_bp = std::move(bp_support.m_rank_bp);
+ m_rank_bp.set_vector(m_bp);
+ m_select_bp = std::move(bp_support.m_select_bp);
+ m_select_bp.set_vector(m_bp);
+
+ m_nnd = std::move(bp_support.m_nnd);
+
+ m_size = std::move(bp_support.m_size);
+ m_blocks = std::move(bp_support.m_blocks);
+
+ m_pioneer_bp = bp_support.m_pioneer_bp;
+ if (m_pioneer_bp_support != nullptr) {
+ delete m_pioneer_bp_support;
+ }
+ m_pioneer_bp_support = bp_support.m_pioneer_bp_support;
+ if (m_pioneer_bp_support) m_pioneer_bp_support->set_vector(&m_pioneer_bp);
+ bp_support.m_pioneer_bp_support = nullptr;
+ }
+ return *this;
+ }
+
+ void set_vector(const bit_vector* bp) {
+ m_bp = bp;
+ m_rank_bp.set_vector(bp);
+ m_select_bp.set_vector(bp);
+ }
+
+ /*! Calculates the excess value at index i.
+ * \param i The index of which the excess value should be calculated.
+ */
+ inline size_type excess(size_type i)const {
+ return (m_rank_bp(i+1)<<1)-i-1;
+ }
+
+ /*! Returns the number of opening parentheses up to and including index i.
+ * \pre{ \f$ 0\leq i < size() \f$ }
+ */
+ size_type rank(size_type i)const {
+ return m_rank_bp(i+1);
+ }
+
+ /*! Returns the index of the i-th opening parenthesis.
+ * \param i Number of the parenthesis to select.
+ * \pre{ \f$1\leq i < rank(size())\f$ }
+ * \post{ \f$ 0\leq select(i) < size() \f$ }
+ */
+ size_type select(size_type i)const {
+ return m_select_bp(i);
+ }
+
+ /*! Calculate the index of the matching closing parenthesis to the parenthesis at index i.
+ * \param i Index of an parenthesis. 0 <= i < size().
+ * \return * i, if the parenthesis at index i is closing,
+ * * the position j of the matching closing parenthesis, if a matching parenthesis exists,
+ * * size() if no matching closing parenthesis exists.
+ */
+ size_type find_close(size_type i)const {
+ assert(i < m_size);
+ if (!(*m_bp)[i]) {// if there is a closing parenthesis at index i return i
+ return i;
+ }
+ size_type mi = 0; // match for i
+ if ((mi=near_find_closing(*m_bp, i+1, 1, t_bs))==i) {
+ const size_type i_ = m_nnd.rank(i+1)-1; // lemma that this gives us an opening pioneer
+ assert(m_pioneer_bp[i_]==1); // assert that i2 is an opening parenthesis
+ size_type mi_ = m_pioneer_bp_support->find_close(i_); assert(m_pioneer_bp[mi_]==0);
+ mi = m_nnd.select(mi_+1); /* matching pioneer position in bp */ assert((*m_bp)[mi]==0);
+ mi = (mi/t_bs)*t_bs;
+ size_type epb2 = excess(mi-1); // excess of first parenthesis in the pioneer block
+ const size_type ei = excess(i); // excess at position i
+ /* invariant: epb >= ei-1 */ //assert( epb+1 >= ei );
+ return near_find_closing(*m_bp, mi, epb2-ei+1, t_bs);
+
+ }
+ return mi;
+ }
+
+ //! Calculate the matching opening parenthesis
+ /*! \param i Index of a closing parenthesis.
+ * \return * i, if the parenthesis at index i is closing,
+ * * the position j of the matching opening parenthesis,
+ * if a matching parenthesis exists,
+ * * size() if no matching closing parenthesis exists.
+ */
+ size_type find_open(size_type i)const {
+ assert(i < m_size);
+ if ((*m_bp)[i]) { // if there is a opening parenthesis
+ return i; // return i
+ }
+ size_type mi = 0; // match for i
+ if ((mi=near_find_opening(*m_bp, i-1, 1, t_bs)) == i) {
+ const size_type i_ = m_nnd.rank(i); // lemma that this gives us an closing pioneer
+ assert(m_pioneer_bp[i_]==0); // assert that i' is an opening parenthesis
+ const size_type mi_ = m_pioneer_bp_support->find_open(i_); assert(m_pioneer_bp[mi_]==1);
+ mi = m_nnd.select(mi_+1); /* matching pioneer position in bp */ assert((*m_bp)[mi]==1);
+ mi = (mi/t_bs)*t_bs + t_bs - 1; assert(mi < i);
+ size_type epb2 = excess(mi+1); // excess of last parenthesis in the pioneer block
+ const size_type ei = excess(i); // excess at position i
+ /*invariant: epb >= ei+1*/ //assert( epb >= ei+1 );
+ return near_find_opening(*m_bp, mi, epb2-ei+1-2*((*m_bp)[mi+1]), t_bs);
+ }
+ return mi;
+ }
+
+ //! Calculate enclose.
+ /*! \param i Index of an opening parenthesis.
+ * \return The index of the opening parenthesis corresponding to
+ * the closest matching parenthesis pair enclosing i,
+ * or size() if no such pair exists.
+ */
+ size_type enclose(size_type i)const {
+ assert(i < m_size);
+ if (!(*m_bp)[i]) { // if there is closing parenthesis at position i
+ return find_open(i);
+ }
+ const size_type exi = excess(i);
+ if (exi == 1) // if i is not enclosed by a parentheses pair..
+ return size();
+ size_type ei; // enclose for i
+ if ((ei=near_find_opening(*m_bp, i-1, 1, t_bs)) == i) {
+ const size_type i_ = m_nnd.rank(i); // next parenthesis in the pioneer bitmap
+ size_type ei_; // enclose for i'
+ ei_ = m_pioneer_bp_support->enclose(i_);
+ assert(m_pioneer_bp[ei_]==1);
+ ei = m_nnd.select(ei_+1); assert((*m_bp)[ei]==1);
+ ei = (ei/t_bs)*t_bs + t_bs - 1; assert(ei < i);
+ size_type epb2 = excess(ei+1); // excess of last parenthesis in the pioneer block
+ /* invariant epb+1 >= exi */ //assert( epb+1 >= exi );
+ return near_find_opening(*m_bp, ei, epb2-exi+1+2*((*m_bp)[ei+1]==0), t_bs);
+ }
+ return ei;
+ }
+
+ //! Range restricted enclose operation
+ /*! Range restricted enclose operation for parentheses pairs
+ * \f$(i,\mu(i))\f$ and \f$(j,\mu(j))\f$.
+ * \param i First opening parenthesis.
+ * \param j Second opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The smallest index, say k, of an opening parenthesis such that
+ * find_close(i) < k < j and find_close(j) < find_close(k). If such a k does
+ * not exists, restricted_enclose(i,j) returns size().
+ * \par Time complexity
+ * \f$ \Order{block\_size} \f$
+ */
+ size_type rr_enclose(const size_type i, const size_type j)const {
+ assert(j < m_size);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ const size_type mip1 = find_close(i)+1;
+ if (mip1 >= j)
+ return size();
+ return rmq_open(mip1, j);
+ }
+
+ /*! Search the interval [l,r-1] for an opening parenthesis, say i, such that find_close(i) >= r.
+ * \param l The left end (inclusive) of the interval to search for the result.
+ * \param r The right end (exclusive) of the interval to search for the result.
+ * \return the minimal opening parenthesis i with \f$ \ell \leq i < r \f$ and \f$ find_close(i) \geq r \f$;
+ * if no such i exists size() is returned.
+ * \par Time complexity
+ * \f$ \Order{block\_size} \f$
+ */
+ size_type rmq_open(const size_type l, const size_type r)const {
+ if (l >= r)
+ return size();
+ size_type min_ex_pos = r;
+
+ if (l/t_bs == r/t_bs) {
+ min_ex_pos = near_rmq_open(*m_bp, l, r);
+ } else { // parentheses pair does not start in the same block
+ // note: l and r are not in the same block
+ size_type k, ex; // helper variables
+ size_type min_ex = excess(r) + 2*((*m_bp)[r]==0);// minimal excess
+
+
+ // 1.2
+ size_type l_ = m_nnd.rank(l); // l_ inclusive
+ size_type r_ = m_nnd.rank(r); // r_ exclusive
+
+ size_type min_ex_pos_ = m_pioneer_bp_support->rmq_open(l_, r_);
+ if (min_ex_pos_ < r_) {
+ k = m_nnd.select(min_ex_pos_ + 1);
+ min_ex = excess(k); min_ex_pos = k;
+ } else {
+ // 1.1
+ k = near_rmq_open(*m_bp, (r/t_bs)*t_bs, r);
+ if (k < r) {
+ assert(excess(k) < min_ex);
+ min_ex = excess(k); min_ex_pos = k;
+ }
+ }
+ // 1.3
+ k = near_rmq_open(*m_bp, l, (l/t_bs+1)*t_bs);
+ if (k < (l/t_bs+1)*t_bs and(ex=excess(k)) < min_ex) {
+ min_ex = ex; min_ex_pos = k;
+ }
+ }
+ // 1.4
+ if (min_ex_pos < r)
+ return min_ex_pos;
+ else
+ return size();
+ }
+
+ //! The range restricted enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The minimal opening parenthesis, say k, such that \f$ findclose(i) < k < j\f$ and
+ * findclose(j) < findclose(k). If such a k does not exists, restricted_enclose(i,j) returns size().
+ * \par Time complexity
+ * \f$ \Order{size()}\f$ in the worst case.
+ */
+ size_type rr_enclose_naive(size_type i, size_type j)const {
+ assert(j > i and j < m_size);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ size_type mi = find_close(i); // matching parenthesis to i
+ assert(mi > i and mi < j);
+ assert(find_close(j) > j);
+ size_type k = enclose(j);
+ if (k == m_size or k < i) // there exists no opening parenthesis at position mi<k<j.
+ return m_size;
+ size_type kk;
+ do {
+ kk = k;
+ k = enclose(k);
+ } while (k != m_size and k > mi);
+ return kk;
+ }
+
+ //! The range minimum query (rmq) returns the index of the parenthesis with minimal excess in the range \f$[l..r]\f$
+ /*! \param l The left border of the interval \f$[l..r]\f$ (\f$l\leq r\f$).
+ * \param r The right border of the interval \f$[l..r]\f$ (\f$l \leq r\f$).
+ // TODO: Method does not return the rightmost rmq.
+ */
+ size_type rmq(size_type l, size_type r)const {
+ assert(l<=r);
+ size_type m = rmq_open(l, r+1);
+ if (m==size())
+ return r;
+ else if (m==l)
+ return l;
+ else { // m>l and m<=r
+ assert(0 == (*m_bp)[m-1]);
+ return m-1;
+ }
+ }
+
+ //! The double enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The maximal opening parenthesis, say k, such that \f$ k<j \wedge k>findclose(j) \f$.
+ * If such a k does not exists, double_enclose(i,j) returns size().
+ */
+ size_type double_enclose(size_type i, size_type j)const {
+ assert(j > i);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ size_type k = rr_enclose(i, j);
+ if (k == size())
+ return enclose(j);
+ else
+ return enclose(k);
+ }
+
+ //! Return the number of zeros which procede position i in the balanced parentheses sequence.
+ /*! \param i Index of an parenthesis.
+ */
+ size_type preceding_closing_parentheses(size_type i)const {
+ assert(i < m_size);
+ if (!i) return 0;
+ size_type ones = m_rank_bp(i);
+ if (ones) { // ones > 0
+ assert(m_select_bp(ones) < i);
+ return i - m_select_bp(ones) - 1;
+ } else {
+ return i;
+ }
+ }
+
+ /*! The size of the supported balanced parentheses sequence.
+ * \return the size of the supported balanced parentheses sequence.
+ */
+ size_type size() const {
+ return m_size;
+ }
+
+ //! Serializes the bp_support_gg to a stream.
+ /*!
+ * \param out The outstream to which the data structure is written.
+ * \return The number of bytes written to out.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_blocks, out, child, "block_cnt");
+
+ written_bytes += m_rank_bp.serialize(out, child, "bp_rank");
+ written_bytes += m_select_bp.serialize(out, child, "bp_select");
+ written_bytes += m_nnd.serialize(out, child, "nearest_neighbour_dictionary");
+
+ written_bytes += m_pioneer_bp.serialize(out, child, "pioneer_bp");
+ if (m_bp != nullptr and m_bp->size() > 0)
+ written_bytes += m_pioneer_bp_support->serialize(out, child, "pioneer_bp_support");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load the bp_support_gg for a bit_vector v.
+ /*!
+ * \param in The instream from which the data structure is read.
+ * \param bp Bit vector representing the supported BP sequence.
+ */
+ void load(std::istream& in, const bit_vector* bp) {
+ m_bp = bp;
+ read_member(m_size, in);
+ read_member(m_blocks, in);
+
+ m_rank_bp.load(in, m_bp);
+ m_select_bp.load(in, m_bp);
+ m_nnd.load(in);
+
+ m_pioneer_bp.load(in);
+ if (m_pioneer_bp_support != nullptr) {
+ delete m_pioneer_bp_support;
+ m_pioneer_bp_support = nullptr;
+ }
+ if (m_bp != nullptr and m_bp->size() > 0) {
+ m_pioneer_bp_support = new bp_support_type();
+ m_pioneer_bp_support->load(in, &m_pioneer_bp);
+ }
+ }
+};
+
+}// end namespace
+
+
+
+
+#endif
diff --git a/include/sdsl/bp_support_sada.hpp b/include/sdsl/bp_support_sada.hpp
new file mode 100644
index 0000000..997d94d
--- /dev/null
+++ b/include/sdsl/bp_support_sada.hpp
@@ -0,0 +1,894 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file bp_support_sada.hpp
+ \brief bp_support_sada.hpp contains an implementation of a balanced
+ parentheses support structure proposed by Kunihiko Sadakane.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_BP_SUPPORT_SADA
+#define INCLUDED_SDSL_BP_SUPPORT_SADA
+
+#include "int_vector.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "bp_support_algorithm.hpp"
+#include "fast_cache.hpp"
+#include <stack>
+#include <map>
+#include <set>
+#include <utility>
+#include <stdexcept>
+#ifndef NDEBUG
+#include <algorithm>
+#endif
+#include <iostream>
+
+namespace sdsl
+{
+
+//! A class that provides support for bit_vectors that represent a BP sequence.
+/*! This data structure supports the following operations:
+ * - find_open
+ * - find_close
+ * - enclose
+ * - double_enclose
+ * - rank
+ * - select
+ * - excess
+ * - rr_enclose
+ * An opening parenthesis in the balanced parentheses sequence is represented by a 1 in the bit_vector
+ * and a closing parenthesis by a 0.
+ *
+ * \tparam t_sml_blk The size of the small blocks. Denoted as `s` in Sadakane's paper.
+ * \tparam t_med_deg Number of small blocks that a medium block contains. Denoted as `l` in Sadakane's paper.
+ * \tparam t_rank Type of rank support used for the underlying bitvector.
+ * \tparam t_select Type of select support used for the underlying bitvector.
+ *
+ * \par References
+ * - Kunihiko Sadakane:
+ * The Ultimate Balanced Parentheses
+ * Technical Report 2008.
+ * - Kunihiko Sadakane, Gonzalo Navarro:
+ * Fully-Functional Succinct Trees.
+ * SODA 2010: 134-149
+ *
+ * @ingroup bps
+ */
+template<uint32_t t_sml_blk = 256,
+ uint32_t t_med_deg = 32,
+ class t_rank = rank_support_v5<>,
+ class t_select = select_support_mcl<> >
+class bp_support_sada
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef bit_vector::difference_type difference_type;
+ typedef int_vector<> sml_block_array_type;
+ typedef int_vector<> med_block_array_type;
+ typedef t_rank rank_type;
+ typedef t_select select_type;
+ private:
+ static_assert(0 < t_sml_blk, "bp_support_sada: t_sml_blk should be greater than 0!");
+ const bit_vector* m_bp = nullptr; // the supported balanced parentheses sequence as bit_vector
+ rank_type m_bp_rank; // RS for the BP sequence => see excess() and rank()
+ select_type m_bp_select; // SS for the BP sequence => see select()
+
+ sml_block_array_type m_sml_block_min_max;
+ med_block_array_type m_med_block_min_max;
+
+ size_type m_size = 0; // number of supported parentheses
+ size_type m_sml_blocks = 0; // number of small sized blocks
+ size_type m_med_blocks = 0; // number of medium sized blocks
+ size_type m_med_inner_blocks = 0; // number of inner nodes in the min max tree of the medium sized blocks
+//#define USE_CACHE
+#ifdef USE_CACHE
+ mutable fast_cache find_close_cache;
+ mutable fast_cache find_open_cache;
+ mutable fast_cache select_cache;
+#endif
+
+ void copy(const bp_support_sada& bp_support) {
+ m_bp = bp_support.m_bp;
+ m_bp_rank = bp_support.m_bp_rank;
+ m_bp_rank.set_vector(m_bp);
+ m_bp_select = bp_support.m_bp_select;
+ m_bp_select.set_vector(m_bp);
+
+ m_sml_block_min_max = bp_support.m_sml_block_min_max;
+ m_med_block_min_max = bp_support.m_med_block_min_max;
+
+ m_size = bp_support.m_size;
+ m_sml_blocks = bp_support.m_sml_blocks;
+ m_med_blocks = bp_support.m_med_blocks;
+ m_med_inner_blocks = bp_support.m_med_inner_blocks;
+ }
+
+ inline static size_type sml_block_idx(size_type i) {
+ return i/t_sml_blk;
+ }
+
+ inline static size_type med_block_idx(size_type i) {
+ return i/(t_sml_blk*t_med_deg);
+ }
+
+ inline static bool is_root(size_type v) {
+ return v==0;
+ }
+
+ inline static bool is_left_child(size_type v) {
+ assert(!is_root(v));
+ return v%2;
+ }
+
+ inline static bool is_right_child(size_type v) {
+ assert(!is_root(v));
+ return !(v%2);
+ }
+
+ inline static size_type parent(size_type v) {
+ assert(!is_root(v));
+ return (v-1)/2;
+ }
+
+ inline static size_type left_child(size_type v) {
+ return 2*v+1;
+ }
+
+ inline static size_type right_child(size_type v) {
+ return 2*v+2;
+ }
+
+ inline bool node_exists(size_type v)const {
+ return v < (m_med_inner_blocks + m_med_blocks);
+ }
+
+ inline static size_type right_sibling(size_type v) {
+ return ++v;
+ }
+
+ inline static size_type left_sibling(size_type v) {
+ return --v;
+ }
+
+ inline bool is_leaf(size_type v)const {
+ return v >= m_med_inner_blocks;
+ }
+
+ inline difference_type min_value(size_type v)const {
+ return m_size-((difference_type)m_med_block_min_max[2*v]);
+ }
+
+ inline difference_type max_value(size_type v)const {
+ return m_med_block_min_max[2*v+1]-m_size;
+ }
+
+ inline difference_type sml_min_value(size_type sml_block)const {
+ return (1 - ((difference_type)m_sml_block_min_max[sml_block<<1]));
+ }
+
+ inline difference_type sml_max_value(size_type sml_block)const {
+ return (difference_type)m_sml_block_min_max[(sml_block<<1)+1] - 1;
+ }
+
+ void print_node(size_type v)const {
+ std::cout<< "v = "<< v <<" (" << min_value(v)
+ << ", " << max_value(v) << ")" ;
+ if (is_leaf(v)) {
+ std::cout<<" range: ["<<(v-m_med_inner_blocks)*t_med_deg* t_sml_blk
+ << ","<<(v-m_med_inner_blocks+1)*t_med_deg* t_sml_blk-1<<"]";
+ }
+ std::cout<< std::endl;
+ }
+
+ //! Calculate the min parenthesis \f$j>i\f$ with \f$excess(j)=excess(i)+rel\f$
+ /*! \param i The index of a parenthesis in the supported sequence.
+ * \param rel The excess difference to the excess value of parentheses \f$i\f$.
+ * \return If there exists a parenthesis \f$ j>i\f$ with
+ * \f$ excess(j) = excess(i)+rel \f$, \f$j\f$ is returned
+ * otherwise size().
+ */
+ size_type fwd_excess(size_type i, difference_type rel)const {
+ size_type j;
+ // (1) search the small block for the answer
+ if ((j = near_fwd_excess(*m_bp, i+1, rel, t_sml_blk)) > i) {
+ return j;
+ }
+ difference_type desired_excess = excess(i)+rel;
+ // (2) scan the small blocks of the current median block for an answer
+ if ((j = fwd_excess_in_med_block(sml_block_idx(i)+1, desired_excess)) != size()) {
+ return j;
+ }
+ // (3) search the min-max tree of the medium blocks for the right med block
+ if (med_block_idx(i) == m_med_blocks) // if we are already in the last medium block => we are done
+ return size();
+ size_type v = m_med_inner_blocks + med_block_idx(i);
+ // (3 a) go up the tree
+ while (!is_root(v)) {
+ if (is_left_child(v)) { // if the node is a left child
+ v = right_sibling(v); // choose right sibling
+ if (min_value(v) <= desired_excess and desired_excess <= max_value(v)) // found solution
+ break;
+ }
+ v = parent(v); // choose parent
+ }
+ // (3 b) go down the tree
+ if (!is_root(v)) { // found solution for the query
+ while (!is_leaf(v)) {
+ v = left_child(v); // choose left child
+ if (!(min_value(v) <= desired_excess and desired_excess <= max_value(v))) {
+ v = right_sibling(v); // choose right child == right sibling of the left child
+ assert((min_value(v) <= desired_excess and desired_excess <= max_value(v)));
+ }
+ }
+ return fwd_excess_in_med_block((v-m_med_inner_blocks)*t_med_deg, desired_excess);
+ }
+ // no solution found
+ return size();
+ }
+
+ //! Calculate the maximal parenthesis \f$ j<i \f$ with \f$ excess(j) = excess(i)+rel \f$
+ /*! \param i The index of a parenthesis in the supported sequence.
+ * \param rel The excess difference to the excess value of parenthesis \f$i\f$.
+ * \return If there exists a parenthesis \f$i<j\f$ with \f$ excess(j) = excess(i)+rel\f$, \f$j\f$ is returned
+ * otherwise size().
+ */
+ size_type bwd_excess(size_type i, difference_type rel)const {
+ size_type j;
+ if (i == 0) {
+ return rel == 0 ? -1 : size();
+ }
+ // (1) search the small block for the answer
+ if ((j = near_bwd_excess(*m_bp, i-1, rel, t_sml_blk)) < i or j == (size_type)-1) {
+ return j;
+ }
+ difference_type desired_excess = excess(i)+rel;
+ // (2) scan the small blocks of the current median block for an answer
+ if ((j = bwd_excess_in_med_block(sml_block_idx(i)-1, desired_excess)) != size()) {
+ return j;
+ }
+ // (3) search the min-max tree of the medium blocks for the right med block
+ if (med_block_idx(i) == 0) { // if we are already in the first medium block => we are done
+ if (desired_excess == 0)
+ return -1;
+ return size();
+ }
+ size_type v = m_med_inner_blocks + med_block_idx(i);
+ // (3 a) go up the tree
+ while (!is_root(v)) {
+ if (is_right_child(v)) { // if the node is a right child
+ v = left_sibling(v); // choose left sibling
+ if (min_value(v) <= desired_excess and desired_excess <= max_value(v)) // found solution
+ break;
+ }
+ v = parent(v); // choose parent
+ }
+ // (3 b) go down the tree
+ if (!is_root(v)) { // found solution for the query
+ while (!is_leaf(v)) {
+ v = right_child(v); // choose child
+ if (!(min_value(v) <= desired_excess and desired_excess <= max_value(v))) {
+ v = left_sibling(v); // choose left child == left sibling of the right child
+ assert((min_value(v) <= desired_excess and desired_excess <= max_value(v)));
+ }
+ }
+ return bwd_excess_in_med_block((v-m_med_inner_blocks)*t_med_deg+(t_med_deg-1), desired_excess);
+ } else if (desired_excess == 0) {
+ return -1;
+ }
+ // no solution found
+ return size();
+ }
+
+ //! Calculate the maximal parentheses \f$ j \leq sml_block_idx\cdot t_sml_blk+(t_sml_blk-1) \f$ with \f$ excess(j)=desired\_excess \f$
+ size_type bwd_excess_in_med_block(size_type sml_block_idx, difference_type desired_excess)const {
+ // get the first small block in the medium block right to the current med block
+ size_type first_sml_block_in_med_block = (med_block_idx(sml_block_idx*t_sml_blk))*t_med_deg;
+
+ while ((sml_block_idx+1) and sml_block_idx >= first_sml_block_in_med_block) {
+ difference_type ex = (sml_block_idx == 0) ? 0 : excess(sml_block_idx*t_sml_blk-1);
+ difference_type min_ex = ex + (1 - ((difference_type)m_sml_block_min_max[2*sml_block_idx]));
+ difference_type max_ex = ex + (m_sml_block_min_max[2*sml_block_idx+1] - 1);
+
+ if (min_ex <= desired_excess and desired_excess <= max_ex) {
+ size_type j = near_bwd_excess(*m_bp, (sml_block_idx+1)*t_sml_blk-1, desired_excess-excess((sml_block_idx+1)*t_sml_blk), t_sml_blk);
+ return j;
+ }
+ --sml_block_idx;
+ }
+ if (sml_block_idx == 0 and desired_excess == 0)
+ return -1;
+ return size();
+ }
+
+ //! Calculate the minimal parentheses \f$ j \geq sml_block_idx\cdot t_sml_blk \f$ with \f$ excess(j)=desired\_excess \f$
+ size_type fwd_excess_in_med_block(size_type sml_block_idx, difference_type desired_excess)const {
+ // get the first small block in the medium block right to the current med block
+ size_type first_sml_block_nr_in_next_med_block = (med_block_idx(sml_block_idx*t_sml_blk)+1)*t_med_deg;
+ if (first_sml_block_nr_in_next_med_block > m_sml_blocks)
+ first_sml_block_nr_in_next_med_block = m_sml_blocks;
+
+ assert(sml_block_idx > 0);
+ while (sml_block_idx < first_sml_block_nr_in_next_med_block) {
+ difference_type ex = excess(sml_block_idx*t_sml_blk-1);
+ difference_type min_ex = ex + (1 - ((difference_type)m_sml_block_min_max[2*sml_block_idx]));
+ difference_type max_ex = ex + m_sml_block_min_max[2*sml_block_idx+1] - 1;
+ if (min_ex <= desired_excess and desired_excess <= max_ex) {
+ size_type j = near_fwd_excess(*m_bp, sml_block_idx*t_sml_blk, desired_excess-ex, t_sml_blk);
+ return j;
+ }
+ ++sml_block_idx;
+ }
+ return size();
+ }
+
+ public:
+ const rank_type& bp_rank = m_bp_rank; //!< RS for the underlying BP sequence.
+ const select_type& bp_select = m_bp_select; //!< SS for the underlying BP sequence.
+ const sml_block_array_type& sml_block_min_max = m_sml_block_min_max; //!< Small blocks array. Rel. min/max for the small blocks.
+ const med_block_array_type& med_block_min_max = m_med_block_min_max; //!< Array containing the min max tree of the medium blocks.
+
+ bp_support_sada() {}
+
+ //! Constructor
+ explicit bp_support_sada(const bit_vector* bp): m_bp(bp),
+ m_size(bp==nullptr?0:bp->size()),
+ m_sml_blocks((m_size+t_sml_blk-1)/t_sml_blk),
+ m_med_blocks((m_size+t_sml_blk* t_med_deg-1)/(t_sml_blk* t_med_deg)),
+ m_med_inner_blocks(0) {
+ if (bp == nullptr or bp->size()==0)
+ return;
+ // initialize rank and select
+ util::init_support(m_bp_rank, bp);
+ util::init_support(m_bp_select, bp);
+
+ m_med_inner_blocks = 1;
+ // m_med_inner_blocks = (next power of 2 greater than or equal to m_med_blocks)-1
+ while (m_med_inner_blocks < m_med_blocks) {
+ m_med_inner_blocks <<= 1; assert(m_med_inner_blocks!=0);
+ }
+ --m_med_inner_blocks;
+ assert((m_med_inner_blocks == 0) or(m_med_inner_blocks%2==1));
+
+ m_sml_block_min_max = int_vector<>(2*m_sml_blocks, 0, bits::hi(t_sml_blk+2)+1);
+ m_med_block_min_max = int_vector<>(2*(m_med_blocks+m_med_inner_blocks), 0, bits::hi(2*m_size+2)+1);
+
+ // calculate min/max excess values of the small blocks and medium blocks
+ difference_type min_ex = 1, max_ex = -1, curr_rel_ex = 0, curr_abs_ex = 0;
+ for (size_type i=0; i < m_size; ++i) {
+ if ((*bp)[i])
+ ++curr_rel_ex;
+ else
+ --curr_rel_ex;
+ if (curr_rel_ex > max_ex) max_ex = curr_rel_ex;
+ if (curr_rel_ex < min_ex) min_ex = curr_rel_ex;
+ if ((i+1)%t_sml_blk == 0 or i+1 == m_size) {
+ size_type sidx = i/t_sml_blk;
+ m_sml_block_min_max[2*sidx ] = -(min_ex-1);
+ m_sml_block_min_max[2*sidx + 1] = max_ex+1;
+
+ size_type v = m_med_inner_blocks + sidx/t_med_deg;
+
+ if ((difference_type)(-(curr_abs_ex + min_ex)+m_size) > ((difference_type)m_med_block_min_max[2*v])) {
+ assert(curr_abs_ex+min_ex <= min_value(v));
+ m_med_block_min_max[2*v] = -(curr_abs_ex + min_ex)+m_size;
+ }
+
+ if ((difference_type)(curr_abs_ex + max_ex + m_size) > (difference_type)m_med_block_min_max[2*v + 1])
+ m_med_block_min_max[2*v + 1] = curr_abs_ex + max_ex + m_size;
+
+ curr_abs_ex += curr_rel_ex;
+ min_ex = 1; max_ex = -1; curr_rel_ex = 0;
+ }
+ }
+
+ for (size_type v = m_med_block_min_max.size()/2 - 1; !is_root(v); --v) {
+ size_type p = parent(v);
+ if (min_value(v) < min_value(p)) // update minimum
+ m_med_block_min_max[2*p] = m_med_block_min_max[2*v];
+ if (max_value(v) > max_value(p)) // update maximum
+ m_med_block_min_max[2*p+1] = m_med_block_min_max[2*v+1];
+ }
+ }
+
+ //! Copy constructor
+ bp_support_sada(const bp_support_sada& bp_support) {
+ copy(bp_support);
+ }
+
+ //! Move constructor
+ bp_support_sada(bp_support_sada&& bp_support) {
+ *this = std::move(bp_support);
+ }
+
+ //! Assignment operator
+ bp_support_sada& operator=(bp_support_sada&& bp_support) {
+ if (this != &bp_support) {
+ m_bp = std::move(bp_support.m_bp);
+ m_bp_rank = std::move(bp_support.m_bp_rank);
+ m_bp_rank.set_vector(m_bp);
+ m_bp_select = std::move(bp_support.m_bp_select);
+ m_bp_select.set_vector(m_bp);
+
+ m_sml_block_min_max = std::move(bp_support.m_sml_block_min_max);
+ m_med_block_min_max = std::move(bp_support.m_med_block_min_max);
+
+ m_size = std::move(bp_support.m_size);
+ m_sml_blocks = std::move(bp_support.m_sml_blocks);
+ m_med_blocks = std::move(bp_support.m_med_blocks);
+ m_med_inner_blocks = std::move(bp_support.m_med_inner_blocks);
+ }
+ return *this;
+ }
+
+ //! Swap method
+ /*! Swaps the content of the two data structure.
+ * You have to use set_vector to adjust the supported bit_vector.
+ * \param bp_support Object which is swapped.
+ */
+ void swap(bp_support_sada& bp_support) {
+ // m_bp.swap(bp_support.m_bp); use set_vector to set the supported bit_vector
+ m_bp_rank.swap(bp_support.m_bp_rank);
+ m_bp_select.swap(bp_support.m_bp_select);
+
+ m_sml_block_min_max.swap(bp_support.m_sml_block_min_max);
+ m_med_block_min_max.swap(bp_support.m_med_block_min_max);
+
+ std::swap(m_size, bp_support.m_size);
+ std::swap(m_sml_blocks, bp_support.m_sml_blocks);
+ std::swap(m_med_blocks, bp_support.m_med_blocks);
+ std::swap(m_med_inner_blocks, bp_support.m_med_inner_blocks);
+ }
+
+ //! Assignment operator
+ bp_support_sada& operator=(const bp_support_sada& bp_support) {
+ if (this != &bp_support) {
+ copy(bp_support);
+ }
+ return *this;
+ }
+ /*
+ bp_support_sada& operator=(bp_support_sada&& bps)
+ {
+ this->swap(bps);
+ return *this;
+ }
+ */
+ void set_vector(const bit_vector* bp) {
+ m_bp = bp;
+ m_bp_rank.set_vector(bp);
+ m_bp_select.set_vector(bp);
+ }
+
+ /*! Calculates the excess value at index i.
+ * \param i The index of which the excess value should be calculated.
+ */
+ inline difference_type excess(size_type i)const {
+ return (m_bp_rank(i+1)<<1)-i-1;
+ }
+
+ /*! Returns the number of opening parentheses up to and including index i.
+ * \pre{ \f$ 0\leq i < size() \f$ }
+ */
+ size_type rank(size_type i)const {
+ return m_bp_rank(i+1);
+ }
+
+ /*! Returns the index of the i-th opening parenthesis.
+ * \param i Number of the parenthesis to select.
+ * \pre{ \f$1\leq i < rank(size())\f$ }
+ * \post{ \f$ 0\leq select(i) < size() \f$ }
+ */
+ size_type select(size_type i)const {
+#ifdef USE_CACHE
+ size_type a = 0;
+ if (select_cache.exists(i, a)) {
+ return a;
+ } else {
+ a = m_bp_select(i);
+ select_cache.write(i, a);
+ return a;
+ }
+#endif
+ return m_bp_select(i);
+ }
+
+ /*! Calculate the index of the matching closing parenthesis to the parenthesis at index i.
+ * \param i Index of an parenthesis. 0 <= i < size().
+ * \return * i, if the parenthesis at index i is closing,
+ * * the position j of the matching closing parenthesis, if a matching parenthesis exists,
+ * * size() if no matching closing parenthesis exists.
+ */
+ size_type find_close(size_type i)const {
+ assert(i < m_size);
+ if (!(*m_bp)[i]) {// if there is a closing parenthesis at index i return i
+ return i;
+ }
+#ifdef USE_CACHE
+ size_type a = 0;
+ if (find_close_cache.exists(i, a)) {
+ return a;
+ } else {
+ a = fwd_excess(i, -1);
+ find_close_cache.write(i, a);
+ return a;
+ }
+#endif
+ return fwd_excess(i, -1);
+ }
+
+ //! Calculate the matching opening parenthesis to the closing parenthesis at position i
+ /*! \param i Index of a closing parenthesis.
+ * \return * i, if the parenthesis at index i is closing,
+ * * the position j of the matching opening parenthesis, if a matching parenthesis exists,
+ * * size() if no matching closing parenthesis exists.
+ */
+ size_type find_open(size_type i)const {
+ assert(i < m_size);
+ if ((*m_bp)[i]) {// if there is a opening parenthesis at index i return i
+ return i;
+ }
+#ifdef USE_CACHE
+ size_type a = 0;
+ if (find_open_cache.exists(i, a)) {
+ return a;
+ } else {
+ size_type bwd_ex = bwd_excess(i,0);
+ if (bwd_ex == size())
+ a = size();
+ else
+ a = bwd_ex+1;
+ find_open_cache.write(i, a);
+ return a;
+ }
+#endif
+ size_type bwd_ex = bwd_excess(i,0);
+ if (bwd_ex == size())
+ return size();
+ else
+ return bwd_ex+1;
+ }
+
+ //! Calculate the index of the opening parenthesis corresponding to the closest matching parenthesis pair enclosing i.
+ /*! \param i Index of an opening parenthesis.
+ * \return The index of the opening parenthesis corresponding to the closest matching parenthesis pair enclosing i,
+ * or size() if no such pair exists.
+ */
+ size_type enclose(size_type i)const {
+ assert(i < m_size);
+ if (!(*m_bp)[i]) { // if there is closing parenthesis at position i
+ return find_open(i);
+ }
+ size_type bwd_ex = bwd_excess(i, -2);
+ if (bwd_ex == size())
+ return size();
+ else
+ return bwd_ex+1;
+ }
+
+ //! The range restricted enclose operation for parentheses pairs \f$(i,\mu(i))\f$ and \f$(j,\mu(j))\f$.
+ /*! \param i First opening parenthesis.
+ * \param j Second opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The smallest index, say k, of an opening parenthesis such that findclose(i) < k < j and
+ * findclose(j) < findclose(k). If such a k does not exists, restricted_enclose(i,j) returns size().
+ * \par Time complexity
+ * \f$ \Order{block\_size} \f$
+ */
+ size_type rr_enclose(const size_type i, const size_type j)const {
+ assert(j < m_size);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ const size_type mip1 = find_close(i)+1;
+ if (mip1 >= j)
+ return size();
+ return rmq_open(mip1, j);
+ }
+
+ /*! Search the interval [l,r-1] for an opening parenthesis, say i, such that find_close(i) >= r.
+ * \param l The left end (inclusive) of the interval to search for the result.
+ * \param r The right end (exclusive) of the interval to search for the result.
+ * \return The minimal opening parenthesis i with \f$ \ell \leq i < r \f$ and \f$ find_close(i) \geq r \f$;
+ * if no such i exists size() is returned.
+ * \par Time complexity
+ * \f$ \Order{block\_size} \f$
+ */
+ size_type rmq_open(const size_type l, const size_type r)const {
+ assert(r < m_bp->size());
+ if (l >= r)
+ return size();
+ size_type res = rmq(l, r-1);
+ assert(res>=l and res<=r-1);
+ if ((*m_bp)[res] == 1) { // The parenthesis with minimal excess is opening
+ assert(find_close(res) >= r);
+ return res;
+ } else {
+ res = res+1; // go to the next parenthesis to the right
+ if (res < r) { // The parenthesis with minimal excess if closing and the next opening parenthesis is less than r
+ assert((*m_bp)[res] == 1);
+ size_type ec = enclose(res);
+ if (ec < l or ec == size()) {
+ assert(find_close(res)>=r);
+ return res;
+ } else {
+ assert(find_close(ec)>=r);
+ return ec;
+ }
+ } else if (res == r) {
+ size_type ec = enclose(res); // if m_bp[res]==0 => find_open(res), if m_bp[res]==1 => enclose(res)
+ if (ec >= l) {
+ assert(ec == size() or excess(ec)==excess(res-1));
+ return ec;
+ }
+ }
+ }
+ return size();
+ }
+
+ size_type median_block_rmq(size_type l_sblock, size_type r_sblock, bit_vector::difference_type& min_ex)const {
+ assert(l_sblock <= r_sblock+1);
+ size_type pos_min_block = (size_type)-1;
+ difference_type e = 0;
+ if (l_sblock == 0) {
+ if (sml_min_value(0) <= min_ex) {
+ pos_min_block = 0;
+ min_ex = sml_min_value(0);
+ }
+ l_sblock = 1;
+ }
+ for (size_type i=l_sblock; i <= r_sblock; ++i) {
+ if ((e = (excess(i*t_sml_blk-1) + sml_min_value(i))) <= min_ex) {
+ pos_min_block = i;
+ min_ex = e;
+ }
+ }
+ return pos_min_block;
+ }
+
+
+ //! The range minimum query (rmq) returns the index of the parenthesis with minimal excess in the range \f$[l..r]\f$
+ /*! \param l The left border of the interval \f$[l..r]\f$ (\f$l\leq r\f$).
+ * \param r The right border of the interval \f$[l..r]\f$ (\f$l \leq r\f$).
+ */
+ size_type rmq(size_type l, size_type r)const {
+ assert(l<=r);
+ size_type sbl = sml_block_idx(l);
+ size_type sbr = sml_block_idx(r);
+ difference_type min_rel_ex = 0;
+ if (sbl == sbr) { // if l and r are in the same small block
+ return near_rmq(*m_bp, l, r, min_rel_ex);
+ } else {
+ difference_type min_ex = 0; // current minimal excess value
+ size_type min_pos = 0; // current min pos
+ enum min_pos_type {POS, SMALL_BLOCK_POS, MEDIUM_BLOCK_POS};
+ enum min_pos_type pos_type = POS; // current
+ min_pos = near_rmq(*m_bp, l, (sbl+1)*t_sml_blk-1, min_rel_ex); // scan the leftmost small block of l
+ assert(min_pos >= l);
+ min_ex = excess(l) + min_rel_ex;
+
+ size_type mbl = med_block_idx(l);
+ size_type mbr = med_block_idx(r); assert(mbl <= mbr);
+
+ size_type temp = median_block_rmq(sbl+1, std::min((mbl+1)*t_med_deg-1, sbr-1), min_ex); // scan the medium block of l
+ if (temp != (size_type)-1) {
+ assert(temp* t_sml_blk >= l and temp* t_sml_blk <= r);
+ min_pos = temp;
+ assert(min_pos >= 0 and min_pos < m_sml_blocks);
+ pos_type = SMALL_BLOCK_POS;
+ }
+#if 0
+ // sequential scan the medium blocks
+ for (size_type v=mbl+1+m_med_inner_blocks; v < mbr + m_med_inner_blocks; ++v) {
+ assert(is_leaf(v));
+ if (min_value(v) <= min_ex) {
+ min_ex = min_value(v);
+ min_pos = v;
+ assert(min_pos-m_med_inner_blocks >= 0 and min_pos < m_med_blocks-m_med_inner_blocks);
+ pos_type = MEDIUM_BLOCK_POS;
+ }
+ }
+#else
+ // tree search in the min max tree of the medium blocks
+ if (mbr-mbl > 1) {
+ size_type v = mbl + 1 + m_med_inner_blocks;
+ size_type rcb = mbl + 1; // rightmost covered block
+ size_type h = 0; // subtree height
+ while (rcb < mbr-1) { // go up the tree until the rightmost covered block >= mbr-1
+ if (min_value(v) <= min_ex) {
+ min_ex = min_value(v); min_pos = v; pos_type = MEDIUM_BLOCK_POS;
+ }
+ if (is_right_child(v)) { // v is a right child
+ h += 1;
+ rcb += (1<<h);
+ v = right_sibling(parent(v));
+ } else { // it is a left child
+ rcb += (1<<h);
+ h += 1;
+ v = parent(v);
+ }
+ }
+ if (rcb <= mbr-1 and min_value(v) <= min_ex) {
+ min_ex = min_value(v); min_pos = v; pos_type = MEDIUM_BLOCK_POS;
+ }
+ assert(node_exists(v));
+ assert(rcb >= mbr-1);
+
+ while (rcb != mbr-1) { // go down the tree until the rightmost covered block = mbr-1
+ assert(h != (size_type)-1);
+ if (rcb > mbr-1) {
+ h = h-1;
+ rcb = rcb - (1<<h);
+ v = left_child(v);
+ } else { // rcb < mbr-1
+ h = h-1;
+ rcb = rcb + (1<<h);
+ v = right_sibling(right_child(v));
+ }
+ if (rcb <= mbr-1 and min_value(v) <= min_ex) {
+ min_ex = min_value(v); min_pos = v; pos_type = MEDIUM_BLOCK_POS;
+ }
+ }
+ if (pos_type == MEDIUM_BLOCK_POS) {
+ while (!is_leaf(min_pos)) {
+ min_pos = right_child(min_pos);
+ if (!node_exists(min_pos) or min_value(min_pos) > min_ex)
+ min_pos = left_sibling(min_pos);
+ }
+ }
+ }
+#endif
+
+ // search in the medium block of r
+ temp = median_block_rmq(std::max(mbr*t_med_deg, sbl+1), sbr-1, min_ex); // scan the medium block of r
+ if (temp != (size_type)-1) {
+ assert(temp* t_sml_blk >= l and temp* t_sml_blk <= r);
+ min_pos = temp;
+ pos_type = SMALL_BLOCK_POS;
+ }
+ // search in the small block of r
+ temp = near_rmq(*m_bp, sbr*t_sml_blk, r, min_rel_ex); // scan the small block of r
+ if ((excess(sbr*t_sml_blk) + min_rel_ex) <= min_ex) { // if it contains the minimum return its position
+ assert(temp>=l and temp<=r);
+ return temp;
+ }
+ // if the found minimum lies in a medium block => find its small block
+ if (pos_type == MEDIUM_BLOCK_POS) {
+ min_pos = min_pos - m_med_inner_blocks;
+ temp = median_block_rmq(min_pos*t_med_deg, (min_pos+1)*t_med_deg-1, min_ex);
+ assert(temp != (size_type)-1); // assert that we find a solution
+ assert(temp* t_sml_blk >= l and temp* t_sml_blk <= r);
+ min_pos = temp;
+ pos_type = SMALL_BLOCK_POS;
+ }
+ if (pos_type == SMALL_BLOCK_POS) {
+ min_pos = near_rmq(*m_bp, min_pos*t_sml_blk, (min_pos+1)*t_sml_blk-1, min_rel_ex);
+ assert(min_pos >=l and min_pos <= r);
+ }
+ return min_pos;
+ }
+ }
+
+ //! The range restricted enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The minimal opening parenthesis, say k, such that \f$ findclose(i) < k < j\f$ and
+ * findclose(j) < findclose(k). If such a k does not exists, restricted_enclose(i,j) returns size().
+ * \par Time complexity
+ * \f$ \Order{size()}\f$ in the worst case.
+ */
+ size_type rr_enclose_naive(size_type i, size_type j)const {
+ assert(j > i and j < m_size);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ size_type mi = find_close(i); // matching parenthesis to i
+ assert(mi > i and mi < j);
+ assert(find_close(j) > j);
+ size_type k = enclose(j);
+ if (k == m_size or k < i) // there exists no opening parenthesis at position mi<k<j.
+ return m_size;
+ size_type kk;
+ do {
+ kk = k;
+ k = enclose(k);
+ } while (k != m_size and k > mi);
+ return kk;
+ }
+
+ //! The double enclose operation
+ /*! \param i Index of an opening parenthesis.
+ * \param j Index of an opening parenthesis \f$ i<j \wedge findclose(i) < j \f$.
+ * \return The maximal opening parenthesis, say k, such that \f$ k<j \wedge k>findclose(j) \f$.
+ * If such a k does not exists, double_enclose(i,j) returns size().
+ */
+ size_type double_enclose(size_type i, size_type j)const {
+ assert(j > i);
+ assert((*m_bp)[i]==1 and(*m_bp)[j]==1);
+ size_type k = rr_enclose(i, j);
+ if (k == size())
+ return enclose(j);
+ else
+ return enclose(k);
+ }
+
+ //! Return the number of zeros which proceed position i in the balanced parentheses sequence.
+ /*! \param i Index of an parenthesis.
+ */
+ size_type preceding_closing_parentheses(size_type i)const {
+ assert(i < m_size);
+ if (!i) return 0;
+ size_type ones = m_bp_rank(i);
+ if (ones) { // ones > 0
+ assert(m_bp_select(ones) < i);
+ return i - m_bp_select(ones) - 1;
+ } else {
+ return i;
+ }
+ }
+
+ /*! The size of the supported balanced parentheses sequence.
+ * \return the size of the supported balanced parentheses sequence.
+ */
+ size_type size() const {
+ return m_size;
+ }
+
+ //! Serializes the bp_support_sada to a stream.
+ /*!
+ * \param out The outstream to which the data structure is written.
+ * \return The number of bytes written to out.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_sml_blocks, out, child, "sml_block_cnt");
+ written_bytes += write_member(m_med_blocks, out, child, "med_block_cnt");
+ written_bytes += write_member(m_med_inner_blocks, out, child, "med_inner_blocks");
+
+ written_bytes += m_bp_rank.serialize(out, child, "bp_rank");
+ written_bytes += m_bp_select.serialize(out, child, "bp_select");
+
+ written_bytes += m_sml_block_min_max.serialize(out, child, "sml_blocks");
+ written_bytes += m_med_block_min_max.serialize(out, child, "med_blocks");
+
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load the bp_support_sada for a bit_vector v.
+ /*!
+ * \param in The instream from which the data strucutre is read.
+ * \param bp Bit vector representing a balanced parentheses sequence that is supported by this data structure.
+ */
+ void load(std::istream& in, const bit_vector* bp) {
+ m_bp = bp;
+ read_member(m_size, in);
+ assert(m_size == bp->size());
+ read_member(m_sml_blocks, in);
+ read_member(m_med_blocks, in);
+ read_member(m_med_inner_blocks, in);
+
+ m_bp_rank.load(in, m_bp);
+ m_bp_select.load(in, m_bp);
+
+ m_sml_block_min_max.load(in);
+ m_med_block_min_max.load(in);
+ }
+};
+
+}// end namespace
+
+
+
+
+#endif
diff --git a/include/sdsl/coder.hpp b/include/sdsl/coder.hpp
new file mode 100644
index 0000000..7f46df8
--- /dev/null
+++ b/include/sdsl/coder.hpp
@@ -0,0 +1,77 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file coder.hpp
+ \brief coder.hpp contains the coder namespace and includes the header files of sdsl::coder::fibonacci, sdsl::coder::elias_delta, and sdsl::coder::run_length
+ \author Simon Gog
+ */
+#ifndef SDSL_CODER
+#define SDSL_CODER
+
+#include "int_vector.hpp"
+#include "coder_fibonacci.hpp"
+#include "coder_elias_delta.hpp"
+#include "coder_elias_gamma.hpp"
+#include "coder_comma.hpp"
+
+namespace sdsl
+{
+
+//! Namespace for the different coder of the sdsl.
+namespace coder
+{
+
+template<class Coder>
+class run_length
+{
+ public:
+ typedef uint64_t size_type;
+ static void encode(uint64_t x, uint64_t*& z, uint8_t offset);
+ static uint64_t encoding_length(const uint64_t* s, uint8_t s_offset, size_type bit_length);
+};
+
+template<class Coder>
+typename run_length<Coder>::size_type run_length<Coder>::encoding_length(const uint64_t* s, uint8_t s_offset, size_type bit_length)
+{
+ assert(s_offset < 64);
+ size_type i=0;
+ uint64_t w = (*s >> s_offset);
+ uint8_t last_bit = w&1;
+ size_type result = 0;
+ while (i < bit_length) {
+ size_type len = 0;
+ while (last_bit == (w&1) and i < bit_length) {
+// std::cout<<w<<" "<<i<<std::endl;
+ ++len; ++i; ++s_offset;
+ w >>= 1;
+ if (s_offset == 64) {
+ s_offset = 0;
+ w = *(++s);
+ }
+ }
+// std::cout<<"len="<<Coder::encoding_length(len)<<std::endl;
+ last_bit = (w&1);
+ result += Coder::encoding_length(len);
+ }
+ return result;
+}
+
+
+} // end namespace coder
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/coder_comma.hpp b/include/sdsl/coder_comma.hpp
new file mode 100644
index 0000000..afd095c
--- /dev/null
+++ b/include/sdsl/coder_comma.hpp
@@ -0,0 +1,319 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file coder_comma.hpp
+ \brief coder_comma.hpp contains the class sdsl::coder::comma
+ \author Uwe Baier
+ */
+#ifndef SDSL_CODER_COMMA_INCLUDED
+#define SDSL_CODER_COMMA_INCLUDED
+
+#include <sdsl/bits.hpp>
+#include <array>
+#include <math.h>
+
+namespace sdsl {
+
+namespace coder {
+
+//! A class to encode and decode between comma code and binary code.
+/*! \author Uwe Baier
+ *
+ * Comma coding works as the following:
+ * First of all, comma coding needs a parameter t_width which indicates
+ * how big a encoded digit will be (in bits), let's say t_width = 2.
+ * By use of t_width one can calculate a base for encoding, in detail
+ * this means
+ * base = 2^t_width - 1
+ * now, given any number it is encoded as the follows: The number gets displayed
+ * in the calculated base, and each digit of the number is saved with t_width bits.
+ * To indicate the end of the number, a termination digit is used (namely this is
+ * the value base).
+ * Example:
+ * t_width = 2 => base = 2^2 - 1 = 3
+ * Value to be encoded: 15
+ * 15 (base 10) = 120 (base 3)
+ * Encoded value: 120 (plus termination digit) = 01 10 00 11 in binary
+ * (last digit is termination digit)
+ *
+ * \tparam t_width Width of one digit used in comma code
+ */
+template<uint8_t t_width = 2>
+class comma {
+ private:
+ static_assert(t_width > 1 && t_width <= 32,
+ "comma coder: Width must be in interval [2,32]");
+
+ //base in which numbers are coded
+ static const uint32_t base = (1 << t_width) - 1;
+
+ //table needed for computation of encoding lengths.
+ //table contains entries of the kind (index, base^index)
+ //to know how much digits a number needs to be encoded.
+ static const size_t codelentbllen = ceil(64 / log2(base));
+ static std::array<uint64_t, codelentbllen> codelentbl;
+
+ //utility function to set up codelen table
+ static std::array<uint64_t, codelentbllen> createCodeLenTbl();
+
+ //helper function to encode a single number without
+ //termination digit
+ static void encode_in_base(uint64_t x, uint64_t *& z,
+ uint8_t& offset);
+ public:
+ typedef uint64_t size_type;
+ static const uint8_t min_codeword_length =
+ t_width; //0 needs t_width bits as termination
+
+ //// ENCODING /////////////////////////////////////////////////
+
+ //! Get the number of bits that are necessary to encode
+ // the value w in comma code.
+ /*! \param w 64bit int to get the length of its comma encoding.
+ */
+ static uint8_t encoding_length(uint64_t w);
+
+ //! Encode one positive integer x to an int_vector
+ // at bit position start_idx.
+ /* \param x Positive integer to encode.
+ \param z Raw data of vector to write the encoded form of x.
+ \param start_idx Beginning bit index to write the encoded form ox x in z.
+ */
+ static void encode(uint64_t x, uint64_t*& z, uint8_t& offset);
+
+ //! Encode integers contained in vector v into vector z
+ /* \param v vector containing positive integer values
+ \param z vector to put the encoded values
+ */
+ template<class int_vector>
+ static bool encode(const int_vector& v, int_vector& z);
+
+ //// DECODING /////////////////////////////////////////////////
+
+ //! Decode n comma encoded values beginning at start_idx
+ // in the bitstring "data"
+ /* \param data Bitstring
+ \param start_idx Starting index of the decoding.
+ \param n Number of values to decode from the bitstring.
+ \param it Iterator to store the values.
+ */
+ template<bool t_sumup, bool t_inc,class t_iter>
+ static uint64_t decode(const uint64_t* data,
+ const size_type start_idx, size_type n,
+ t_iter it=(t_iter)nullptr);
+
+ //! Decode n comma gamma encoded integers
+ // beginning at start_idx in the bitstring "data"
+ // and return the sum of these values.
+ /*! \param data Pointer to the beginning
+ of the comma encoded bitstring.
+ \param start_idx Index of the first bit
+ to encode the values from.
+ \param n Number of values to decode from the bitstring.
+ Attention: There have to be at least n encoded
+ values in the bitstring.
+ */
+ static uint64_t decode_prefix_sum(const uint64_t* data,
+ const size_type start_idx, size_type n);
+
+ //! Decode n comma gamma encoded integers
+ // beginning at start_idx ending at end_idx (exclusive)
+ // in the bitstring "data"
+ // and return the sum of these values.
+ /*! \param data Pointer to the beginning
+ of the comma encoded bitstring.
+ \param start_idx Index of the first bit
+ to encode the values from.
+ \param end_idx Index of the last bit
+ to encode the values from.
+ \param n Number of values to decode from the bitstring.
+ Attention: There have to be at least n encoded
+ values in the bitstring.
+ */
+ static uint64_t decode_prefix_sum(const uint64_t* data,
+ const size_type start_idx, const size_type end_idx,
+ size_type n);
+
+ //! Decode vector z containing comma encoded integers
+ // and store them in vector v.
+ /*! \param z vector that contains encoded integers.
+ \param v vector to store the decoded integers
+ */
+ template<class int_vector>
+ static bool decode(const int_vector& z, int_vector& v);
+
+ //interface needs this function for whatever :>
+ template<class int_vector>
+ static uint64_t* raw_data(int_vector& v) {
+ return v.m_data;
+ }
+};
+
+//// IMPLEMENTATION ///////////////////////////////////////////////////////////
+
+//// CODELENGTH TABLE SETUP ///////////////////////////////
+
+template<uint8_t t_width>
+std::array<uint64_t, comma<t_width>::codelentbllen> comma<t_width>::codelentbl =
+ createCodeLenTbl();
+
+template<uint8_t t_width>
+std::array<uint64_t, comma<t_width>::codelentbllen> comma<t_width>::createCodeLenTbl() {
+ std::array<uint64_t, codelentbllen> tbl;
+ uint64_t n = 1;
+ for (size_t i = 0; i < codelentbllen; i++) {
+ tbl[i] = n;
+ n = (n << t_width) - n; //n = n * base
+ }
+ return tbl;
+}
+
+//// Encoding /////////////////////////////////////////////
+
+template<uint8_t t_width>
+inline uint8_t comma<t_width>::encoding_length(uint64_t w) {
+ //use function table and binary search to determine the number of digits
+ //needed to encode w in given base.
+ uint8_t numdigits =
+ std::upper_bound(codelentbl.begin(), codelentbl.end(), w)
+ - codelentbl.begin();
+ //finally calculate length.
+ //Don't forget termination character on calculations ;)
+ return (numdigits + 1) * t_width;
+}
+
+template<uint8_t t_width>
+void comma<t_width>::encode_in_base(uint64_t x, uint64_t *& z,
+ uint8_t& offset) {
+ if (x) {
+ uint32_t digit = x % base; //get next digit
+ //encode digits with higher order
+ encode_in_base(x / base, z, offset);
+ //and write own digit
+ bits::write_int_and_move(z, digit, offset, t_width);
+ }
+}
+
+template<uint8_t t_width>
+inline void comma<t_width>::encode(uint64_t x, uint64_t*& z, uint8_t& offset) {
+ //encode x itself
+ encode_in_base(x, z, offset);
+ //and append the termination digit
+ bits::write_int_and_move(z, base, offset, t_width);
+}
+
+template<uint8_t t_width>
+template<class int_vector>
+bool comma<t_width>::encode(const int_vector& v, int_vector& z) {
+ //first, find out how much bits vector z needs to save values
+ typedef typename int_vector::size_type size_type;
+ size_type z_bit_size = 0;
+ for (typename int_vector::const_iterator it = v.begin(), end = v.end();
+ it != end; ++it) {
+ z_bit_size += encoding_length(*it);
+ }
+
+ //trim vector z to correct size
+ z.width(v.width());
+ z.bit_resize(z_bit_size); //for future may check if resizing works
+
+ //iterate again and save values in z
+ uint64_t* z_data = z.m_data;
+ uint8_t offset = 0;
+ for (typename int_vector::const_iterator it = v.begin(), end = v.end();
+ it != end; ++it) {
+ encode(*it, z_data, offset);
+ }
+ return true;
+}
+
+//// DECODING /////////////////////////////////////////////
+
+template<uint8_t t_width>
+template<bool t_sumup, bool t_inc, class t_iter>
+inline uint64_t comma<t_width>::decode(const uint64_t* data,
+ const size_type start_idx, size_type n, t_iter it) {
+ data += (start_idx >> 6); //jump to byte offset
+ uint8_t offset = start_idx & 0x3F; //and calculate bit offset
+ uint64_t value = 0;
+ for (size_type i = 0; i < n; i++) {
+ //read next value
+ uint64_t v = 0;
+ for (uint32_t digit = (uint32_t)bits::read_int_and_move(data, offset, t_width); //read first digit
+ digit != base; //while digit is not the terminating digit
+ v = (v << t_width) - v + digit, //v = v * base + digit
+ digit = (uint32_t)bits::read_int_and_move(data, offset, t_width)); //and read next digit
+ //now decide how to handle value
+ value = (t_sumup) ? value + v : v;
+ if (t_inc) *(it++) = value;
+ }
+ return value;
+}
+
+template<uint8_t t_width>
+uint64_t comma<t_width>::decode_prefix_sum(const uint64_t* data,
+ const size_type start_idx, size_type n) {
+ //easiest seems to be to use already build function decode...
+ return decode<true,false,int *>(data, start_idx, n);
+ //Note for above: 3rd template parameter ca be any pntr except void *
+}
+
+template<uint8_t t_width>
+uint64_t comma<t_width>::decode_prefix_sum(const uint64_t* data,
+ const size_type start_idx,
+ SDSL_UNUSED const size_type end_idx, size_type n) {
+ //end index does not change anything here...
+ return decode_prefix_sum(data, start_idx, n);
+}
+
+template<uint8_t t_width>
+template<class int_vector>
+bool comma<t_width>::decode(const int_vector& z, int_vector& v) {
+ //check if bit size is dividable through t_width.
+ if (z.bit_size() % t_width != 0) return false;
+
+ //calculate num of overall digits in z (including terminating digit)
+ uint64_t numOfDigits = z.bit_size() / t_width;
+ //iteration vars for z vector
+ const uint64_t *z_data = z.data();
+ uint8_t z_offset = 0;
+ //utility to count number of entries in z, and last read digit
+ uint32_t digit = base;
+ typename int_vector::size_type n = 0;
+
+ //iterate over all digits. each time a termination digit is
+ // detected, a encoded number in vector ends.
+ while (numOfDigits--) {
+ digit = (uint32_t)bits::read_int_and_move(z_data, z_offset, t_width);
+ if (digit == base) n++; //termination digit detected
+ }
+
+ //also, ensure last read digit was a termination digit
+ if (digit != base) return false;
+
+ //resize vector v
+ v.width(z.width());
+ v.resize(n);
+
+ //and finally decode and save result in v
+ decode<false, true>(z.data(), 0, n, v.begin());
+ return true;
+}
+
+} //end of namespace coder
+} //end of namespace sdsl
+
+#endif
diff --git a/include/sdsl/coder_elias_delta.hpp b/include/sdsl/coder_elias_delta.hpp
new file mode 100644
index 0000000..2a72a35
--- /dev/null
+++ b/include/sdsl/coder_elias_delta.hpp
@@ -0,0 +1,255 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file coder_elias_delta.hpp
+ \brief coder_elias_delta.hpp contains the class sdsl::coder::elias_delta
+ \author Simon Gog
+ */
+#ifndef SDSL_CODER_ELIAS_DELTA
+#define SDSL_CODER_ELIAS_DELTA
+
+#include "int_vector.hpp"
+
+namespace sdsl
+{
+
+namespace coder
+{
+
+//! A class to encode and decode between Elias-\f$\delta\f$ and binary code.
+class elias_delta
+{
+ public:
+ typedef uint64_t size_type;
+
+ static struct impl {
+ //! Array contains precomputed values for the decoding of the prefix sum of Elias delta encoded numbers.
+ /*! The 8 most significant bits contain the length of decoded bits.
+ * The following 8 bits contain the number of decoded values.
+ * The last 16 bits contain the sum of the decoded values.
+ */
+ uint32_t prefixsum[1<<16];
+
+ uint16_t prefixsum_8bit[(1<<8)*8];
+
+ impl() {
+ // initialize prefixsum
+ for (uint64_t x=0; x < (1<<16); ++x) {
+ const uint64_t* w = &x; // copy of x
+ uint64_t value = 0;
+ uint16_t numbers = 0, offset=0, offset2=0;
+ while ((x >> offset) !=0) {
+ uint64_t len_1_len = bits::read_unary(w, offset), len = 0;
+ if (len_1_len == 0) {
+ offset += 1;
+ value += 1;
+ ++numbers;
+ } else {
+ offset2 = offset + len_1_len +1;
+ len = bits::read_int(w, offset2, len_1_len) + (1ULL << len_1_len);
+ offset2 += len_1_len;
+ if (offset2 + len-1 <= 16) {
+ value += bits::read_int(w, offset2, len-1) + (1ULL << (len-1));
+ offset = offset2 + len - 1;
+ ++numbers;
+ } else break;
+ }
+ }
+ uint32_t result=0;// the highest 8 bit equal the shift/offset, the second highest 8 bit equal the number of decoded values,
+ // and the last 16 bit equals value of decoded prefix sum
+ result = (offset << 24) | (numbers<<16) | value;
+ if (value>0)
+ assert(offset > 0 and numbers > 0 and offset<=16 and numbers <= 16);
+ prefixsum[x] = result;
+ }
+ // initialize prefixsum_8bit
+
+ for (uint32_t maxi=1, idx=0; maxi<=8; ++maxi) {
+ for (uint64_t x=0; x < (1<<8); ++x) {
+ const uint64_t* w = &x; // copy of x
+ uint64_t value = 0;
+ uint32_t numbers = 0, offset=0, offset2=0;
+ while ((x >> offset) !=0 and numbers < maxi) {
+ uint64_t len_1_len = bits::read_unary(w, offset), len = 0;
+ if (len_1_len == 0) {
+ offset += 1;
+ value += 1;
+ ++numbers;
+ } else {
+ offset2 = offset + len_1_len +1;
+ len = bits::read_int(w, offset2, len_1_len) + (1ULL << len_1_len);
+ offset2 += len_1_len;
+ if (offset2 + len-1 <= 8) {
+ value += bits::read_int(w, offset2, len-1) + (1ULL << (len-1));
+ offset = offset2 + len - 1;
+ ++numbers;
+ } else break;
+ }
+ }
+ uint16_t result=0;// the highest 8 bit equal the shift/offset, the second highest 8 bit equal the number of decoded values,
+ // and the last 16 bit equals value of decoded prefix sum
+ result = (offset << 8) | (numbers<<4) | value;
+ prefixsum_8bit[idx++] = result;
+ }
+ }
+ }
+ } data;
+
+ static const uint8_t min_codeword_length = 1; // 1 represents 1 and is the code word with minimum length
+ static uint8_t encoding_length(uint64_t);
+ //! Decode n Elias-delta encoded bits beginning at start_idx in the bitstring "data"
+ /* \param data Bitstring
+ \param start_idx Starting index of the decoding.
+ \param n Number of values to decode from the bitstring.
+ \param it Iterator to decode the values.
+ */
+ template<bool t_sumup, bool t_inc,class t_iter>
+ static uint64_t decode(const uint64_t* data, const size_type start_idx, size_type n, t_iter it=(t_iter)nullptr);
+
+ //! Decode n Elias delta encoded integers beginning at start_idx in the bitstring "data" and return the sum of these values.
+ /*! \param data Pointer to the beginning of the Elias delta encoded bitstring.
+ \param start_idx Index of the first bit to endcode the values from.
+ \param n Number of values to decode from the bitstring. Attention: There have to be at least n encoded values in the bitstring.
+ */
+ static uint64_t decode_prefix_sum(const uint64_t* data, const size_type start_idx, size_type n);
+ static uint64_t decode_prefix_sum(const uint64_t* data, const size_type start_idx, const size_type end_idx, size_type n);
+
+ template<class int_vector>
+ static bool encode(const int_vector& v, int_vector& z);
+ template<class int_vector>
+ static bool decode(const int_vector& z, int_vector& v);
+
+ //! Encode one positive integer x to an int_vector at bit position start_idx.
+ /* \param x Positive integer to encode.
+ \param z Raw data of vector to write the encoded form of x.
+ \param start_idx Beginning bit index to write the encoded form ox x in z.
+ */
+ static void encode(uint64_t x, uint64_t*& z, uint8_t& offset);
+
+ template<class int_vector>
+ static uint64_t* raw_data(int_vector& v) {
+ return v.m_data;
+ }
+};
+
+// \sa coder::elias_delta::encoding_length
+inline uint8_t elias_delta::encoding_length(uint64_t w)
+{
+ uint8_t len_1 = w ? bits::hi(w) : 64;
+ return len_1 + (bits::hi(len_1+1)<<1) + 1;
+}
+
+template<class int_vector>
+bool elias_delta::encode(const int_vector& v, int_vector& z)
+{
+ typedef typename int_vector::size_type size_type;
+ z.width(v.width());
+ size_type z_bit_size = 0;
+ uint64_t w;
+ const uint64_t zero_val = v.width() < 64 ? (1ULL)<<v.width() : 0;
+ for (typename int_vector::const_iterator it = v.begin(), end = v.end(); it != end; ++it) {
+ if ((w=*it) == 0) {
+ w = zero_val;
+ }
+ z_bit_size += encoding_length(w);
+ }
+ z.bit_resize(z_bit_size); // Initial size of z
+ if (z_bit_size & 0x3F) { // if z_bit_size % 64 != 0
+ *(z.m_data + (z_bit_size>>6)) = 0; // initialize last word
+ }
+ z_bit_size = 0;
+ uint64_t* z_data = z.m_data;
+ uint8_t offset=0;
+ size_type len, len_1_len; // TODO: change to uint8_t and test it
+ for (typename int_vector::const_iterator it = v.begin(), end=v.end(); it != end; ++it) {
+ w = *it;
+ if (w == 0) {
+ w = zero_val;
+ }
+ // (number of bits to represent w)
+ len = w ? bits::hi(w)+1 : 65;
+ // (number of bits to represent the length of w) -1
+ len_1_len = bits::hi(len);
+ // Write unary representation for the length of the length of w
+ bits::write_int_and_move(z_data, 1ULL << len_1_len, offset, len_1_len+1);
+ if (len_1_len) {
+ bits::write_int_and_move(z_data, len, offset, len_1_len);
+ bits::write_int_and_move(z_data, w, offset, len-1);
+ }
+ }
+ return true;
+}
+
+inline void elias_delta::encode(uint64_t x, uint64_t*& z, uint8_t& offset)
+{
+ uint8_t len, len_1_len;
+ // (number of bits to represent w)
+ len = x ? bits::hi(x)+1 : 65;
+ // (number of bits to represent the length of w) - 1
+ len_1_len = bits::hi(len);
+ // Write unary representation for the length of the length of w
+ bits::write_int_and_move(z, 1ULL << len_1_len, offset, len_1_len+1);
+ if (len_1_len) {
+ bits::write_int_and_move(z, len, offset, len_1_len);
+ bits::write_int_and_move(z, x, offset, len-1);
+ }
+}
+
+template<class int_vector>
+bool elias_delta::decode(const int_vector& z, int_vector& v)
+{
+ typename int_vector::size_type len_1_len, len, n = 0;
+ const uint64_t* z_data = z.data();
+ const uint64_t* z_end = z.data()+(z.bit_size()>>6);
+ uint8_t offset = 0;
+ while ((z_data < z_end) or (z_data==z_end and offset < (z.bit_size()&0x3F))) {
+ len_1_len = bits::read_unary_and_move(z_data, offset);
+ if (len_1_len) {
+ len = bits::read_int_and_move(z_data, offset, len_1_len) + (1 << len_1_len);
+ bits::move_right(z_data, offset, len-1);
+ }
+ ++n;
+ }
+ v.width(z.width());
+ v.resize(n);
+ return decode<false, true>(z.data(), 0, n, v.begin());
+}
+
+template<bool t_sumup, bool t_inc, class t_iter>
+inline uint64_t elias_delta::decode(const uint64_t* data, const size_type start_idx, size_type n, t_iter it)
+{
+ data += (start_idx >> 6);
+ uint64_t value = 0;
+ size_type i = 0;
+ size_type len_1_len, len;
+ uint8_t offset = start_idx & 0x3F;
+ while (i++ < n) {// while not all values are decoded
+ if (!t_sumup) value = 0;
+ len_1_len = bits::read_unary_and_move(data, offset); // read length of length of x
+ if (!len_1_len) {
+ value += 1;
+ } else {
+ len = bits::read_int_and_move(data, offset, len_1_len) + (1ULL << len_1_len);
+ value += bits::read_int_and_move(data, offset, len-1) + (len-1<64) * (1ULL << (len-1));
+ }
+ if (t_inc) *(it++) = value;
+ }
+ return value;
+}
+
+} // end namespace coder
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/coder_elias_gamma.hpp b/include/sdsl/coder_elias_gamma.hpp
new file mode 100644
index 0000000..7afc346
--- /dev/null
+++ b/include/sdsl/coder_elias_gamma.hpp
@@ -0,0 +1,252 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file coder_elias_gamma.hpp
+ \brief coder_elias_gamma.hpp contains the class sdsl::coder::elias_gamma
+ \author Simon Gog
+ */
+#ifndef SDSL_CODER_ELIAS_GAMMA
+#define SDSL_CODER_ELIAS_GAMMA
+
+#include "int_vector.hpp"
+
+namespace sdsl
+{
+
+namespace coder
+{
+
+//! A class to encode and decode between Elias-\f$\delta\f$ and binary code.
+class elias_gamma
+{
+ public:
+ typedef uint64_t size_type;
+
+ static struct impl {
+ //! Array contains precomputed values for the decoding of the prefix sum of Elias gamma encoded numbers.
+ /*! The 8 most significant bits contain the length of decoded bits.
+ * The following 8 bits contain the number of decoded values.
+ * The last 16 bits contain the sum of the decoded values.
+ */
+ uint32_t prefixsum[1<<16];
+
+ uint16_t prefixsum_8bit[(1<<8)*8];
+
+ impl() {
+ // initialize prefixsum
+ for (uint64_t x=0; x < (1<<16); ++x) {
+ const uint64_t* w = &x; // copy of x
+ uint64_t value = 0;
+ uint16_t numbers = 0, offset=0, offset2=0;
+ while ((x >> offset) !=0) {
+ uint64_t len_1 = bits::read_unary(w, offset);
+ if (len_1 == 0) {
+ offset += 1;
+ value += 1;
+ ++numbers;
+ } else {
+ offset2 = offset + len_1 + 1;
+ if (offset2 + len_1 <= 16) {
+ value += bits::read_int(w, offset2, len_1) + (1ULL << len_1);
+ offset = offset2 + len_1;
+ ++numbers;
+ } else break;
+ }
+ }
+ uint32_t result=0;// the highest 8 bit equal the shift/offset, the second highest 8 bit equal the number of decoded values,
+ // and the last 16 bit equals value of decoded prefix sum
+ result = (offset << 24) | (numbers<<16) | value;
+ if (value>0)
+ assert(offset > 0 and numbers > 0 and offset<=16 and numbers <= 16);
+ prefixsum[x] = result;
+ }
+ // initialize prefixsum_8bit
+
+ for (uint32_t maxi=1, idx=0; maxi<=8; ++maxi) {
+ for (uint64_t x=0; x < (1<<8); ++x) {
+ const uint64_t* w = &x; // copy of x
+ uint64_t value = 0;
+ uint32_t numbers = 0, offset=0, offset2=0;
+ while ((x >> offset) !=0 and numbers < maxi) {
+ uint64_t len_1 = bits::read_unary(w, offset);
+ if (len_1 == 0) {
+ offset += 1;
+ value += 1;
+ ++numbers;
+ } else {
+ offset2 = offset + len_1 + 1;
+ if (offset2 + len_1 <= 8) {
+ value += bits::read_int(w, offset2, len_1) + (1ULL << len_1);
+ offset = offset2 + len_1;
+ ++numbers;
+ } else break;
+ }
+ }
+ uint16_t result=0;// the highest 8 bit equal the shift/offset, the second highest 8 bit equal the number of decoded values,
+ // and the last 16 bit equals value of decoded prefix sum
+ result = (offset << 12) | (numbers<<8) | value;
+ prefixsum_8bit[idx++] = result;
+ }
+ }
+ }
+ } data;
+
+ static const uint8_t min_codeword_length = 1; // 1 represents 1 and is the code word with minimum length
+ static uint8_t encoding_length(uint64_t);
+ //! Decode n Elias-delta encoded bits beginning at start_idx in the bitstring "data"
+ /* \param data Bitstring
+ \param start_idx Starting index of the decoding.
+ \param n Number of values to decode from the bitstring.
+ \param it Iterator to decode the values.
+ */
+ template<bool t_sumup, bool t_inc,class t_iter>
+ static uint64_t decode(const uint64_t* data, const size_type start_idx, size_type n, t_iter it=(t_iter)nullptr);
+
+ //! Decode n Elias gamma encoded integers beginning at start_idx in the bitstring "data" and return the sum of these values.
+ /*! \param data Pointer to the beginning of the Elias gamma encoded bitstring.
+ \param start_idx Index of the first bit to endcode the values from.
+ \param n Number of values to decode from the bitstring. Attention: There have to be at least n encoded values in the bitstring.
+ */
+ static uint64_t decode_prefix_sum(const uint64_t* data, const size_type start_idx, size_type n);
+ static uint64_t decode_prefix_sum(const uint64_t* data, const size_type start_idx, const size_type end_idx, size_type n);
+
+ template<class int_vector>
+ static bool encode(const int_vector& v, int_vector& z);
+ template<class int_vector>
+ static bool decode(const int_vector& z, int_vector& v);
+
+ //! Encode one positive integer x to an int_vector at bit position start_idx.
+ /* \param x Positive integer to encode.
+ \param z Raw data of vector to write the encoded form of x.
+ \param start_idx Beginning bit index to write the encoded form ox x in z.
+ */
+ static void encode(uint64_t x, uint64_t*& z, uint8_t& offset);
+
+ template<class int_vector>
+ static uint64_t* raw_data(int_vector& v) {
+ return v.m_data;
+ }
+};
+
+// \sa coder::elias_gamma::encoding_length
+inline uint8_t elias_gamma::encoding_length(uint64_t w)
+{
+ uint8_t len_1 = w ? bits::hi(w) : 64;
+ return 2*len_1 + 1;
+}
+
+template<class int_vector>
+bool elias_gamma::encode(const int_vector& v, int_vector& z)
+{
+ typedef typename int_vector::size_type size_type;
+ z.width(v.width());
+ size_type z_bit_size = 0;
+ uint64_t w;
+ const uint64_t zero_val = v.width() < 64 ? (1ULL)<<v.width() : 0;
+ for (typename int_vector::const_iterator it = v.begin(), end = v.end(); it != end; ++it) {
+ if ((w=*it) == 0) {
+ w = zero_val;
+ }
+ z_bit_size += encoding_length(w);
+ }
+ z.bit_resize(z_bit_size); // Initial size of z
+ if (z_bit_size & 0x3F) { // if z_bit_size % 64 != 0
+ *(z.m_data + (z_bit_size>>6)) = 0; // initialize last word
+ }
+ z_bit_size = 0;
+ uint64_t* z_data = z.m_data;
+ uint8_t offset=0;
+ size_type len_1; // TODO: change to uint8_t and test it
+ for (typename int_vector::const_iterator it = v.begin(), end=v.end(); it != end; ++it) {
+ w = *it;
+ if (w == 0) {
+ w = zero_val;
+ }
+ // (number of bits to represent w)-1
+ if (!w) {
+ len_1 = 64;
+ bits::write_int_and_move(z_data, 0ULL, offset, 64);
+ bits::write_int_and_move(z_data, 1ULL, offset, 1);
+ } else {
+ len_1 = bits::hi(w);
+ bits::write_int_and_move(z_data, 1ULL << len_1, offset, len_1+1);
+ }
+ if (len_1) {
+ bits::write_int_and_move(z_data, w, offset, len_1);
+ }
+ }
+ return true;
+}
+
+inline void elias_gamma::encode(uint64_t x, uint64_t*& z, uint8_t& offset)
+{
+ uint8_t len_1 = 0;
+ if (!x) {
+ len_1 = 64;
+ bits::write_int_and_move(z, 0, offset, 64);
+ bits::write_int_and_move(z, 1, offset, 1);
+ } else {
+ len_1 = bits::hi(x);
+ bits::write_int_and_move(z, 1ULL << len_1, offset, len_1+1);
+ }
+ if (len_1) {
+ bits::write_int_and_move(z, x, offset, len_1);
+ }
+}
+
+template<class int_vector>
+bool elias_gamma::decode(const int_vector& z, int_vector& v)
+{
+ typename int_vector::size_type len_1, n = 0;
+ const uint64_t* z_data = z.data();
+ const uint64_t* z_end = z.data()+(z.bit_size()>>6);
+ uint8_t offset = 0;
+ while ((z_data < z_end) or (z_data==z_end and offset < (z.bit_size()&0x3F))) {
+ len_1 = bits::read_unary_and_move(z_data, offset);
+ if (len_1) {
+ bits::move_right(z_data, offset, len_1);
+ }
+ ++n;
+ }
+ v.width(z.width());
+ v.resize(n);
+ return decode<false, true>(z.data(), 0, n, v.begin());
+}
+
+template<bool t_sumup, bool t_inc, class t_iter>
+inline uint64_t elias_gamma::decode(const uint64_t* data, const size_type start_idx, size_type n, t_iter it)
+{
+ data += (start_idx >> 6);
+ uint64_t value = 0;
+ size_type i = 0;
+ size_type len_1;
+ uint8_t offset = start_idx & 0x3F;
+ while (i++ < n) {// while not all values are decoded
+ if (!t_sumup) value = 0;
+ len_1 = bits::read_unary_and_move(data, offset); // read length of x-1
+ if (!len_1) {
+ value += 1;
+ } else {
+ value += bits::read_int_and_move(data, offset, len_1) + (len_1<64) * (1ULL << len_1);
+ }
+ if (t_inc) *(it++) = value;
+ }
+ return value;
+}
+
+} // end namespace coder
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/coder_fibonacci.hpp b/include/sdsl/coder_fibonacci.hpp
new file mode 100644
index 0000000..b77c860
--- /dev/null
+++ b/include/sdsl/coder_fibonacci.hpp
@@ -0,0 +1,416 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file coder_fibonacci.hpp
+ \brief coder_fibonacci.hpp contains the class sdsl::coder::fibonacci
+ \author Simon Gog
+ */
+#ifndef SDSL_CODER_FIBONACCI_INCLUDED
+#define SDSL_CODER_FIBONACCI_INCLUDED
+
+#include "int_vector.hpp"
+
+namespace sdsl
+{
+
+namespace coder
+{
+
+//! A class to encode and decode between Fibonacci and binary code.
+class fibonacci
+{
+ public:
+ static struct impl {
+ uint64_t fib12bit_to_bin[(1<<12)*8];
+ //! End position of the first Fibonacci encoded number in the 13-bit word.
+ /*! fib2bin_shift[x] = 0 if bit-pattern `11` does not occur in x. Otherwise
+ fib2bin_shift[x] = end position of the first Fibonacci encoded word.
+ E.g. Fib2binShift[3] = 2 and Fib2binShift[6] = 3.
+ Space: 256.0 kBytes
+ */
+ uint8_t fib2bin_shift[(1<<13)];
+ //! Array contains precomputed values for the decoding of a prefix sum of Fibonacci encoded integers
+ /*! The 5 most significant bits contain information about how far to shift to get to the next encoded integer.
+ If this 5 bits equal zero, there is no whole Fibonacci number encoded in the 16 bits...
+ space for Fib2bin_greedy-table 128.0 kBytes
+ maxentry = 1596 index of maxentry = 54613
+ */
+ uint16_t fib2bin_16_greedy[(1<<16)];
+
+ //! Array contains precomputed values for the decoding of a number in the Fibonacci system.
+ uint64_t fib2bin_0_95[(1<<12)*8];
+
+ impl() {
+ for (uint32_t x=0; x <= 0x1FFF; ++x) {
+ if (bits::cnt11(x)) {
+ fib2bin_shift[x] = bits::sel11(x, 1)+1;
+ } else {
+ fib2bin_shift[x] = 0;
+ }
+ }
+ for (uint32_t x=0; x < 1<<16; ++x) {
+ uint16_t w = 0;
+ uint32_t offset=0;
+ if (uint32_t cnt = bits::cnt11(x)) {
+ uint32_t y=x;
+ uint32_t fib_pos=1;
+ do {
+ if (y&1) {
+ w += bits::lt_fib[fib_pos-1];
+ if (y&2) {
+ --cnt; ++offset;
+ fib_pos=0;
+ y>>=1;
+ }
+ }
+ ++fib_pos; ++offset;
+ y>>=1;
+ } while (cnt);
+ }
+ fib2bin_16_greedy[x] = (offset<<11) | w;
+ }
+ for (uint32_t p=0; p<8; ++p) {
+ for (uint32_t x=0; x<=0xFFF; ++x) {
+ uint64_t w = 0;
+ for (uint32_t j=0; j < 12 and 12*p+j < 92; ++j) {
+ if ((x>>j)&1ULL) {
+ w += bits::lt_fib[12*p+j];
+ if (x>>(j+1)&1ULL) {
+ break;
+ }
+ }
+ }
+ fib2bin_0_95[(p<<12) | x] = w;
+ }
+ }
+ }
+ } data;
+
+ typedef uint64_t size_type;
+
+ static const uint8_t min_codeword_length = 2; // 11 represents 1 and is the code word with minimum length
+ //! Get the number of bits that are necessary to encode the value w in Fibonacci code.
+ /*! \param w 64bit integer to get the length of its fibonacci encoding. Inclusive the terminating 1 of the code.
+ */
+ static uint8_t encoding_length(uint64_t w);
+ //! Decode n Fibonacci encoded bits beginning at start_idx in the bitstring "data"
+ /* \param data Bitstring
+ \param start_idx Starting index of the decoding.
+ \param n Number of values to decode from the bitstring.
+ \param it Iterator
+ */
+ template<bool t_sumup, bool t_inc, class t_iter>
+ static uint64_t decode(const uint64_t* data, const size_type start_idx, size_type n, t_iter it=(t_iter)nullptr);
+
+ template<bool t_sumup, bool t_inc, class t_iter>
+ static uint64_t decode1(const uint64_t* data, const size_type start_idx, size_type n, t_iter it=(t_iter)nullptr);
+
+
+
+ //! Decode n Fibonacci encoded integers beginning at start_idx in the bitstring "data" and return the sum of these values.
+ /*! \param data Pointer to the beginning of the Fibonacci encoded bitstring.
+ \param start_idx Index of the first bit to encode the values from.
+ \param n Number of values to decode from the bitstring. Attention: There have to be at least n encoded values in the bitstring.
+ */
+ static uint64_t decode_prefix_sum(const uint64_t* data, const size_type start_idx, size_type n);
+
+ //! Decode n Fibonacci encoded integers beginning at start_idx and ending at end_idx (exclusive) in the bitstring "data" and return the sum of these values.
+ /*! \sa decode_prefix_sum
+ */
+ static uint64_t decode_prefix_sum(const uint64_t* data, const size_type start_idx, const size_type end_idx, size_type n);
+
+ template<class int_vector1, class int_vector2>
+ static bool encode(const int_vector1& v, int_vector2& z);
+
+ template<class int_vector>
+ static uint64_t* raw_data(int_vector& v) {
+ return v.m_data;
+ };
+
+ //! Encode one positive integer x to an int_vector at bit position start_idx.
+ /*! \param x Positive integer to encode.
+ \param z Raw data of vector to write the encoded form of x.
+ \param offset Start offset to write the encoded form of x in z. \f$0\leq offset< 64\f$.
+ */
+ static void encode(uint64_t x, uint64_t*& z, uint8_t& offset);
+
+ template<class int_vector1, class int_vector2>
+ static bool decode(const int_vector1& z, int_vector2& v);
+};
+
+inline uint8_t fibonacci::encoding_length(uint64_t w)
+{
+ if (w == 0) {
+ return 93;
+ }
+ // This limit for the leftmost 1bit in the resulting fib code could be improved using a table
+ uint8_t len_1 = bits::hi(w); // len-1 of the fib code
+ while (++len_1 < (uint8_t)(sizeof(bits::lt_fib)/sizeof(bits::lt_fib[0])) && w >= bits::lt_fib[len_1]);
+ return len_1+1;
+}
+
+template<class int_vector1, class int_vector2>
+inline bool fibonacci::encode(const int_vector1& v, int_vector2& z)
+{
+ uint64_t z_bit_size = 0;
+ uint64_t w;
+ const uint64_t zero_val = v.width() < 64 ? (1ULL)<<v.width() : 0;
+ for (typename int_vector1::const_iterator it=v.begin(), end = v.end(); it != end; ++it) {
+ if ((w=*it) == 0) {
+ if (v.width() < 64) {
+ w = zero_val;
+ }
+ }
+ z_bit_size += encoding_length(w);
+ }
+ z.bit_resize(z_bit_size);
+ if (z_bit_size & 0x3F) { // if z_bit_size % 64 != 0
+ *(z.m_data + (z_bit_size>>6)) = 0; // initialize last word
+ }
+ uint64_t* z_data = z.m_data;
+ uint8_t offset = 0;
+ uint64_t fibword_high = 0x0000000000000001ULL, fibword_low;
+ uint64_t t;
+ for (typename int_vector1::const_iterator it=v.begin(), end = v.end(); it != end; ++it) {
+ w = *it;
+ if (w == 0) {
+ w = zero_val;
+ }
+ int8_t len_1 = encoding_length(w)-1,j;
+ fibword_low = 0x0000000000000001ULL;
+
+ if (len_1 >= 64) { // length > 65
+ fibword_high = 0x0000000000000001ULL;
+ j = len_1-1;
+ if (w == 0) { // handle special case
+ fibword_high <<= 1;
+ fibword_high |= 1;
+ fibword_high <<= 1;
+ w -= bits::lt_fib[len_1-1];
+ j -= 2;
+ }
+ for (; j>63; --j) {
+ fibword_high <<= 1;
+ if (w >= (t=bits::lt_fib[j])) {
+ w -= t;
+ fibword_high |= 1;
+ if (w and j>64) {
+ fibword_high <<= 1;
+ --j;
+ } else {
+ fibword_high <<= (64-j);
+ break;
+ }
+ }
+ }
+ j = 64;
+ } else {
+ j = len_1-1;
+ }
+
+ for (; j >= 0; --j) {
+ fibword_low <<= 1;
+ if (w >= (t=bits::lt_fib[j])) {
+ w -= t;
+ fibword_low |= 1;
+ if (w) {
+ fibword_low <<= 1;
+ --j;
+ } else {
+ fibword_low <<= (j);
+ break;
+ }
+ }
+ }
+ if (len_1 >=64) {
+ bits::write_int_and_move(z_data, fibword_low, offset, 64);
+ bits::write_int_and_move(z_data, fibword_high, offset, len_1 - 63);
+ } else {
+ bits::write_int_and_move(z_data, fibword_low, offset, (len_1&0x3F) +1);
+ }
+ }
+ z.width(v.width());
+ return true;
+}
+
+inline void fibonacci::encode(uint64_t x, uint64_t*& z, uint8_t& offset)
+{
+ uint64_t fibword_high = 0x0000000000000001ULL, fibword_low;
+ uint64_t t;
+ int8_t len_1 = encoding_length(x)-1,j;
+ fibword_low = 0x0000000000000001ULL;
+
+ if (len_1 >= 64) { // length > 65
+ fibword_high = 0x0000000000000001ULL;
+ j = len_1-1;
+ if (x == 0) { // handle special case
+ fibword_high <<= 1;
+ fibword_high |= 1;
+ fibword_high <<= 1;
+ x -= bits::lt_fib[len_1-1];
+ j -= 2;
+ }
+ for (; j>63; --j) {
+ fibword_high <<= 1;
+ if (x >= (t=bits::lt_fib[j])) {
+ x -= t;
+ fibword_high |= 1;
+ if (x and j>64) {
+ fibword_high <<= 1;
+ --j;
+ } else {
+ fibword_high <<= (64-j);
+ break;
+ }
+ }
+ }
+ j = 64;
+ } else {
+ j = len_1-1;
+ }
+ for (; j >= 0; --j) {
+ fibword_low <<= 1;
+ if (x >= (t=bits::lt_fib[j])) {
+ x -= t;
+ fibword_low |= 1;
+ if (x) {
+ fibword_low <<= 1;
+ --j;
+ } else {
+ fibword_low <<= (j);
+ break;
+ }
+ }
+ }
+ if (len_1 >=64) {
+ bits::write_int_and_move(z, fibword_low, offset, 64);
+ bits::write_int_and_move(z, fibword_high, offset, len_1 - 63);
+ } else {
+ bits::write_int_and_move(z, fibword_low, offset, (len_1&0x3F) +1);
+ }
+}
+
+template<class int_vector1, class int_vector2>
+bool fibonacci::decode(const int_vector1& z, int_vector2& v)
+{
+ uint64_t n = 0, carry = 0; // n = number of values to be decoded
+ const uint64_t* data = z.data();
+ // Determine size of v
+ if (z.empty()) {// if z is empty we are ready with decoding
+ v.width(z.width());
+ v.resize(0);
+ return true;
+ }
+ for (typename int_vector1::size_type i=0; i < (z.capacity()>>6)-1; ++i, ++data) {
+ n += bits::cnt11(*data, carry);
+ }
+ if (z.capacity() != z.bit_size()) {
+ n += bits::cnt11((*data) & bits::lo_set[z.bit_size()&0x3F], carry);
+ } else {
+ n += bits::cnt11(*data, carry);
+ }
+ v.width(z.width()); v.resize(n);
+ return decode<false, true>(z.data(), 0, n, v.begin());
+}
+
+template<bool t_sumup, bool t_inc, class t_iter>
+inline uint64_t fibonacci::decode(const uint64_t* data, const size_type start_idx, size_type n, t_iter it)
+{
+ data += (start_idx >> 6);
+ uint64_t w = 0, value = 0;
+ int8_t buffered = 0; // bits buffered in w, in 0..64
+ int8_t read = start_idx & 0x3F; // read bits in current *data 0..63
+ int8_t shift = 0;
+ uint32_t fibtable = 0;
+ while (n) {// while not all values are decoded
+ while (buffered < 13 and bits::cnt11(w) < n) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else { // read < buffered
+ read += 64-buffered;
+ buffered = 64;
+ }
+ }
+ value += fibonacci::data.fib2bin_0_95[(fibtable<<12) | (w&0xFFF)];
+ shift = fibonacci::data.fib2bin_shift[w&0x1FFF];
+ if (shift > 0) {// if end of decoding
+ w >>= shift;
+ buffered -= shift;
+ if (t_inc) *(it++) = value;
+ if (!t_sumup and n!=1) value = 0;
+ fibtable = 0;
+ --n;
+ } else { // not end of decoding
+ w >>= 12;
+ buffered -= 12;
+ ++fibtable;
+ }
+ }
+ return value;
+}
+
+template<bool t_sumup, bool t_inc, class t_iter>
+inline uint64_t fibonacci::decode1(const uint64_t* data, const size_type start_idx, size_type n, t_iter it)
+{
+ data += (start_idx >> 6);
+ uint64_t w = 0, value = 0;
+ int8_t buffered = 0; // bits buffered in w, in 0..64
+ int8_t read = start_idx & 0x3F; // read bits in current *data 0..63
+ int8_t shift = 0;
+ uint32_t fibtable = 0;
+ uint8_t blocknr = (start_idx>>6)%9;
+ while (n) {// while not all values are decoded
+ while (buffered < 13 and bits::cnt11(w) < n) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++blocknr;
+ ++data;
+ if (blocknr==8) {
+ ++data;
+ blocknr=0;
+ }
+ buffered += 64-read;
+ read = 0;
+ } else { // read < buffered
+ read += 64-buffered;
+ buffered = 64;
+ }
+ }
+ value += fibonacci::data.fib2bin_0_95[(fibtable<<12) | (w&0xFFF)];
+ shift = fibonacci::data.fib2bin_shift[w&0x1FFF];
+ if (shift > 0) {// if end of decoding
+ w >>= shift;
+ buffered -= shift;
+ if (t_inc) *(it++) = value;
+ if (!t_sumup)
+ value = 0;
+ fibtable = 0;
+ --n;
+ } else { // not end of decoding
+ w >>= 12;
+ buffered -= 12;
+ ++fibtable;
+ }
+ }
+ return value;
+}
+
+} // end namespace coder
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/config.hpp b/include/sdsl/config.hpp
new file mode 100644
index 0000000..3cc258f
--- /dev/null
+++ b/include/sdsl/config.hpp
@@ -0,0 +1,61 @@
+#ifndef SDSL_CONFIG
+#define SDSL_CONFIG
+
+#include "uintx_t.hpp"
+#include <map>
+#include <string>
+
+namespace sdsl
+{
+namespace conf // namespace for library constant
+{
+// size of the buffer for reading and writing data in elements (not in bytes)
+const uint64_t SDSL_BLOCK_SIZE = (uint64_t)1<<22;
+
+const char KEY_BWT[] = "bwt";
+const char KEY_BWT_INT[] = "bwt_int";
+const char KEY_SA[] = "sa";
+const char KEY_CSA[] = "csa";
+const char KEY_CST[] = "cst";
+const char KEY_ISA[] = "isa";
+const char KEY_TEXT[] = "text";
+const char KEY_TEXT_INT[] = "text_int";
+const char KEY_PSI[] = "psi";
+const char KEY_LCP[] = "lcp";
+const char KEY_SAMPLE_CHAR[]= "sample_char";
+}
+typedef uint64_t int_vector_size_type;
+
+typedef std::map<std::string, std::string> tMSS;
+
+enum format_type {JSON_FORMAT, R_FORMAT, HTML_FORMAT};
+
+enum byte_sa_algo_type {LIBDIVSUFSORT, SE_SAIS};
+
+//! Helper class for construction process
+struct cache_config {
+ bool delete_files; // Flag which indicates if all files which were created
+ // during construction should be deleted.
+ std::string dir; // Directory for temporary files.
+ std::string id; // Identifier is part of temporary file names. If
+ // id is the empty string, then it will be replace
+ // a concatenation of PID and a unique ID inside the
+ // current process.
+ tMSS file_map; // Files stored during the construction process.
+ cache_config(bool f_delete_files=true, std::string f_dir="./", std::string f_id="", tMSS f_file_map=tMSS());
+};
+
+//! Helper classes to transform width=0 and width=8 to corresponding text key
+template<uint8_t width>
+struct key_text_trait {
+ static const char* KEY_TEXT;
+};
+
+//! Helper classes to transform width=0 and width=8 to corresponding bwt key
+template<uint8_t width>
+struct key_bwt_trait {
+ static const char* KEY_BWT;
+};
+}
+
+#endif
diff --git a/include/sdsl/construct.hpp b/include/sdsl/construct.hpp
new file mode 100644
index 0000000..40b5e3d
--- /dev/null
+++ b/include/sdsl/construct.hpp
@@ -0,0 +1,208 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file construct.hpp
+ \brief construct.hpp contains methods to construct indexes (compressed suffix arrays and trees).
+ \author Simon Gog
+*/
+
+#ifndef INCLUDED_SDSL_CONSTRUCT
+#define INCLUDED_SDSL_CONSTRUCT
+
+#include "sdsl_concepts.hpp"
+#include "int_vector.hpp"
+#include "construct_lcp.hpp"
+#include "construct_bwt.hpp"
+#include "construct_sa.hpp"
+#include <string>
+
+namespace sdsl
+{
+
+template<class int_vector>
+bool contains_no_zero_symbol(const int_vector& text, const std::string& file)
+{
+ for (int_vector_size_type i=0; i < text.size(); ++i) {
+ if ((uint64_t)0 == text[i]) {
+ throw std::logic_error(std::string("Error: File \"")+file+"\" contains zero symbol.");
+ return false;
+ }
+ }
+ return true;
+}
+
+template<class int_vector>
+void append_zero_symbol(int_vector& text)
+{
+ text.resize(text.size()+1);
+ text[text.size()-1] = 0;
+}
+
+
+template<class t_index>
+void construct(t_index& idx, std::string file, uint8_t num_bytes=0)
+{
+ tMSS file_map;
+ cache_config config;
+ if (is_ram_file(file)) {
+ config.dir = "@";
+ }
+ construct(idx, file, config, num_bytes);
+}
+
+template<class t_index, class t_data>
+void construct_im(t_index& idx, t_data data, uint8_t num_bytes=0)
+{
+ std::string tmp_file = ram_file_name(util::to_string(util::pid())+"_"+util::to_string(util::id()));
+ store_to_file(data, tmp_file);
+ construct(idx, tmp_file, num_bytes);
+ ram_fs::remove(tmp_file);
+}
+
+//! Constructs an index object of type t_index for a text stored on disk.
+/*!
+ * \param idx t_index object. Any sdsl suffix array of suffix tree.
+ * \param file Name of the text file. The representation of the file
+ * is dependent on the next parameter.
+ * \
+ * \param num_bytes If `num_bytes` equals 0, the file format is a serialized
+ * int_vector<>. Otherwise the file is interpreted as sequence
+ * of `num_bytes`-byte integer stored in big endian order.
+ */
+template<class t_index>
+void construct(t_index& idx, const std::string& file, cache_config& config, uint8_t num_bytes=0)
+{
+ // delegate to CSA or CST construction
+ typename t_index::index_category index_tag;
+ construct(idx, file, config, num_bytes, index_tag);
+}
+
+// Specialization for WTs
+template<class t_index>
+void construct(t_index& idx, const std::string& file, cache_config& config, uint8_t num_bytes, wt_tag)
+{
+ auto event = memory_monitor::event("construct wavelet tree");
+ int_vector<t_index::alphabet_category::WIDTH> text;
+ load_vector_from_file(text, file, num_bytes);
+ std::string tmp_key = util::to_string(util::pid())+"_"+util::to_string(util::id());
+ std::string tmp_file_name = cache_file_name(tmp_key, config);
+ store_to_file(text, tmp_file_name);
+ util::clear(text);
+ {
+ int_vector_buffer<t_index::alphabet_category::WIDTH> text_buf(tmp_file_name);
+ t_index tmp(text_buf, text_buf.size());
+ idx.swap(tmp);
+ }
+ sdsl::remove(tmp_file_name);
+}
+
+// Specialization for CSAs
+template<class t_index>
+void construct(t_index& idx, const std::string& file, cache_config& config, uint8_t num_bytes, csa_tag)
+{
+ auto event = memory_monitor::event("construct CSA");
+ const char* KEY_TEXT = key_text_trait<t_index::alphabet_category::WIDTH>::KEY_TEXT;
+ const char* KEY_BWT = key_bwt_trait<t_index::alphabet_category::WIDTH>::KEY_BWT;
+ typedef int_vector<t_index::alphabet_category::WIDTH> text_type;
+ {
+ auto event = memory_monitor::event("parse input text");
+ // (1) check, if the text is cached
+ if (!cache_file_exists(KEY_TEXT, config)) {
+ text_type text;
+ load_vector_from_file(text, file, num_bytes);
+ if (contains_no_zero_symbol(text, file)) {
+ append_zero_symbol(text);
+ store_to_cache(text,KEY_TEXT, config);
+ }
+ }
+ register_cache_file(KEY_TEXT, config);
+ }
+ {
+ // (2) check, if the suffix array is cached
+ auto event = memory_monitor::event("SA");
+ if (!cache_file_exists(conf::KEY_SA, config)) {
+ construct_sa<t_index::alphabet_category::WIDTH>(config);
+ }
+ register_cache_file(conf::KEY_SA, config);
+ }
+ {
+ // (3) construct BWT
+ auto event = memory_monitor::event("BWT");
+ if (!cache_file_exists(KEY_BWT, config)) {
+ construct_bwt<t_index::alphabet_category::WIDTH>(config);
+ }
+ register_cache_file(KEY_BWT, config);
+ }
+ {
+ // (4) use BWT to construct the CSA
+ auto event = memory_monitor::event("construct CSA");
+ t_index tmp(config);
+ idx.swap(tmp);
+ }
+ if (config.delete_files) {
+ auto event = memory_monitor::event("delete temporary files");
+ util::delete_all_files(config.file_map);
+ }
+}
+
+// Specialization for CSTs
+template<class t_index>
+void construct(t_index& idx, const std::string& file, cache_config& config, uint8_t num_bytes, cst_tag)
+{
+ auto event = memory_monitor::event("construct CST");
+ const char* KEY_TEXT = key_text_trait<t_index::alphabet_category::WIDTH>::KEY_TEXT;
+ const char* KEY_BWT = key_bwt_trait<t_index::alphabet_category::WIDTH>::KEY_BWT;
+ csa_tag csa_t;
+ {
+ // (1) check, if the compressed suffix array is cached
+ typename t_index::csa_type csa;
+ if (!cache_file_exists(std::string(conf::KEY_CSA)+"_"+util::class_to_hash(csa), config)) {
+ cache_config csa_config(false, config.dir, config.id, config.file_map);
+ construct(csa, file, csa_config, num_bytes, csa_t);
+ auto event = memory_monitor::event("store CSA");
+ config.file_map = csa_config.file_map;
+ store_to_cache(csa,std::string(conf::KEY_CSA)+"_"+util::class_to_hash(csa), config);
+ }
+ register_cache_file(std::string(conf::KEY_CSA)+"_"+util::class_to_hash(csa), config);
+ }
+ {
+ // (2) check, if the longest common prefix array is cached
+ auto event = memory_monitor::event("LCP");
+ register_cache_file(KEY_TEXT, config);
+ register_cache_file(KEY_BWT, config);
+ register_cache_file(conf::KEY_SA, config);
+ if (!cache_file_exists(conf::KEY_LCP, config)) {
+ if (t_index::alphabet_category::WIDTH==8) {
+ construct_lcp_semi_extern_PHI(config);
+ } else {
+ construct_lcp_PHI<t_index::alphabet_category::WIDTH>(config);
+ }
+ }
+ register_cache_file(conf::KEY_LCP, config);
+ }
+ {
+ auto event = memory_monitor::event("CST");
+ t_index tmp(config);
+ tmp.swap(idx);
+ }
+ if (config.delete_files) {
+ auto event = memory_monitor::event("delete temporary files");
+ util::delete_all_files(config.file_map);
+ }
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/construct_bwt.hpp b/include/sdsl/construct_bwt.hpp
new file mode 100644
index 0000000..68a5a58
--- /dev/null
+++ b/include/sdsl/construct_bwt.hpp
@@ -0,0 +1,82 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file construct_bwt.hpp
+ \brief construct_bwt.hpp contains a space and time efficient construction method for the Burrows and Wheeler Transform (BWT).
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CONSTRUCT_BWT
+#define INCLUDED_SDSL_CONSTRUCT_BWT
+
+#include "int_vector.hpp"
+#include "sfstream.hpp"
+#include "util.hpp"
+#include "config.hpp" // for cache_config
+
+#include <iostream>
+#include <stdexcept>
+#include <list>
+
+namespace sdsl
+{
+
+//! Constructs the Burrows and Wheeler Transform (BWT) from text over byte- or integer-alphabet and suffix array.
+/*! The algorithm constructs the BWT and stores it to disk.
+ * \tparam t_width Width of the text. 0==integer alphabet, 8=byte alphabet.
+ * \param config Reference to cache configuration
+ * \par Space complexity
+ * \f$ n \log \sigma \f$ bits
+ * \pre Text and Suffix array exist in the cache. Keys:
+ * * conf::KEY_TEXT for t_width=8 or conf::KEY_TEXT_INT for t_width=0
+ * * conf::KEY_SA
+ * \post BWT exist in the cache. Key
+ * * conf::KEY_BWT for t_width=8 or conf::KEY_BWT_INT for t_width=0
+ */
+template<uint8_t t_width>
+void construct_bwt(cache_config& config)
+{
+ static_assert(t_width == 0 or t_width == 8 , "construct_bwt: width must be `0` for integer alphabet and `8` for byte alphabet");
+
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<t_width> text_type;
+ typedef int_vector_buffer<t_width> bwt_type;
+ const char* KEY_TEXT = key_text_trait<t_width>::KEY_TEXT;
+ const char* KEY_BWT = key_bwt_trait<t_width>::KEY_BWT;
+
+ // (1) Load text from disk
+ text_type text;
+ load_from_cache(text, KEY_TEXT, config);
+ size_type n = text.size();
+ uint8_t bwt_width = text.width();
+
+ // (2) Prepare to stream SA from disc and BWT to disc
+ size_type buffer_size = 1000000; // buffer_size is a multiple of 8!, TODO: still true?
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config), std::ios::in, buffer_size);
+ std::string bwt_file = cache_file_name(KEY_BWT, config);
+ bwt_type bwt_buf(bwt_file, std::ios::out, buffer_size, bwt_width);
+
+ // (3) Construct BWT sequentially by streaming SA and random access to text
+ size_type to_add[2] = {(size_type)-1,n-1};
+ for (size_type i=0; i < n; ++i) {
+ bwt_buf[i] = text[ sa_buf[i]+to_add[sa_buf[i]==0] ];
+ }
+ bwt_buf.close();
+ register_cache_file(KEY_BWT, config);
+}
+
+}// end namespace
+
+#endif
diff --git a/include/sdsl/construct_config.hpp b/include/sdsl/construct_config.hpp
new file mode 100644
index 0000000..b2ed6cd
--- /dev/null
+++ b/include/sdsl/construct_config.hpp
@@ -0,0 +1,19 @@
+#ifndef INCLUDED_SDSL_CONSTRUCT_CONFIG
+#define INCLUDED_SDSL_CONSTRUCT_CONFIG
+
+#include "config.hpp"
+
+namespace sdsl
+{
+
+class construct_config
+{
+ public:
+ static byte_sa_algo_type byte_algo_sa;
+
+ construct_config() = delete;
+};
+
+}
+
+#endif
diff --git a/include/sdsl/construct_isa.hpp b/include/sdsl/construct_isa.hpp
new file mode 100644
index 0000000..7239ec9
--- /dev/null
+++ b/include/sdsl/construct_isa.hpp
@@ -0,0 +1,38 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file construct_isa.hpp
+ \brief construct_isa.hpp contains a space and time efficient construction method for the inverse suffix array
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CONSTRUCT_ISA
+#define INCLUDED_SDSL_CONSTRUCT_ISA
+
+#include "int_vector.hpp"
+#include "util.hpp"
+
+#include <iostream>
+#include <stdexcept>
+#include <list>
+
+namespace sdsl
+{
+
+void construct_isa(cache_config& config);
+
+}// end namespace
+
+#endif
diff --git a/include/sdsl/construct_lcp.hpp b/include/sdsl/construct_lcp.hpp
new file mode 100644
index 0000000..8abc787
--- /dev/null
+++ b/include/sdsl/construct_lcp.hpp
@@ -0,0 +1,287 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010-2013 Simon Gog
+ Copyright (C) 2013 Timo Beller
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file construct_lcp.hpp
+ \brief construct_lcp.hpp contains a space and time efficient construction method for lcp arrays
+ \author Simon Gog, Timo Beller
+*/
+#ifndef INCLUDED_SDSL_CONSTRUCT_LCP
+#define INCLUDED_SDSL_CONSTRUCT_LCP
+
+#include "config.hpp"
+#include "int_vector.hpp"
+#include "sfstream.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "util.hpp"
+#include "construct_isa.hpp"
+#include "construct_bwt.hpp"
+#include "wt_huff.hpp"
+#include "wt_algorithm.hpp"
+#include "construct_lcp_helper.hpp"
+
+#include <iostream>
+#include <stdexcept>
+#include <algorithm>
+
+//#define STUDY_INFORMATIONS
+
+namespace sdsl
+{
+
+//! Construct the LCP array for text over byte- or integer-alphabet.
+/*! The algorithm computes the lcp array and stores it to disk.
+ * \tparam t_width Width of the text. 0==integer alphabet, 8=byte alphabet.
+ * \param config Reference to cache configuration
+ * \pre Text and Suffix array exist in the cache. Keys:
+ * * conf::KEY_TEXT for t_width=8 or conf::KEY_TEXT_INT for t_width=0
+ * * conf::KEY_SA
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n} \f$
+ * \par Space complexity
+ * \f$ n (\log \sigma + \log n) \f$ bits
+ * \par Reference
+ * Toru Kasai, Gunho Lee, Hiroki Arimura, Setsuo Arikawa, Kunsoo Park:
+ * Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Applications.
+ * CPM 2001: 181-192
+ */
+template<uint8_t t_width>
+void construct_lcp_kasai(cache_config& config)
+{
+ static_assert(t_width == 0 or t_width == 8 , "construct_lcp_kasai: width must be `0` for integer alphabet and `8` for byte alphabet");
+ int_vector<> lcp;
+ typedef int_vector<>::size_type size_type;
+ construct_isa(config);
+ {
+ int_vector<t_width> text;
+ if (!load_from_cache(text, key_text_trait<t_width>::KEY_TEXT, config)) {
+ return;
+ }
+ int_vector_buffer<> isa_buf(cache_file_name(conf::KEY_ISA, config), std::ios::in, 1000000); // init isa file_buffer
+ int_vector<> sa;
+ if (!load_from_cache(sa, conf::KEY_SA, config)) {
+ return;
+ }
+ // use Kasai algorithm to compute the lcp values
+ for (size_type i=0,j=0,sa_1=0,l=0, n=isa_buf.size(); i < n; ++i) {
+ sa_1 = isa_buf[i]; // = isa[i]
+ if (sa_1) {
+ j = sa[sa_1-1];
+ if (l) --l;
+ assert(i!=j);
+ while (text[i+l]==text[j+l]) { // i+l < n and j+l < n are not necessary, since text[n]=0 and text[i]!=0 (i<n) and i!=j
+ ++l;
+ }
+ sa[ sa_1-1 ] = l; //overwrite sa array with lcp values
+ } else {
+ l = 0;
+ sa[ n-1 ] = 0;
+ }
+ }
+
+ for (size_type i=sa.size(); i>1; --i) {
+ sa[i-1] = sa[i-2];
+ }
+ sa[0] = 0;
+ lcp.swap(sa);
+ }
+ store_to_cache(lcp, conf::KEY_LCP, config);
+}
+
+
+//! Construct the LCP array for text over byte- or integer-alphabet.
+/*! The algorithm computes the lcp array and stores it to disk.
+ * \pre Text and Suffix array exist in the cache. Keys:
+ * * conf::KEY_TEXT for t_width=8 or conf::KEY_TEXT_INT for t_width=0
+ * * conf::KEY_SA
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n} \f$
+ * \par Space complexity
+ * \f$ n( \log \sigma + \log \n ) \f$ bits
+ * \par Reference
+ * Juha Kärkkäinen, Giovanni Manzini, Simon J. Puglisi:
+ * Permuted Longest-Common-Prefix Array.
+ * CPM 2009: 181-192
+ */
+template<uint8_t t_width>
+void construct_lcp_PHI(cache_config& config)
+{
+ static_assert(t_width == 0 or t_width == 8 , "construct_lcp_PHI: width must be `0` for integer alphabet and `8` for byte alphabet");
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<t_width> text_type;
+ const char* KEY_TEXT = key_text_trait<t_width>::KEY_TEXT;
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config));
+ size_type n = sa_buf.size();
+
+ assert(n > 0);
+ if (1 == n) { // Handle special case: Input only the sentinel character.
+ int_vector<> lcp(1, 0);
+ store_to_cache(lcp, conf::KEY_LCP, config);
+ return;
+ }
+
+// (1) Calculate PHI (stored in array plcp)
+ int_vector<> plcp(n, 0, sa_buf.width());
+ for (size_type i=0, sai_1 = 0; i < n; ++i) {
+ size_type sai = sa_buf[i];
+ plcp[ sai ] = sai_1;
+ sai_1 = sai;
+ }
+
+// (2) Load text from disk
+ text_type text;
+ load_from_cache(text, KEY_TEXT, config);
+
+// (3) Calculate permuted LCP array (text order), called PLCP
+ size_type max_l = 0;
+ for (size_type i=0, l=0; i < n-1; ++i) {
+ size_type phii = plcp[i];
+ while (text[i+l] == text[phii+l]) {
+ ++l;
+ }
+ plcp[i] = l;
+ if (l) {
+ max_l = std::max(max_l, l);
+ --l;
+ }
+ }
+ util::clear(text);
+ uint8_t lcp_width = bits::hi(max_l)+1;
+
+// (4) Transform PLCP into LCP
+ std::string lcp_file = cache_file_name(conf::KEY_LCP, config);
+ size_type buffer_size = 1000000; // buffer_size is a multiple of 8!
+ int_vector_buffer<> lcp_buf(lcp_file, std::ios::out, buffer_size, lcp_width); // open buffer for lcp
+ lcp_buf[0] = 0;
+ sa_buf.buffersize(buffer_size);
+ for (size_type i=1; i < n; ++i) {
+ size_type sai = sa_buf[i];
+ lcp_buf[i] = plcp[sai];
+ }
+ lcp_buf.close();
+ register_cache_file(conf::KEY_LCP, config);
+}
+
+
+//! Construct the LCP array (only for byte strings)
+/*! The algorithm computes the lcp array and stores it to disk.
+ * \param config Reference to cache configuration
+ * \pre Text and Suffix array exist in the cache. Keys:
+ * * conf::KEY_TEXT
+ * * conf::KEY_SA
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n*q} \f$ implmented with \f$ q=64 \f$
+ * \par Space complexity
+ * \f$ n + \frac{n*\log{n}}{q} \f$ bytes, implmented with \f$ q=64 \f$
+ * \par Reference
+ * Juha Kärkkäinen, Giovanni Manzini, Simon J. Puglisi:
+ * Permuted Longest-Common-Prefix Array.
+ * CPM 2009: 181-192
+ */
+void construct_lcp_semi_extern_PHI(cache_config& config);
+
+
+//! Construct the LCP array (only for byte strings)
+/*! The algorithm computes the lcp array and stores it to disk.
+ * Our new 2 phases lcp algorithm
+ * \param config Reference to cache configuration
+ * \pre Text, Suffix array and BWT exist in the cache. Keys:
+ * * conf::KEY_TEXT
+ * * conf::KEY_SA
+ * * conf::KEY_BWT
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n^2} \f$, but usually faster than goPHI
+ * \par Space complexity
+ * Usually \f$ 2n \f$ bytes, worst case \f$5n bytes\f$
+ * \par Reference
+ * Simon Gog, Enno Ohlebusch:
+ * Fast and Lightweight LCP-Array Construction Algorithms.
+ * ALENEX 2011: 25-34
+ */
+void construct_lcp_go(cache_config& config);
+
+
+//! Construct the LCP array (only for byte strings)
+/*! The algorithm computes the lcp array and stores it to disk.
+ * Our new 2 phases lcp algorithm
+ * \param config Reference to cache configuration
+ * \pre Text, Suffix array and BWT exist in the cache. Keys:
+ * * conf::KEY_TEXT
+ * * conf::KEY_SA
+ * * conf::KEY_BWT
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n} \f$
+ * \par Space complexity
+ * Usually \f$ 2n \f$ bytes
+ * \par Reference
+ * Simon Gog, Enno Ohlebusch:
+ * Lightweight LCP-Array Construction in Linear Time.
+ * CoRR abs/1012.4263 (2010)
+ */
+void construct_lcp_goPHI(cache_config& config);
+
+
+//! Construct the LCP array out of the BWT (only for byte strings)
+/*! The algorithm computes the lcp array and stores it to disk. It needs only the Burrows and Wheeler transform.
+ * \param config Reference to cache configuration
+ * \pre BWT exist in the cache. Keys:
+ * * conf::KEY_BWT
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n \log{\sigma}} \f$
+ * \par Space complexity
+ * Usually not more than \f$ 2.5n \f$ bytes
+ * \par Reference
+ * Timo Beller, Simon Gog, Enno Ohlebusch, Thomas Schnattinger:
+ * Computing the Longest Common Prefix Array Based on the Burrows-Wheeler Transform.
+ * SPIRE 2011: 197-208
+ */
+void construct_lcp_bwt_based(cache_config& config);
+
+
+//! Construct the LCP array out of the BWT (only for byte strings)
+/*! The algorithm computes the lcp array and stores it to disk. It needs only the Burrows and Wheeler transform.
+ * \param config Reference to cache configuration
+ * \pre BWT exist in the cache. Keys:
+ * * conf::KEY_BWT
+ * \post LCP array exist in the cache. Key
+ * * conf::KEY_LCP
+ * \par Time complexity
+ * \f$ \Order{n \log{\sigma}} \f$
+ * \par Space complexity
+ * Usually not more than \f$ 1.5n \f$ bytes
+ * \par Reference
+ * Timo Beller, Simon Gog, Enno Ohlebusch, Thomas Schnattinger:
+ * Computing the longest common prefix array based on the Burrows-Wheeler transform.
+ * J. Discrete Algorithms 18: 22-31 (2013)
+ */
+void construct_lcp_bwt_based2(cache_config& config);
+
+}// end namespace
+
+#endif
diff --git a/include/sdsl/construct_lcp_helper.hpp b/include/sdsl/construct_lcp_helper.hpp
new file mode 100644
index 0000000..2fc2f9c
--- /dev/null
+++ b/include/sdsl/construct_lcp_helper.hpp
@@ -0,0 +1,89 @@
+#ifndef INCLUDED_SDSL_CONSTRUCT_LCP_HELPER
+#define INCLUDED_SDSL_CONSTRUCT_LCP_HELPER
+
+#include "sdsl/int_vector.hpp"
+#include <queue>
+#include <list>
+#include <vector>
+
+namespace sdsl
+{
+
+
+void insert_lcp_values(int_vector<>& partial_lcp, bit_vector& index_done, std::string lcp_file, uint64_t max_lcp_value, uint64_t lcp_value_offset);
+
+template<class tWT>
+void create_C_array(std::vector<uint64_t>& C, const tWT& wt)
+{
+ uint64_t quantity; // quantity of characters in interval
+ std::vector<unsigned char> cs(wt.sigma); // list of characters in the interval
+ std::vector<uint64_t> rank_c_i(wt.sigma); // number of occurrence of character in [0 .. i-1]
+ std::vector<uint64_t> rank_c_j(wt.sigma); // number of occurrence of character in [0 .. j-1]
+
+ C = std::vector<uint64_t>(257, 0);
+ interval_symbols(wt, 0, wt.size(), quantity, cs, rank_c_i, rank_c_j);
+ for (uint64_t i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ C[c+1] = rank_c_j[i];
+ }
+ for (uint64_t i=1; i<C.size()-1; ++i) {
+ C[i+1] += C[i];
+ }
+}
+
+
+class buffered_char_queue
+{
+ typedef bit_vector::size_type size_type;
+ typedef std::queue<uint8_t> tQ;
+ private:
+ static const uint32_t m_buffer_size = 10000;//409600;
+ uint8_t m_write_buf[m_buffer_size];
+ uint8_t m_read_buf[m_buffer_size];
+ size_type m_widx; // write index
+ size_type m_ridx; // read index
+ bool m_sync; // are read and write buffer the same?
+ size_type m_disk_buffered_blocks; // number of blocks written to disk and not read again yet
+ char m_c;
+ size_type m_rb; // read blocks
+ size_type m_wb; // written blocks
+
+ std::string m_file_name;
+
+ std::fstream m_stream;
+
+ public:
+
+ buffered_char_queue();
+ void init(const std::string& dir, char c);
+ ~buffered_char_queue();
+ void push_back(uint8_t x);
+ uint8_t pop_front();
+};
+
+typedef std::list<int_vector<>::size_type> tLI;
+typedef std::vector<int_vector<>::size_type> tVI;
+
+template<class size_type_class>
+void push_front_m_index(size_type_class i, uint8_t c, tLI(&m_list)[256], uint8_t (&m_chars)[256], size_type_class& m_char_count)
+{
+ if (m_list[c].empty()) {
+ m_chars[m_char_count++] = c;
+ }
+ m_list[c].push_front(i);
+}
+
+template<class size_type_class>
+void push_back_m_index(size_type_class i, uint8_t c, tLI(&m_list)[256], uint8_t (&m_chars)[256], size_type_class& m_char_count)
+{
+ if (m_list[c].empty()) {
+ m_chars[m_char_count++] = c;
+ }
+ m_list[c].push_back(i);
+}
+
+void lcp_info(tMSS& file_map);
+
+}
+
+#endif
diff --git a/include/sdsl/construct_sa.hpp b/include/sdsl/construct_sa.hpp
new file mode 100644
index 0000000..cacb862
--- /dev/null
+++ b/include/sdsl/construct_sa.hpp
@@ -0,0 +1,174 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file construct_sa.hpp
+ \brief construct_sa.hpp contains an interface to access suffix array construction algorithms
+ \author Simon Gog
+*/
+
+#ifndef INCLUDED_SDSL_CONSTRUCT_SA
+#define INCLUDED_SDSL_CONSTRUCT_SA
+
+#include "config.hpp"
+#include "int_vector.hpp"
+
+#include "divsufsort.h"
+#include "divsufsort64.h"
+
+#include "qsufsort.hpp"
+
+#include "construct_sa_se.hpp"
+#include "construct_config.hpp"
+
+namespace sdsl
+{
+
+//! Constructs the Suffix Array (SA) from text over byte-alphabet.
+/*! The algorithm constructs the SA and stores it to disk.
+ * \param config Reference to cache configuration
+ * \par Space complexity
+ * Usually less than \f$1.5n \f$ bytes of main memory and
+ * \f$10n \f$ bytes of secondary memory
+ * \pre Text exist in the cache. Keys:
+ * * conf::KEY_TEXT
+ * \post SA exist in the cache. Key
+ * * conf::KEY_SA
+ *
+ * This construction method uses less main memory, since data-structures
+ * are only kept in main memory, when random access to them is needed.
+ * Otherwise they are stored on disk. The disk-usage peak of this algorithm
+ * is about 10 times the input.
+ *
+ * \par References
+ * [1] T. Beller, M. Zwerger, S. Gog and E. Ohlebusch:
+ * ,,Space-Efficient Construction of the Burrows-Wheeler Transform'',
+ * Proceedings of SPIRE 2013.
+ *
+ */
+void construct_sa_se(cache_config& config);
+
+namespace algorithm
+{
+
+//
+// Forward declarations
+//----------------------------------------------------------
+
+//! Calculates the Suffix Array for a text.
+/*!
+ * \param c Text (c-string) to calculate the suffix array. The lex. order is given by the ascii-codes of the characters.
+ * \param len Length of the text. *(c+len)=0 and for i<len *(c+len)!=0
+ * \param sa Reference to a RandomAccessContainer which will contain the result of the calculation.
+ * \pre sa.size() has to be equal to len.
+ */
+template<uint8_t fixedIntWidth>
+void calculate_sa(const unsigned char* c, typename int_vector<fixedIntWidth>::size_type len, int_vector<fixedIntWidth>& sa)
+{
+ typedef typename int_vector<fixedIntWidth>::size_type size_type;
+ if (len <= 1) { // handle special case
+ sa = int_vector<fixedIntWidth>(len,0);
+ return;
+ }
+ bool small_file = (sizeof(len) <= 4 or len < 0x7FFFFFFFULL);
+ if (small_file) {
+ uint8_t oldIntWidth = sa.width();
+ if (32 == fixedIntWidth or(0==fixedIntWidth and 32 >= oldIntWidth)) {
+ sa.width(32);
+ sa.resize(len);
+ divsufsort(c, (int32_t*)sa.data(), len);
+ // copy integers back to the right positions
+ if (oldIntWidth!=32) {
+ for (size_type i=0; i<len; ++i) {
+ sa.set_int(i*oldIntWidth, sa.get_int(i<<5, 32), oldIntWidth);
+ }
+ sa.width(oldIntWidth);
+ sa.resize(len);
+ }
+ } else {
+ if (sa.width() < bits::hi(len)+1) {
+ throw std::logic_error("width of int_vector is to small for the text!!!");
+ }
+ int_vector<> sufarray(len,0,32);
+ divsufsort(c, (int32_t*)sufarray.data(), len);
+ for (size_type i=0; i<len; ++i) {
+ sa[i] = sufarray[i];
+ }
+ }
+ } else {
+ uint8_t oldIntWidth = sa.width();
+ sa.width(64);
+ sa.resize(len);
+ divsufsort64(c, (int64_t*)sa.data(), len);
+ // copy integers back to the right positions
+ if (oldIntWidth!=64) {
+ for (size_type i=0; i<len; ++i) {
+ sa.set_int(i*oldIntWidth, sa.get_int(i<<6, 64), oldIntWidth);
+ }
+ sa.width(oldIntWidth);
+ sa.resize(len);
+ }
+ }
+}
+
+
+} // end namespace algorithm
+
+//! Constructs the Suffix Array (SA) from text over byte- or integer-alphabet.
+/*! The algorithm constructs the SA and stores it to disk.
+ * \tparam t_width Width of the text. 0==integer alphabet, 8=byte alphabet.
+ * \param config Reference to cache configuration
+ * \par Space complexity
+ * \f$ 5n \f$ byte for t_width=8 and input < 2GB
+ * \f$ 9n \f$ byte for t_width=8 and input > 2GB
+ * \f$ n \log \sigma \f$ bits for t_width=0
+ * \pre Text exist in the cache. Keys:
+ * * conf::KEY_TEXT for t_width=8 or conf::KEY_TEXT_INT for t_width=0
+ * \post SA exist in the cache. Key
+ * * conf::KEY_SA
+ * \par Reference
+ * For t_width=8: DivSufSort (http://code.google.com/p/libdivsufsort/)
+ * For t_width=0: qsufsort (http://www.larsson.dogma.net/qsufsort.c)
+ */
+template<uint8_t t_width>
+void construct_sa(cache_config& config)
+{
+ static_assert(t_width == 0 or t_width == 8 , "construct_sa: width must be `0` for integer alphabet and `8` for byte alphabet");
+ const char* KEY_TEXT = key_text_trait<t_width>::KEY_TEXT;
+ if (t_width == 8) {
+ if (construct_config::byte_algo_sa == LIBDIVSUFSORT) {
+ typedef int_vector<t_width> text_type;
+ text_type text;
+ load_from_cache(text, KEY_TEXT, config);
+ // call divsufsort
+ int_vector<> sa(text.size(), 0, bits::hi(text.size())+1);
+ algorithm::calculate_sa((const unsigned char*)text.data(), text.size(), sa);
+ store_to_cache(sa, conf::KEY_SA, config);
+ } else if (construct_config::byte_algo_sa == SE_SAIS) {
+ construct_sa_se(config);
+ }
+ } else if (t_width == 0) {
+ // call qsufsort
+ int_vector<> sa;
+ sdsl::qsufsort::construct_sa(sa, cache_file_name(KEY_TEXT, config).c_str(), 0);
+ store_to_cache(sa, conf::KEY_SA, config);
+ } else {
+ std::cerr << "Unknown alphabet type" << std::endl;
+ }
+}
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/construct_sa_se.hpp b/include/sdsl/construct_sa_se.hpp
new file mode 100644
index 0000000..f42187a
--- /dev/null
+++ b/include/sdsl/construct_sa_se.hpp
@@ -0,0 +1,696 @@
+#ifndef SDSL_CONSTRUCT_SA_SE
+#define SDSL_CONSTRUCT_SA_SE
+
+#include "io.hpp"
+#include "int_vector.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <string>
+
+namespace sdsl
+{
+
+template<class int_vector_type>
+uint64_t _get_next_lms_position(int_vector_type& text, uint64_t i)
+{
+ if (i >= text.size()-3) {
+ return text.size()-1;
+ }
+ // text[i] is S-TYP or L-TYP
+ uint64_t ci=text[i], cip1=text[i+1];
+ while (ci <= cip1) {
+ ++i;
+ ci = cip1;
+ cip1 = text[i+1];
+ }
+ // text[i] is L-TYP or S-TYP
+ uint64_t candidate = i+1;
+ while (ci >= cip1) {
+ if (ci > cip1) {
+ if (i+1==text.size()-1) {
+ return text.size()-1;
+ }
+ candidate = i+1;
+ }
+ ++i;
+ ci = cip1;
+ cip1 = text[i+1];
+ }
+ return candidate;
+}
+
+void
+_construct_sa_IS(int_vector<> &text, int_vector<> &sa,
+ std::string& filename_sa, size_t n, size_t text_offset,
+ size_t sigma, uint64_t recursion);
+
+template <class int_vector_type >
+void _construct_sa_se(int_vector_type& text, std::string filename_sa, uint64_t sigma, uint64_t recursion)
+{
+ std::string filename_text = tmp_file(filename_sa, "_text_rec"+util::to_string(recursion));
+ store_to_file(text, filename_text);
+ uint64_t n = text.size();
+ uint64_t nsize = bits::hi(n)+1;
+ uint8_t int_width = bits::hi(n-1)+1;
+ uint64_t buffersize = 1024*1024/8;
+
+ // Step 1 - Scan Text from right to left and count LMS, S and L characters and store lms_positions
+
+ // Define variables
+ size_t first_lms_pos=0;
+ size_t number_of_lms_strings = 0;
+ size_t bkt_s_last = 0, bkt_s_sum=0, bound_s=0, bkt_l_sum=0;
+ int_vector<> C(sigma, 0, int_width);
+ int_vector<> bkt_lms(sigma, 0, int_width);
+ int_vector<> bkt_s(sigma, 0, int_width);
+ int_vector<> bkt_l(sigma, 0, int_width);
+ std::string filename_lms_pos_b = tmp_file(filename_sa, "_lms_pos_b"+util::to_string(recursion));
+ size_t parts = 10;
+
+ {
+ int_vector_buffer<1> lms_pos_b(filename_lms_pos_b, std::ios::out, buffersize, 1);
+ uint64_t ci = text[n-1];
+ ++C[ci];
+ bool was_s_typ = 1;
+ for (size_t i=n-2; i<n; --i) {
+ uint64_t cip1 = ci;
+ ci = text[i];
+ ++C[ci];
+ if (was_s_typ) {
+ ++bkt_s[text[i+1]];
+ if (ci>cip1) {
+ ++bkt_lms[cip1];
+ lms_pos_b[i+1] = 1;
+ ++number_of_lms_strings;
+ first_lms_pos = i+1;
+ was_s_typ = 0;
+ }
+ } else if (ci<cip1) {
+ was_s_typ = 1;
+ }
+ }
+ if (was_s_typ) {
+ ++bkt_s[ci];
+ }
+ bkt_l[0] = C[0]-bkt_s[0];
+ for (size_t i=1; i<C.size(); ++i) {
+ bkt_l[i] = C[i]-bkt_s[i];
+ C[i] = C[i]+C[i-1];
+ }
+ lms_pos_b.close();
+ }
+
+ // Step 2 - Scan Text from right to left and detect LMS-Positions. Sort and write them to disk
+ int_vector_buffer<> right(tmp_file(filename_sa, "_right"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ size_t right_pointer=0;
+ int_vector_buffer<> left(tmp_file(filename_sa, "_left"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ size_t left_pointer=0;
+ {
+ for (size_t i=0, tmp2=0, tmp=0; i<sigma; ++i) {
+ tmp += bkt_lms[i];
+ bkt_lms[i] = tmp2;
+ tmp2 = tmp;
+ }
+ int_vector_buffer<> lms_positions(tmp_file(filename_sa, "_lms_positions"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ for (size_t i=n-2, was_s_typ=1, ci=text[n-1]; i<n; --i) {
+ uint64_t cip1 = ci;
+ ci = text[i];
+ if (ci>cip1) {
+ if (was_s_typ) {
+ lms_positions.push_back(bkt_lms[cip1]);
+ lms_positions.push_back(i+1);
+ ++bkt_lms[cip1];
+ was_s_typ = 0;
+ }
+ } else if (ci<cip1) {
+ was_s_typ = 1;
+ }
+ }
+ util::clear(text);
+ {
+ // Order lms_positions according to first character
+ int_vector<> lms_strings(number_of_lms_strings, 0, int_width);
+ for (size_t i=0; i<lms_positions.size();) {
+ size_t idx = lms_positions[i++];
+ size_t val = lms_positions[i++];
+ lms_strings[idx] = val;
+ }
+ lms_positions.close(true);
+ // Store it to file
+ left_pointer = 0;
+ for (size_t i=0; i<number_of_lms_strings; ++i) {
+ left[left_pointer++] = lms_strings[number_of_lms_strings-i-1];
+ }
+ }
+ load_from_file(text, filename_text);
+ }
+ left_pointer--;
+
+ // Step 3 - Scan virtual array from left to right
+ {
+ // prepare bkt_l and backup it into bkt_lms
+ for (size_t i=0, tmp=0; i<sigma; ++i) {
+ tmp = bkt_l[i];
+ bkt_l[i] = bkt_l_sum;
+ bkt_l_sum += tmp;
+ bkt_lms[i] = bkt_l[i];
+ }
+
+ size_t partsize = bkt_l_sum/parts+1;
+
+ int_vector<> array(partsize, 0, int_width);
+ std::vector< int_vector_buffer<> > cached_array(parts-1);
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i] = int_vector_buffer<>(tmp_file(filename_sa, "_rightbuffer"+util::to_string(i)+"_"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ }
+
+ for (size_t c=0, pos=0, offset=0; c<sigma; ++c) {
+ // begin with array
+ for (; pos<bkt_l[c]; ++pos) {
+ // Load lazy values
+ if (pos-offset >= partsize) {
+ offset += partsize;
+ for (size_t i=0, cur_part=pos/partsize-1; i<cached_array[cur_part].size();) {
+ size_t src = cached_array[cur_part][i++];
+ size_t val = cached_array[cur_part][i++];
+ array[src-offset] = val;
+ }
+ cached_array[pos/partsize-1].reset();
+ }
+
+ size_t idx = array[pos-offset];
+ if (idx == 0) {
+ right[right_pointer++] = idx;
+ } else {
+ size_t symbol = text[idx-1];
+ if (symbol >= c) {
+ size_t val = idx-1;
+ size_t src = bkt_l[symbol];
+ bkt_l[symbol] = bkt_l[symbol] + 1;
+ if ((src-offset)/partsize == 0) {
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize-1;
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ } else {
+ right[right_pointer++] = idx;
+ }
+ }
+ }
+ // continue with stack
+ while (left_pointer < number_of_lms_strings and text[left[left_pointer]] == c) {
+ size_t idx = left[left_pointer--];
+ --idx;
+ size_t symbol = text[idx];
+
+ size_t val = idx;
+ size_t src = bkt_l[symbol];
+ bkt_l[symbol] = bkt_l[symbol] + 1;
+ if ((src-offset)/partsize == 0) {
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize-1;
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ }
+ }
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i].close(true);
+ }
+
+ // Restore bkt_l from bkt_lms
+ for (size_t i=0; i<sigma; ++i) {
+ bkt_l[i] = bkt_lms[i];
+ }
+ }
+ right_pointer--;
+
+ // Step 4 - Scan virtual array from right to left
+ left_pointer = 0;
+ left.reset();
+ {
+ // Prepare bkt_s and backup it into bkt_lms
+ bkt_s_last=0, bkt_s_sum=0;
+ for (size_t i=0; i<sigma; ++i) {
+ bkt_s_sum += bkt_s[i];
+ if (bkt_s[i]) {
+ bkt_s[i] = bkt_s_sum;
+ bkt_s_last = bkt_s_sum;
+ } else {
+ bkt_s[i] = bkt_s_sum;
+ }
+ bkt_lms[i] = bkt_s[i];
+ }
+ bound_s = bkt_s_sum;
+
+ // Determine splitting parameters
+ for (size_t i=0; i<sigma; ++i) {
+ if (bkt_s[i] > bkt_s_sum/2) {
+ bkt_s_sum = bkt_s[i];
+ break;
+ }
+ }
+
+ size_t partsize = bound_s/parts+1;
+ int_vector<> array(partsize, 0, int_width);
+ std::vector< int_vector_buffer<> > cached_array(parts-1);
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i] = int_vector_buffer<>(tmp_file(filename_sa, "_leftbuffer"+util::to_string(i)+"_"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ }
+ for (size_t c=sigma-1, pos=bkt_s_last-1, offset=partsize*(parts-1); c<sigma; --c) {
+ // begin with array
+ for (; pos+1 > bkt_s[c]; --pos) {
+ while (pos < offset) {
+ // Load buffered values
+ offset -= partsize;
+ for (size_t i=0, cur_part=offset/partsize; i<cached_array[cur_part].size();) {
+ size_t src = cached_array[cur_part][i++];
+ size_t val = cached_array[cur_part][i++];
+ array[src-offset] = val;
+ }
+ cached_array[offset/partsize].reset();
+ }
+
+ size_t idx = array[pos-offset];
+ if (idx==0) {
+ idx = n;
+ }
+ --idx;
+ size_t symbol = text[idx];
+ if (symbol <= c) {
+ bkt_s[symbol] = bkt_s[symbol] - 1;
+ size_t val = idx;
+ size_t src = bkt_s[symbol];
+ if (src >= offset) {
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize;
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ } else {
+ left[left_pointer++] = array[pos-offset];
+ }
+ }
+
+ // continue with stack
+ while (right_pointer < number_of_lms_strings and text[right[right_pointer]] == c) {
+ size_t idx = right[right_pointer--];
+ if (idx == 0) {
+ idx = n;
+ }
+ --idx;
+ size_t symbol = text[idx];
+ bkt_s[symbol] = bkt_s[symbol] - 1;
+
+ size_t val = idx;
+ size_t src = bkt_s[symbol];
+ if (src >= offset) {
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize;
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ }
+ }
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i].close(true);
+ }
+ // Restore bkt_s from bkt_lms
+ for (size_t i=0; i<sigma; ++i) {
+ bkt_s[i] = bkt_lms[i];
+ }
+ }
+ right.buffersize(0);
+ right.reset();
+ right_pointer = 0;
+ --left_pointer;
+
+ // Step 5 - Detect same lms-Strings, write text to file
+ int_vector<1> same_lms(number_of_lms_strings, false);
+ size_t last_end_pos = first_lms_pos, order = number_of_lms_strings-1;
+ same_lms[number_of_lms_strings-1] = true;
+ for (size_t i=number_of_lms_strings-2, a=0, b=0, last_a=left[number_of_lms_strings-1]; i<number_of_lms_strings; --i) {
+ b = last_a;
+ a = left[i];
+ last_a = a;
+
+ size_t end_pos = _get_next_lms_position(text, a);
+ if (end_pos-a == last_end_pos-b) {
+ while (a < end_pos and text[a] == text[b]) {
+ ++a;
+ ++b;
+ }
+ if (text[a] == text[b]) {
+ same_lms[i] = true;
+ --order;
+ }
+ }
+ last_end_pos = end_pos;
+ }
+ util::clear(text);
+
+ // Step 7 - Create renamed string
+ int_vector<> text_rec;
+ if (recursion==0) {
+ text_rec.width((bits::hi(order+1)+1));
+ } else {
+ text_rec.width((bits::hi(number_of_lms_strings+1)+1));
+ }
+ text_rec.resize(number_of_lms_strings);
+ util::_set_zero_bits(text_rec);
+ {
+ if (recursion==0 and n/2*text_rec.width()>8*n) {
+ size_t size_of_part = n/4+3;
+ text_rec.resize(size_of_part);
+ util::_set_zero_bits(text_rec);
+ order = 0;
+ for (size_t i=number_of_lms_strings-1; i<number_of_lms_strings; --i) {
+ if (!same_lms[i]) {
+ ++order;
+ }
+ if (left[i]/2 >= size_of_part) {
+ text_rec[(left[i]/2)-size_of_part] = order;
+ }
+ }
+ std::string filename_text_rec_part2 = tmp_file(filename_sa, "_text_rec_part2"+util::to_string(recursion));
+ size_t pos = 0;
+ for (size_t i=0; i<size_of_part; ++i) {
+ if (text_rec[i]>0) {
+ text_rec[pos++] = text_rec[i];
+ }
+ }
+ text_rec.resize(pos);
+ store_to_file(text_rec, filename_text_rec_part2);
+ text_rec.resize(size_of_part);
+ util::_set_zero_bits(text_rec);
+ order = 0;
+ for (size_t i=number_of_lms_strings-1; i<number_of_lms_strings; --i) {
+ if (!same_lms[i]) {
+ ++order;
+ }
+ if (left[i]/2 < size_of_part) {
+ text_rec[left[i]/2] = order;
+ }
+ }
+ pos = 0;
+ for (size_t i=0; i<size_of_part; ++i) {
+ if (text_rec[i]>0) {
+ text_rec[pos++] = text_rec[i];
+ }
+ }
+ text_rec.resize(number_of_lms_strings);
+ int_vector_buffer<> buf(filename_text_rec_part2, std::ios::in, 1024*1024);
+ for (size_t i=0; i<buf.size(); ++i) {
+ text_rec[pos++] = buf[i];
+ }
+ buf.close(true);
+ text_rec[number_of_lms_strings-1] = 0;
+ } else {
+ text_rec.resize(n/2+1);
+ util::_set_zero_bits(text_rec);
+ order = 0;
+ for (size_t i=number_of_lms_strings-1; i<number_of_lms_strings; --i) {
+ if (!same_lms[i]) {
+ ++order;
+ }
+ text_rec[left[left_pointer--]/2] = order;
+ }
+ for (size_t i=0, pos=0; i<text_rec.size(); ++i) {
+ if (text_rec[i]>0) {
+ text_rec[pos++] = text_rec[i];
+ }
+ }
+ text_rec[number_of_lms_strings-1] = 0;
+ text_rec.resize(number_of_lms_strings);
+ }
+ }
+ util::clear(same_lms);
+ left.buffersize(0);
+ left.reset();
+
+ // Step 8 - Determine complete LMS order (recursivly)
+ int_vector<> isa_rec;
+ std::string filename_sa_rec = tmp_file(filename_sa, "_sa_rec"+util::to_string(recursion+1));
+ if (text_rec.size() > order+1) {
+ if (recursion==0) {
+ memory_monitor::event("begin _construct_sa");
+ _construct_sa_se<int_vector<> >(text_rec, filename_sa_rec, order+1, recursion+1);
+ memory_monitor::event("end _construct_sa");
+ } else {
+ text_rec.resize(text_rec.size()*2);
+ for (size_t i=0; i<number_of_lms_strings; ++i) {
+ text_rec[number_of_lms_strings+i] = text_rec[i];
+ text_rec[i] = 0;
+ }
+ memory_monitor::event("begin sa_simple");
+ _construct_sa_IS(text_rec, text_rec, filename_sa_rec, number_of_lms_strings, number_of_lms_strings, order+1, recursion+1);
+ memory_monitor::event("end sa_simple");
+ // SA' in first half, S' in second half
+ text_rec.resize(number_of_lms_strings);
+ store_to_file(text_rec, filename_sa_rec);
+ }
+ } else {
+ isa_rec.swap(text_rec);
+ }
+ util::clear(text_rec);
+
+ // Step 9 - Initiate left for scan in step 12
+ if (isa_rec.size() > 0) {
+ // isa_rec exists //TODO test if its better to create sa_rec
+ // TODO always enough memory? in memory: isa_rec, lms_pos_b, select_support, tmp_left, leftbuffer
+ // load bit_vector lms_positions and create select support
+ bit_vector lms_pos_b(n);
+ load_from_file(lms_pos_b, filename_lms_pos_b);
+ sdsl::remove(filename_lms_pos_b);
+ select_support_mcl<> lms_select_support; // select_support for bit_vector
+ util::init_support(lms_select_support, &lms_pos_b); // Create select_support
+ // write left
+ int_vector<> tmp_left(number_of_lms_strings, 0, int_width);
+ for (size_t i=number_of_lms_strings-1; i<number_of_lms_strings; --i) {
+ size_t idx = isa_rec[i];
+ size_t val = lms_select_support.select(i+1); //TODO test alternative without select support: look for 1 in lms_pos_b (backwards)
+ tmp_left[idx] = val;
+ }
+ util::clear(lms_select_support);
+ util::clear(lms_pos_b);
+ util::clear(isa_rec);
+ // write to left
+ left.buffersize(buffersize);
+ left_pointer = 0;
+ for (; left_pointer<number_of_lms_strings; ++left_pointer) {
+ left[left_pointer] = tmp_left[number_of_lms_strings-left_pointer-1];
+ }
+ left_pointer--;
+ util::clear(tmp_left);
+ } else {
+ left.buffersize(buffersize);
+ left_pointer = 0;
+ {
+ // load bit_vector lms_positions and create select support
+ bit_vector lms_pos_b(n);
+ load_from_file(lms_pos_b, filename_lms_pos_b);
+ sdsl::remove(filename_lms_pos_b);
+ select_support_mcl<> lms_select_support; // select_support for bit_vector
+ util::init_support(lms_select_support, &lms_pos_b); // create select_support
+ // write to left sa_rec buffered
+ int_vector_buffer<> sa_rec_buf(filename_sa_rec, std::ios::in, buffersize, nsize);
+ for (uint64_t i=0; i<sa_rec_buf.size(); ++i) {
+ uint64_t pos = lms_select_support.select(sa_rec_buf[i]+1);
+ left[number_of_lms_strings-1-left_pointer++] = pos;
+ }
+ sa_rec_buf.close(true);
+ left_pointer--;
+ }
+ //TODO test sa_rec unbuffered in recursion level 1 -> space still good?
+ }
+
+
+ // Step 10 - Reload text
+ load_from_file(text, filename_text);
+ sdsl::remove(filename_text);
+
+ // Step 12 - Scan virtual array from left to right second time
+ right.buffersize(buffersize);
+ right_pointer = 0;
+ int_vector_buffer<> cached_sa(filename_sa, std::ios::out, buffersize, nsize);
+ size_t sa_pointer = 0;
+ {
+ size_t partsize = bkt_l_sum/parts+1;
+ int_vector<> array(partsize, 0, int_width);
+ std::vector< int_vector_buffer<> > cached_array(parts-1);
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i] = int_vector_buffer<>(tmp_file(filename_sa, "_rightbuffer"+util::to_string(i)+"_"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ }
+
+ for (size_t c=0, pos=0, offset=0; c<sigma; ++c) {
+ // begin with array
+ for (; pos<bkt_l[c]; ++pos) {
+ // Load lazy values
+ if (pos-offset >= partsize) {
+ offset += partsize;
+ for (size_t i=0, cur_part=pos/partsize-1; i<cached_array[cur_part].size();) {
+ size_t src = cached_array[cur_part][i++];
+ size_t val = cached_array[cur_part][i++];
+ array[src-offset] = val;
+ }
+ cached_array[pos/partsize-1].reset();
+ }
+ size_t idx = array[pos-offset];
+ if (idx == 0) {
+ cached_sa[sa_pointer++] = idx;
+ right[right_pointer++] = idx;
+ } else {
+ size_t symbol = text[idx-1];
+ cached_sa[sa_pointer++] = idx;
+ if (symbol >= c) {
+ size_t val = idx-1;
+ size_t src = bkt_l[symbol];
+ bkt_l[symbol] = bkt_l[symbol] + 1;
+ if ((src-offset)/partsize == 0) {
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize-1;
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ } else {
+ right[right_pointer++] = idx;
+ }
+ }
+ }
+ sa_pointer = C[c];
+ // continue with stack
+ while (left_pointer < number_of_lms_strings and text[left[left_pointer]] == c) {
+ size_t idx = left[left_pointer--];
+ if (idx == 0) {
+ idx = n;
+ }
+ --idx;
+ size_t symbol = text[idx];
+ size_t val = idx;
+ size_t src = bkt_l[symbol];
+ bkt_l[symbol] = bkt_l[symbol] + 1;
+ if ((src-offset)/partsize == 0) {
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize-1;
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ }
+ }
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i].close(true);
+ }
+ }
+ left.close(true);
+ right_pointer--;
+
+ // Step 13 - Scan virtual array from right to left second time
+ {
+ size_t partsize = bound_s/parts+1;
+
+ int_vector<> array(partsize, 0, int_width);
+ std::vector< int_vector_buffer<> > cached_array(parts-1);
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i] = int_vector_buffer<>(tmp_file(filename_sa, "_leftbuffer"+util::to_string(i)+"_"+util::to_string(recursion)), std::ios::out, buffersize, nsize);
+ // cached_array_pointer[i] = 0;
+ }
+ for (size_t c=sigma-1, pos=bkt_s_last-1, offset=partsize*(parts-1); c<sigma; --c) {
+ // begin with array
+ assert(c < C.size());
+ sa_pointer = C[c]-1;
+ for (; pos+1 > bkt_s[c]; --pos) {
+ while (pos < offset) {
+ // Load buffered values
+ offset -= partsize;
+ for (size_t i=0, cur_part=offset/partsize; i<cached_array[cur_part].size();) {
+ size_t src = cached_array[cur_part][i++];
+ size_t val = cached_array[cur_part][i++];
+ assert((src-offset) < array.size());
+ array[src-offset] = val;
+ }
+ assert((offset/partsize) < parts-1);
+ cached_array[offset/partsize].reset();
+ }
+
+ assert((pos-offset) < array.size());
+ size_t idx = array[pos-offset];
+ if (idx==0) {
+ idx = n;
+ }
+ --idx;
+ assert((idx) < text.size());
+ size_t symbol = text[idx];
+ if (symbol <= c) {
+ if (idx==n-1) {
+ cached_sa[sa_pointer--] = 0;
+ } else {
+ cached_sa[sa_pointer--] = idx+1;
+ }
+ assert((symbol) < bkt_s.size());
+ bkt_s[symbol] = bkt_s[symbol] - 1;
+ size_t val = idx;
+ size_t src = bkt_s[symbol];
+ if (src >= offset) {
+ assert((src-offset) < array.size());
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize;
+ assert(part < parts-1);
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ } else {
+ if (idx==n-1) {
+ cached_sa[sa_pointer--] = 0;
+ } else {
+ cached_sa[sa_pointer--] = idx+1;
+ }
+ }
+ }
+ // continue with stack
+ while (right_pointer < number_of_lms_strings and text[right[right_pointer]] == c) {
+ size_t idx = right[right_pointer--];
+ if (idx == 0) {
+ idx = n;
+ }
+ --idx;
+ size_t symbol = text[idx];
+ assert((symbol) < bkt_s.size());
+ bkt_s[symbol] = bkt_s[symbol] - 1;
+
+ size_t val = idx;
+ size_t src = bkt_s[symbol];
+ if (src >= offset) {
+ assert((src-offset) < array.size());
+ array[src-offset] = val;
+ } else {
+ size_t part = src/partsize;
+ assert((part) < parts-1);
+ cached_array[part].push_back(src);
+ cached_array[part].push_back(val);
+ }
+ }
+ }
+ for (size_t i=0; i<cached_array.size(); ++i) {
+ cached_array[i].close(true);
+ }
+ }
+ right.close(true);
+ cached_sa.close();
+
+ return;
+}
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/csa_alphabet_strategy.hpp b/include/sdsl/csa_alphabet_strategy.hpp
new file mode 100644
index 0000000..ec49cc8
--- /dev/null
+++ b/include/sdsl/csa_alphabet_strategy.hpp
@@ -0,0 +1,563 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file csa_alphabet_strategy.hpp
+ \brief csa_alphabet_strategy.hpp includes different strategy classes for representing an alphabet of a CSA.
+ \author Simon Gog
+*/
+
+#ifndef INCLUDED_CSA_ALPHABET_STRATEGY
+#define INCLUDED_CSA_ALPHABET_STRATEGY
+
+
+// TODO: Strategy with 1-to-1 mapping and C_array type as template parameter
+// This can be also used for a integer based CSA.
+
+/* A alphabet strategy provides the following features:
+ * * Member `sigma` which contains the size (=umber of unique symbols) of the alphabet.
+ * * Method `is_present(char_type c)` which indicates if character c occurs in the text.
+ * * Container `char2comp` which maps a symbol to a number [0..sigma-1]. The alphabetic
+ * order is preserved.
+ * * Container `comp2char` which is the inverse mapping of char2comp.
+ * * Container `C` contains the cumulative counts of occurrences. C[i] is the cumulative
+ * count of occurrences of symbols `comp2char[0]` to `comp2char[i-1]` in the text.
+ * * Typedefs for the four above members:
+ * * char2comp_type
+ * * comp2char_type
+ * * C_type
+ * * sigma_type
+ * * Constructor. Takes a int_vector_buffer<8> for byte-alphabets
+ * and int_vector_buffer<0> for integer-alphabets.
+ *
+ * \par Note
+ * sigma_type has to be large enough to represent the alphabet size 2*sigma,
+ * since there is code which will perform a binary search on array `C`.
+ */
+
+#include "int_vector.hpp"
+#include "sd_vector.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "sdsl_concepts.hpp"
+#include "config.hpp"
+#include <string>
+
+namespace sdsl
+{
+
+// forward declarations
+
+class byte_alphabet;
+
+template<class bit_vector_type = bit_vector,
+ class rank_support_type = rank_support_scan<>, //typename bit_vector_type::rank_1_type,
+ class select_support_type = select_support_scan<>, //typename bit_vector_type::select_1_type,
+ class C_array_type = int_vector<>
+ >
+class succinct_byte_alphabet;
+
+template<class bit_vector_type = sd_vector<>,
+ class rank_support_type = typename bit_vector_type::rank_1_type,
+ class select_support_type = typename bit_vector_type::select_1_type,
+ class C_array_type = int_vector<>
+ >
+class int_alphabet;
+
+template <uint8_t int_width>
+struct key_trait {
+ static const char* KEY_BWT;
+ static const char* KEY_TEXT;
+};
+
+template<>
+struct key_trait<8> {
+ static const char* KEY_BWT;
+ static const char* KEY_TEXT;
+};
+
+template<uint8_t int_width>
+const char* key_trait<int_width>::KEY_BWT = conf::KEY_BWT_INT;
+
+template<uint8_t int_width>
+const char* key_trait<int_width>::KEY_TEXT = conf::KEY_TEXT_INT;
+
+template<class t_alphabet_strategy>
+struct alphabet_trait {
+ typedef byte_alphabet type;
+};
+
+template<>
+struct alphabet_trait<int_alphabet_tag> {
+ typedef int_alphabet<> type;
+};
+
+//! A simple space greedy representation for byte alphabets.
+/*!
+ * \par Space consumption:
+ * At least: 2.5 kB
+ * Details: char2comp + comp2char take 2*256 + 2*8 bytes
+ * m_C takes 257*8 bytes
+ * m_sigma takes 2 bytes
+ */
+class byte_alphabet
+{
+ public:
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<8> char2comp_type;
+ typedef int_vector<8> comp2char_type;
+ typedef int_vector<64> C_type;
+ typedef uint16_t sigma_type;
+ typedef uint8_t char_type;
+ typedef uint8_t comp_char_type;
+ typedef std::string string_type;
+ enum { int_width = 8 };
+
+ typedef byte_alphabet_tag alphabet_category;
+ private:
+ char2comp_type m_char2comp; // Mapping from a character into the compact alphabet.
+ comp2char_type m_comp2char; // Inverse mapping of m_char2comp.
+ C_type m_C; // Cumulative counts for the compact alphabet [0..sigma].
+ sigma_type m_sigma; // Effective size of the alphabet.
+
+ void copy(const byte_alphabet&);
+ public:
+
+ const char2comp_type& char2comp;
+ const comp2char_type& comp2char;
+ const C_type& C;
+ const sigma_type& sigma;
+
+ //! Default constructor
+ byte_alphabet();
+
+ //! Construct from a byte-stream
+ /*!
+ * \param text_buf Byte stream.
+ * \param len Length of the byte stream.
+ */
+ byte_alphabet(int_vector_buffer<8>& text_buf, int_vector_size_type len);
+
+ byte_alphabet(const byte_alphabet&);
+ byte_alphabet(byte_alphabet&& b) : byte_alphabet() {
+ *this = std::move(b);
+ }
+
+ byte_alphabet& operator=(const byte_alphabet&);
+ byte_alphabet& operator=(byte_alphabet&&);
+
+ void swap(byte_alphabet&);
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ void load(std::istream& in);
+};
+
+
+//! A space-efficient representation for byte alphabets.
+/*!
+ * The mapping `char2comp` and its inverse `comp2char` is realized internally
+ * by a bitvector of size 256 bits and a rank and a select structure. The rank
+ * structure is used to calculate `char2comp`; the select structure is used to
+ * calculate `comp2char`. Array `C` is represented by a bit-compressed
+ * `int_vector` and `sigma` by a uint16_t.
+ * The types to represent `char2comp`, `comp2char`, and `C` can be specified
+ * by template parameters.
+ */
+template<class bit_vector_type, class rank_support_type, class select_support_type, class C_array_type>
+class succinct_byte_alphabet
+{
+ public:
+ class char2comp_wrapper;
+ class comp2char_wrapper;
+ friend class char2comp_wrapper;
+ friend class comp2char_wrapper;
+
+ typedef int_vector<>::size_type size_type;
+ typedef char2comp_wrapper char2comp_type;
+ typedef comp2char_wrapper comp2char_type;
+ typedef C_array_type C_type;
+ typedef uint16_t sigma_type;
+ typedef uint8_t char_type;
+ typedef uint8_t comp_char_type;
+ typedef std::string string_type;
+ typedef byte_alphabet_tag alphabet_category;
+ enum { int_width = 8 };
+
+ //! Helper class for the char2comp mapping
+ class char2comp_wrapper
+ {
+ private:
+ const succinct_byte_alphabet* m_strat;
+ public:
+ char2comp_wrapper(const succinct_byte_alphabet* strat) : m_strat(strat) {}
+ comp_char_type operator[](char_type c) const {
+ return (comp_char_type) m_strat->m_char_rank((size_type)c);
+ }
+ };
+
+ //! Helper class for the comp2char mapping
+ class comp2char_wrapper
+ {
+ private:
+ const succinct_byte_alphabet* m_strat;
+ public:
+ comp2char_wrapper(const succinct_byte_alphabet* strat) : m_strat(strat) {}
+ char_type operator[](comp_char_type c) const {
+ return (char_type) m_strat->m_char_select(((size_type)c)+1);
+ }
+ };
+
+ private:
+ bit_vector_type m_char; // `m_char[i]` indicates if character with code i is present or not
+ rank_support_type m_char_rank; // rank data structure for `m_char` to answer char2comp
+ select_support_type m_char_select; // select data structure for `m_char` to answer comp2char
+ C_type m_C; // cumulative counts for the compact alphabet [0..sigma]
+ sigma_type m_sigma; // effective size of the alphabet
+
+ void copy(const succinct_byte_alphabet& strat) {
+ m_char = strat.m_char;
+ m_char_rank = strat.m_char_rank;
+ m_char_rank.set_vector(&m_char);
+ m_char_select = strat.m_char_select;
+ m_char_select.set_vector(&m_char);
+ m_C = strat.m_C;
+ m_sigma = strat.m_sigma;
+ }
+ public:
+
+ const char2comp_type char2comp;
+ const comp2char_type comp2char;
+ const C_type& C;
+ const sigma_type& sigma;
+
+ //! Default constructor
+ succinct_byte_alphabet() : char2comp(this), comp2char(this), C(m_C), sigma(m_sigma) {
+ m_sigma = 0;
+ }
+
+ //! Construct from a byte-stream
+ /*!
+ * \param text_buf Byte stream.
+ * \param len Length of the byte stream.
+ */
+ succinct_byte_alphabet(int_vector_buffer<8>& text_buf, int_vector_size_type len):
+ char2comp(this), comp2char(this), C(m_C), sigma(m_sigma) {
+ m_sigma = 0;
+ if (0 == len or 0 == text_buf.size())
+ return;
+ assert(len <= text_buf.size());
+ // initialize vectors
+ int_vector<64> D(257, 0);
+ bit_vector tmp_char(256, 0);
+ // count occurrences of each symbol
+ for (size_type i=0; i < len; ++i) {
+ ++D[text_buf[i]];
+ }
+ assert(1 == D[0]); // null-byte should occur exactly once
+ m_sigma = 0;
+ for (int i=0; i<256; ++i)
+ if (D[i]) {
+ tmp_char[i] = 1; // mark occurring character
+ D[m_sigma] = D[i]; // compactify m_C
+ ++m_sigma;
+ }
+ // resize to sigma+1, since CSAs also need the sum of all elements
+ m_C = C_type(m_sigma+1, 0, bits::hi(len)+1);
+
+ for (int i=(int)m_sigma; i > 0; --i) m_C[i] = D[i-1];
+ m_C[0] = 0;
+ for (int i=1; i <= (int)m_sigma; ++i) m_C[i] = m_C[i] + m_C[i-1];
+ assert(m_C[sigma]==len);
+ m_char = tmp_char;
+ util::init_support(m_char_rank, &m_char);
+ util::init_support(m_char_select, &m_char);
+ }
+
+ //! Copy constructor
+ succinct_byte_alphabet(const succinct_byte_alphabet& strat): char2comp(this), comp2char(this), C(m_C), sigma(m_sigma) {
+ copy(strat);
+ }
+
+ //! Move constructor
+ succinct_byte_alphabet(succinct_byte_alphabet&& strat) {
+ *this = std::move(strat);
+ }
+
+ succinct_byte_alphabet& operator=(const succinct_byte_alphabet& strat) {
+ if (this != &strat) {
+ copy(strat);
+ }
+ return *this;
+ }
+
+ succinct_byte_alphabet& operator=(succinct_byte_alphabet&& strat) {
+ if (this != &strat) {
+ m_char = std::move(strat.m_char);
+ m_char_rank = std::move(strat.m_char_rank);
+ m_char_rank.set_vector(&m_char);
+ m_char_select = std::move(strat.m_char_select);
+ m_char_select.set_vector(&m_char);
+ m_C = std::move(strat.m_C);
+ m_sigma = std::move(strat.m_sigma);
+ }
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(succinct_byte_alphabet& strat) {
+ m_char.swap(strat.m_char);
+ util::swap_support(m_char_rank, strat.m_char_rank, &m_char, &(strat.m_char));
+ util::swap_support(m_char_select, strat.m_char_select, &m_char, &(strat.m_char));
+ m_C.swap(strat.m_C);
+ std::swap(m_sigma,strat.m_sigma);
+ }
+
+ //! Serialize method
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_char.serialize(out, child, "m_char");
+ written_bytes += m_char_rank.serialize(out, child, "m_char_rank");
+ written_bytes += m_char_select.serialize(out, child, "m_char_select");
+ written_bytes += m_C.serialize(out, child, "m_C");
+ written_bytes += write_member(m_sigma, out, child, "m_sigma");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load method
+ void load(std::istream& in) {
+ m_char.load(in);
+ m_char_rank.load(in);
+ m_char_rank.set_vector(&m_char);
+ m_char_select.load(in);
+ m_char_select.set_vector(&m_char);
+ m_C.load(in);
+ read_member(m_sigma, in);
+ }
+};
+
+//! A space-efficient representation for byte alphabets.
+/*!
+ * The mapping `char2comp` and its inverse `comp2char` is realized internally
+ * by a bitvector of size sigma bits and a rank and a select structure, if the
+ * alphabet contains not all symbols in the range [0..sigma-1]. If it contains
+ * all symbols, i.e. the alphabet is continuous, then we map the symbols
+ * directly and no extra space is used.
+ *
+ * The types to represent `char2comp`, `comp2char`, and `C` can be specified
+ * by template parameters.
+ */
+template<class bit_vector_type, class rank_support_type, class select_support_type, class C_array_type>
+class int_alphabet
+{
+ public:
+ class char2comp_wrapper;
+ class comp2char_wrapper;
+ friend class char2comp_wrapper;
+ friend class comp2char_wrapper;
+
+ typedef int_vector<>::size_type size_type;
+ typedef char2comp_wrapper char2comp_type;
+ typedef comp2char_wrapper comp2char_type;
+ typedef C_array_type C_type;
+ typedef uint64_t sigma_type;
+ typedef uint64_t char_type;
+ typedef uint64_t comp_char_type;
+ typedef std::vector<char_type> string_type;
+ typedef int_alphabet_tag alphabet_category;
+ enum { int_width = 0 };
+
+ //! Helper class for the char2comp mapping
+ class char2comp_wrapper
+ {
+ private:
+ const int_alphabet* m_strat;
+ public:
+ char2comp_wrapper(const int_alphabet* strat) : m_strat(strat) {}
+ comp_char_type operator[](char_type c) const {
+ if (m_strat->m_char.size() > 0) { // if alphabet is not continuous
+ return (comp_char_type) m_strat->m_char_rank((size_type)c);
+ } else { // direct map if it is continuous
+ return (comp_char_type) c;
+ }
+ }
+ };
+
+ //! Helper class for the comp2char mapping
+ class comp2char_wrapper
+ {
+ private:
+ const int_alphabet* m_strat;
+ public:
+ comp2char_wrapper(const int_alphabet* strat) : m_strat(strat) {}
+ char_type operator[](comp_char_type c) const {
+ if (m_strat->m_char.size() > 0) { // if alphabet is not continuous
+ return (char_type) m_strat->m_char_select(((size_type)c)+1);
+ } else { // direct map if it is continuous
+ return (char_type) c;
+ }
+ }
+ };
+
+ private:
+ bit_vector_type m_char; // `m_char[i]` indicates if character with code i is present or not
+ rank_support_type m_char_rank; // rank data structure for `m_char` to answer char2comp
+ select_support_type m_char_select; // select data structure for `m_char` to answer comp2char
+ C_type m_C; // cumulative counts for the compact alphabet [0..sigma]
+ sigma_type m_sigma; // effective size of the alphabet
+
+ void copy(const int_alphabet& strat) {
+ m_char = strat.m_char;
+ m_char_rank = strat.m_char_rank;
+ m_char_rank.set_vector(&m_char);
+ m_char_select = strat.m_char_select;
+ m_char_select.set_vector(&m_char);
+ m_C = strat.m_C;
+ m_sigma = strat.m_sigma;
+ }
+
+ //! Check if the alphabet is continuous.
+ bool is_continuous_alphabet(std::map<size_type, size_type>& D) {
+ if (D.size() == 0) { // an empty alphabet is continuous
+ return true;
+ } else {
+ // max key + 1 == size of map
+ return ((--D.end())->first + 1) == D.size();
+ }
+ }
+ public:
+
+ const char2comp_type char2comp;
+ const comp2char_type comp2char;
+ const C_type& C;
+ const sigma_type& sigma;
+
+ //! Default constructor
+ int_alphabet() : char2comp(this), comp2char(this), C(m_C), sigma(m_sigma) {
+ m_sigma = 0;
+ }
+
+ //! Construct from a byte-stream
+ /*!
+ * \param text_buf Byte stream.
+ * \param len Length of the byte stream.
+ */
+ int_alphabet(int_vector_buffer<0>& text_buf, int_vector_size_type len):
+ char2comp(this), comp2char(this), C(m_C), sigma(m_sigma) {
+ m_sigma = 0;
+ if (0 == len or 0 == text_buf.size())
+ return;
+ assert(len <= text_buf.size());
+ // initialize vectors
+ std::map<size_type, size_type> D;
+ // count occurrences of each symbol
+ for (size_type i=0; i < len; ++i) {
+ D[text_buf[i]]++;
+ }
+ m_sigma = D.size();
+ if (is_continuous_alphabet(D)) {
+ // do not initialize m_char, m_char_rank and m_char_select since we can map directly
+ } else {
+ // note: the alphabet has at least size 1, so the following is safe:
+ size_type largest_symbol = (--D.end())->first;
+ bit_vector tmp_char(largest_symbol+1, 0);
+ for (std::map<size_type, size_type>::const_iterator it = D.begin(), end=D.end(); it != end; ++it) {
+ tmp_char[it->first] = 1;
+ }
+ m_char = tmp_char;
+ util::init_support(m_char_rank, &m_char);
+ util::init_support(m_char_select, &m_char);
+ }
+ assert(D.find(0) != D.end() and 1 == D[0]); // null-byte should occur exactly once
+
+ // resize to sigma+1, since CSAs also need the sum of all elements
+ m_C = C_type(m_sigma+1, 0, bits::hi(len)+1);
+ size_type sum = 0, idx=0;
+ for (std::map<size_type, size_type>::const_iterator it = D.begin(), end=D.end(); it != end; ++it) {
+ m_C[idx++] = sum;
+ sum += it->second;
+ }
+ m_C[idx] = sum; // insert sum of all elements
+ }
+
+ //! Copy constructor
+ int_alphabet(const int_alphabet& strat): char2comp(this), comp2char(this), C(m_C), sigma(m_sigma) {
+ copy(strat);
+ }
+
+ //! Copy constructor
+ int_alphabet(int_alphabet&& strat) {
+ *this = std::move(strat);
+ }
+
+ int_alphabet& operator=(const int_alphabet& strat) {
+ if (this != &strat) {
+ copy(strat);
+ }
+ return *this;
+ }
+
+ int_alphabet& operator=(int_alphabet&& strat) {
+ if (this != &strat) {
+ m_char = std::move(strat.m_char);
+ m_char_rank = std::move(strat.m_char_rank);
+ m_char_rank.set_vector(&m_char);
+ m_char_select = std::move(strat.m_char_select);
+ m_char_select.set_vector(&m_char);
+ m_C = std::move(strat.m_C);
+ m_sigma = std::move(strat.m_sigma);
+ }
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(int_alphabet& strat) {
+ m_char.swap(strat.m_char);
+ util::swap_support(m_char_rank, strat.m_char_rank, &m_char, &(strat.m_char));
+ util::swap_support(m_char_select, strat.m_char_select, &m_char, &(strat.m_char));
+ m_C.swap(strat.m_C);
+ std::swap(m_sigma,strat.m_sigma);
+ }
+
+ //! Serialize method
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_char.serialize(out, child, "m_char");
+ written_bytes += m_char_rank.serialize(out, child, "m_char_rank");
+ written_bytes += m_char_select.serialize(out, child, "m_char_select");
+ written_bytes += m_C.serialize(out, child, "m_C");
+ written_bytes += write_member(m_sigma, out, child, "m_sigma");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load method
+ void load(std::istream& in) {
+ m_char.load(in);
+ m_char_rank.load(in);
+ m_char_rank.set_vector(&m_char);
+ m_char_select.load(in);
+ m_char_select.set_vector(&m_char);
+ m_C.load(in);
+ read_member(m_sigma, in);
+ }
+};
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/csa_bitcompressed.hpp b/include/sdsl/csa_bitcompressed.hpp
new file mode 100644
index 0000000..5f94f49
--- /dev/null
+++ b/include/sdsl/csa_bitcompressed.hpp
@@ -0,0 +1,312 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file csa_bitcompressed.hpp
+ \brief csa_bitcompressed.hpp contains a bitcompressed suffix array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CSA_UNCOMPRESSED
+#define INCLUDED_SDSL_CSA_UNCOMPRESSED
+
+#include "int_vector.hpp"
+#include "sdsl_concepts.hpp"
+#include "suffix_array_helper.hpp"
+#include "iterators.hpp"
+#include "util.hpp"
+#include "csa_sampling_strategy.hpp"
+#include "csa_alphabet_strategy.hpp"
+#include <iostream>
+#include <algorithm>
+#include <string>
+#include <iomanip>
+#include <iterator>
+
+
+namespace sdsl
+{
+
+//! A class for the uncompressed suffix array (SA).
+/*!
+ * This class stores the information of the suffix array and the inverse suffix array in uncompressed form.
+ * In contrast to this class, classes like sdsl::csa_sada, and sdsl::csa_wt store
+ * the suffix array and inverse suffix array data in compressed form.
+ *
+ * The interface of this class is exactly the same as for the compressed indexes. This is the reason
+ * why it is in the group of compressed suffix arrays.
+ *
+ * \tparam t_alphabet_strat Policy for alphabet representation.
+ *
+ * \par Space complexity
+ * \f$ 2n\cdot \log n\f$ bits, where \f$n\f$ equals the \f$size()\f$ of the suffix array.
+ * \sa sdsl::csa_sada, sdsl::csa_wt
+ * @ingroup csa
+ */
+template<class t_alphabet_strat=byte_alphabet>
+class csa_bitcompressed
+{
+ friend class bwt_of_csa_psi<csa_bitcompressed>;
+ public:
+ typedef uint64_t value_type; // STL Container requirement
+ typedef random_access_const_iterator<csa_bitcompressed> const_iterator;// STL Container requirement
+ typedef const_iterator iterator; // STL Container requirement
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type; // STL Container requirement
+ typedef size_type csa_size_type;
+ typedef ptrdiff_t difference_type; // STL Container requirement
+ typedef traverse_csa_saisa<csa_bitcompressed,true> psi_type;
+ typedef traverse_csa_saisa<csa_bitcompressed,false> lf_type;
+ typedef bwt_of_csa_psi<csa_bitcompressed> bwt_type;
+ typedef text_of_csa<csa_bitcompressed> text_type;
+ typedef first_row_of_csa<csa_bitcompressed> first_row_type;
+ typedef _sa_order_sampling<csa_bitcompressed,0> sa_sample_type;
+ typedef int_vector<> isa_sample_type;
+ typedef isa_sample_type isa_type;
+ typedef t_alphabet_strat alphabet_type;
+ typedef typename alphabet_type::char_type char_type; // Note: This is the char type of the CSA not the WT!
+ typedef typename alphabet_type::comp_char_type comp_char_type;
+ typedef typename alphabet_type::string_type string_type;
+ typedef typename alphabet_type::alphabet_category alphabet_category;
+ typedef csa_bitcompressed csa_type;
+
+ typedef csa_tag index_category;
+ typedef psi_tag extract_category;
+
+ enum { sa_sample_dens = 1,
+ isa_sample_dens = 1
+ };
+
+ private:
+ sa_sample_type m_sa; // vector for suffix array values
+ isa_sample_type m_isa; // vector for inverse suffix array values
+ alphabet_type m_alphabet;
+
+ void copy(const csa_bitcompressed& csa) {
+ m_sa = csa.m_sa;
+ m_isa = csa.m_isa;
+ m_alphabet = csa.m_alphabet;
+ }
+ public:
+ const typename alphabet_type::char2comp_type& char2comp = m_alphabet.char2comp;
+ const typename alphabet_type::comp2char_type& comp2char = m_alphabet.comp2char;
+ const typename alphabet_type::C_type& C = m_alphabet.C;
+ const typename alphabet_type::sigma_type& sigma = m_alphabet.sigma;
+ const psi_type psi = psi_type(*this);
+ const lf_type lf = lf_type(*this);
+ const bwt_type bwt = bwt_type(*this);
+ const bwt_type L = bwt_type(*this);
+ const isa_type& isa = m_isa;
+ const first_row_type F = first_row_type(*this);
+ const text_type text = text_type(*this);
+ const sa_sample_type& sa_sample = m_sa;
+ const isa_sample_type& isa_sample = m_isa;
+
+ //! Default constructor
+ csa_bitcompressed() {}
+ //! Copy constructor
+ csa_bitcompressed(const csa_bitcompressed& csa) {
+ copy(csa);
+ }
+ //! Move constructor
+ csa_bitcompressed(csa_bitcompressed&& csa) {
+ *this = std::move(csa);
+ }
+
+ //! Constructor
+ csa_bitcompressed(cache_config& config) {
+ std::string text_file = cache_file_name(key_trait<alphabet_type::int_width>::KEY_TEXT,config);
+ int_vector_buffer<alphabet_type::int_width> text_buf(text_file);
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA,config));
+ size_type n = text_buf.size();
+ {
+ alphabet_type tmp_alphabet(text_buf, n);
+ m_alphabet.swap(tmp_alphabet);
+ }
+ {
+ sa_sample_type tmp_sample(config);
+ m_sa.swap(tmp_sample);
+ }
+ set_isa_samples<csa_bitcompressed>(sa_buf, m_isa);
+
+ if (!store_to_file(m_isa, cache_file_name(conf::KEY_ISA,config), true)) {
+ throw std::ios_base::failure("#csa_bitcompressed: Cannot store ISA to file system!");
+ } else {
+ register_cache_file(conf::KEY_ISA, config);
+ }
+ }
+
+
+ //! Number of elements in the instance.
+ /*! Required for the Container Concept of the STL.
+ * \sa max_size, empty
+ */
+ size_type size()const {
+ return m_sa.size();
+ }
+
+ //! Returns the largest size that csa_bitcompressed can ever have.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ static size_type max_size() {
+ return int_vector<>::max_size();
+ }
+
+ //! Returns if the data structure is empty.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ bool empty()const {
+ return m_sa.empty();
+ }
+
+ //! Swap method for csa_bitcompressed
+ void swap(csa_bitcompressed& csa) {
+ if (this != &csa) {
+ m_sa.swap(csa.m_sa);
+ m_isa.swap(csa.m_isa);
+ m_alphabet.swap(csa.m_alphabet);
+ }
+ }
+
+ //! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ *
+ * Required for the STL Random Access Container Concept.
+ */
+ inline value_type operator[](size_type i)const {
+ return m_sa[i];
+ }
+
+ //! Assignment Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ csa_bitcompressed& operator=(const csa_bitcompressed& csa) {
+ if (this != &csa) {
+ copy(csa);
+ }
+ return *this;
+ }
+
+ //! Assignment Move Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ csa_bitcompressed& operator=(csa_bitcompressed&& csa) {
+ if (this != &csa) {
+ m_sa = std::move(csa.m_sa);
+ m_isa = std::move(csa.m_isa);
+ m_alphabet = std::move(csa.m_alphabet);
+ }
+ return *this;
+ }
+
+ //! Serialize to a stream.
+ /*! \param out Output stream to write the data structure.
+ * \return The number of written bytes.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_sa.serialize(out, child, "m_sa");
+ written_bytes += m_isa.serialize(out, child, "m_isa");
+ written_bytes += m_alphabet.serialize(out, child, "m_alphabet");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ m_sa.load(in);
+ m_isa.load(in);
+ m_alphabet.load(in);
+ }
+
+ size_type get_sample_dens()const {
+ return 1;
+ }
+
+ private:
+
+ // Calculates how many symbols c are in the prefix [0..i-1] of the BWT of the original text.
+ /*
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in [0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the BWT.
+ * \par Time complexity
+ * \f$ \Order{\log n} \f$
+ */
+ size_type rank_bwt(size_type i, const char_type c) const {
+ // TODO: special case if c == BWT[i-1] we can use LF to get a constant time answer
+ comp_char_type cc = char2comp[c];
+ if (cc==0 and c!=0) // character is not in the text => return 0
+ return 0;
+ // binary search the interval [C[cc]..C[cc+1]-1] for the result
+ size_type lower_b = C[cc], upper_b = C[((size_type)1)+cc]; // lower_b inclusive, upper_b exclusive
+ while (lower_b+1 < upper_b) {
+ size_type mid = (lower_b+upper_b)/2;
+ if (psi[mid] >= i)
+ upper_b = mid;
+ else
+ lower_b = mid;
+ }
+ if (lower_b > C[cc])
+ return lower_b - C[cc] + 1;
+ else { // lower_b == m_C[cc]
+ return psi[lower_b] < i;// 1 if psi[lower_b]<i, 0 otherwise
+ }
+ }
+
+ // Calculates the i-th occurrence of symbol c in the BWT of the original text.
+ /*
+ * \param i The i-th occurrence. \f$i\in [1..rank(size(),c)]\f$.
+ * \param c Character c.
+ * \returns The i-th occurrence of c in the BWT or size() if c does
+ * not occur t times in BWT>
+ * \par Time complexity
+ * \f$ \Order{t_{\Psi}} \f$
+ */
+ size_type select_bwt(size_type i, const char_type c) const {
+ comp_char_type cc = char2comp[c];
+ if (cc==0 and c!=0) // character is not in the text => return size()
+ return size();
+ if (C[cc]+i-1 < C[((size_type)1)+cc]) {
+ return psi[C[cc]+i-1];
+ }
+ return size();
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/csa_sada.hpp b/include/sdsl/csa_sada.hpp
new file mode 100644
index 0000000..58e343c
--- /dev/null
+++ b/include/sdsl/csa_sada.hpp
@@ -0,0 +1,465 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file csa_sada.hpp
+ \brief csa_sada.hpp contains an implementation of the compressed suffix array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CSA_SADA
+#define INCLUDED_SDSL_CSA_SADA
+
+#include "enc_vector.hpp"
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include "suffix_array_helper.hpp"
+#include "util.hpp"
+#include "csa_sampling_strategy.hpp"
+#include "csa_alphabet_strategy.hpp"
+#include <iostream>
+#include <algorithm>
+#include <cassert>
+#include <cstring> // for strlen
+#include <iomanip>
+#include <iterator>
+
+namespace sdsl
+{
+
+//! A class for the Compressed Suffix Array (CSA) proposed by Sadakane for practical implementation.
+/*!
+ * \tparam t_enc_vec Space-efficient vector for increasing integer sequences.
+ * \tparam t_dens Sampling density of SA values
+ * \tparam t_int_dens Sampling density of ISA values
+ * \tparam t_sa_sample_strat Policy of SA sampling. E.g. sample in SA-order or text-order.
+ * \tparam t_isa Vector type for ISA sample values.
+ * \tparam t_alphabet_strat Policy for alphabet representation.
+ *
+ * \sa sdsl::csa_wt, sdsl::csa_bitcompressed
+ * @ingroup csa
+ */
+template<class t_enc_vec = enc_vector<>, // Vector type used to store the Psi-function
+ uint32_t t_dens = 32, // Sample density for suffix array (SA) values
+ uint32_t t_inv_dens = 64, // Sample density for inverse suffix array (ISA) values
+ class t_sa_sample_strat = sa_order_sa_sampling<>,// Policy class for the SA sampling. Alternative text_order_sa_sampling.
+ class t_isa = int_vector<>, // Container for the ISA samples.
+ class t_alphabet_strat = byte_alphabet // Policy class for the representation of the alphabet.
+ >
+class csa_sada
+{
+ friend class bwt_of_csa_psi<csa_sada>;
+ public:
+ enum { sa_sample_dens = t_dens,
+ isa_sample_dens = t_inv_dens
+ };
+
+ typedef uint64_t value_type;
+ typedef random_access_const_iterator<csa_sada> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef size_type csa_size_type;
+ typedef ptrdiff_t difference_type;
+ typedef t_enc_vec enc_vector_type;
+ typedef enc_vector_type psi_type;
+ typedef traverse_csa_psi<csa_sada,false> lf_type;
+ typedef bwt_of_csa_psi<csa_sada> bwt_type;
+ typedef isa_of_csa_psi<csa_sada> isa_type;
+ typedef text_of_csa<csa_sada> text_type;
+ typedef first_row_of_csa<csa_sada> first_row_type;
+ typedef typename t_sa_sample_strat::template type<csa_sada>::sample_type sa_sample_type;
+ typedef t_isa isa_sample_type;
+ typedef t_alphabet_strat alphabet_type;
+ typedef typename alphabet_type::alphabet_category alphabet_category;
+ typedef typename alphabet_type::comp_char_type comp_char_type;
+ typedef typename alphabet_type::char_type char_type; // Note: This is the char type of the CSA not the WT!
+ typedef typename alphabet_type::string_type string_type;
+ typedef csa_sada csa_type;
+
+ typedef csa_tag index_category;
+ typedef psi_tag extract_category;
+
+ friend class traverse_csa_psi<csa_sada,true>;
+ friend class traverse_csa_psi<csa_sada,false>;
+
+ static const uint32_t linear_decode_limit = 100000;
+ private:
+ enc_vector_type m_psi; // psi function
+ sa_sample_type m_sa_sample; // suffix array samples
+ isa_sample_type m_isa_sample; // inverse suffix array samples
+ alphabet_type m_alphabet; // alphabet component
+
+ mutable std::vector<uint64_t> m_psi_buf; // buffer for decoded psi values
+
+ void copy(const csa_sada& csa) {
+ m_psi = csa.m_psi;
+ m_sa_sample = csa.m_sa_sample;
+ m_isa_sample = csa.m_isa_sample;
+ m_alphabet = csa.m_alphabet;
+ };
+
+ void create_buffer() {
+ if (enc_vector_type::sample_dens < linear_decode_limit) {
+ m_psi_buf = std::vector<uint64_t>(enc_vector_type::sample_dens+1);
+ }
+ }
+
+ public:
+ const typename alphabet_type::char2comp_type& char2comp = m_alphabet.char2comp;
+ const typename alphabet_type::comp2char_type& comp2char = m_alphabet.comp2char;
+ const typename alphabet_type::C_type& C = m_alphabet.C;
+ const typename alphabet_type::sigma_type& sigma = m_alphabet.sigma;
+ const psi_type& psi = m_psi;
+ const lf_type lf = lf_type(*this);
+ const bwt_type bwt = bwt_type(*this);
+ const isa_type isa = isa_type(*this);
+ const bwt_type L = bwt_type(*this);
+ const first_row_type F = first_row_type(*this);
+ const text_type text = text_type(*this);
+ const sa_sample_type& sa_sample = m_sa_sample;
+ const isa_sample_type& isa_sample = m_isa_sample;
+
+
+ //! Default Constructor
+ csa_sada() {
+ create_buffer();
+ }
+ //! Default Destructor
+ ~csa_sada() { }
+
+ //! Copy constructor
+ csa_sada(const csa_sada& csa) {
+ create_buffer();
+ copy(csa);
+ }
+
+ //! Move constructor
+ csa_sada(csa_sada&& csa) {
+ *this = std::move(csa);
+ }
+
+ csa_sada(cache_config& config);
+
+ //! Number of elements in the \f$\CSA\f$.
+ /*! Required for the Container Concept of the STL.
+ * \sa max_size, empty
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type size()const {
+ return m_psi.size();
+ }
+
+ //! Returns the largest size that csa_sada can ever have.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ static size_type max_size() {
+ return t_enc_vec::max_size();
+ }
+
+ //! Returns if the data strucutre is empty.
+ /*! Required for the Container Concept of the STL.A
+ * \sa size
+ */
+ bool empty()const {
+ return m_psi.empty();
+ }
+
+ //! Swap method for csa_sada
+ /*! The swap method can be defined in terms of assignment.
+ This requires three assignments, each of which, for a container type, is linear
+ in the container's size. In a sense, then, a.swap(b) is redundant.
+ This implementation guaranties a run-time complexity that is constant rather than linear.
+ \param csa csa_sada to swap.
+
+ Required for the Assignable Conecpt of the STL.
+ */
+ void swap(csa_sada& csa);
+
+ //! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ * Required for the STL Random Access Container Concept.
+ * \par Time complexity
+ * \f$ \Order{s_{SA}\cdot t_{\Psi}} \f$, where every \f$s_{SA}\f$th suffix array entry is sampled and \f$t_{\Psi}\f$
+ * is the access time for an element in the \f$\Psi\f$-function.
+ */
+ inline value_type operator[](size_type i)const;
+
+ //! Assignment Copy Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ csa_sada& operator=(const csa_sada& csa) {
+ if (this != &csa) {
+ copy(csa);
+ }
+ return *this;
+ }
+
+ //! Assignment Move Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ csa_sada& operator=(csa_sada&& csa) {
+ if (this != &csa) {
+ m_psi = std::move(csa.m_psi);
+ m_sa_sample = std::move(csa.m_sa_sample);
+ m_isa_sample = std::move(csa.m_isa_sample);
+ m_alphabet = std::move(csa.m_alphabet);
+ m_psi_buf = std::move(csa.m_psi_buf);
+ }
+ return *this;
+ }
+
+ //! Serialize to a stream.
+ /*! \param out Outstream to write the data structure.
+ * \return The number of written bytes.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ //! Load from a stream.
+ /*! \param in Input stream to load the data structure from.
+ */
+ void load(std::istream& in);
+
+ uint32_t get_sample_dens() const {
+ return t_dens;
+ }
+
+ private:
+
+ // Calculates how many symbols c are in the prefix [0..i-1] of the BWT of the original text.
+ /*
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in [0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the BWT.
+ * \par Time complexity
+ * \f$ \Order{\log n t_{\Psi}} \f$
+ */
+ size_type rank_bwt(size_type i, const char_type c)const {
+ comp_char_type cc = char2comp[c];
+ if (cc==0 and c!=0) // character is not in the text => return 0
+ return 0;
+ if (i == 0)
+ return 0;
+ assert(i <= size());
+
+ size_type lower_b, upper_b; // lower_b inclusive, upper_b exclusive
+
+ const size_type sd = m_psi.get_sample_dens();
+ size_type lower_sb = (C[cc]+sd-1)/sd; // lower_sb inclusive
+ size_type upper_sb = (C[cc+1]+sd-1)/sd; // upper_sb exclusive
+ while (lower_sb+1 < upper_sb) {
+ size_type mid = (lower_sb+upper_sb)/2;
+ if (m_psi.sample(mid) >= i)
+ upper_sb = mid;
+ else
+ lower_sb = mid;
+ }
+
+ if (lower_sb == upper_sb) { // the interval was smaller than sd
+ lower_b = C[cc]; upper_b = C[cc+1];
+ } else if (lower_sb > (C[cc]+sd-1)/sd) { // main case
+// TODO: don't use get_inter_sampled_values if t_dens is really
+// large
+ lower_b = lower_sb*sd;
+ if (0 == m_psi_buf.size()) {
+ upper_b = std::min(upper_sb*sd, C[cc+1]);
+ goto finish;
+ }
+ uint64_t* p = m_psi_buf.data();
+ // extract the psi values between two samples
+ m_psi.get_inter_sampled_values(lower_sb, p);
+ p = m_psi_buf.data();
+ uint64_t smpl = m_psi.sample(lower_sb);
+ // handle border cases
+ if (lower_b + m_psi.get_sample_dens() >= C[cc+1])
+ m_psi_buf[ C[cc+1]-lower_b ] = size()-smpl;
+ else
+ m_psi_buf[ m_psi.get_sample_dens() ] = size()-smpl;
+ // search the result linear
+ while ((*p++)+smpl < i);
+
+ return p-1-m_psi_buf.data() + lower_b - C[cc];
+ } else { // lower_b == (m_C[cc]+sd-1)/sd and lower_sb < upper_sb
+ if (m_psi.sample(lower_sb) >= i) {
+ lower_b = C[cc];
+ upper_b = lower_sb * sd + 1;
+ } else {
+ lower_b = lower_sb * sd;
+ upper_b = std::min(upper_sb*sd, C[cc+1]);
+ }
+ }
+finish:
+ // binary search the interval [C[cc]..C[cc+1]-1] for the result
+// size_type lower_b = m_C[cc], upper_b = m_C[cc+1]; // lower_b inclusive, upper_b exclusive
+ while (lower_b+1 < upper_b) {
+ size_type mid = (lower_b+upper_b)/2;
+ if (m_psi[mid] >= i)
+ upper_b = mid;
+ else
+ lower_b = mid;
+ }
+ if (lower_b > C[cc])
+ return lower_b - C[cc] + 1;
+ else { // lower_b == m_C[cc]
+ return m_psi[lower_b] < i;// 1 if m_psi[lower_b]<i, 0 otherwise
+ }
+ }
+
+ // Calculates the position of the i-th c in the BWT of the original text.
+ /*
+ * \param i The i-th occurrence. \f$i\in [1..rank_bwt(size(),c)]\f$.
+ * \param c Symbol c.
+ * \returns The position of the i-th c in the BWT or size() if c does occur less then i times.
+ * \par Time complexity
+ * \f$ \Order{t_{\Psi}} \f$
+ */
+ size_type select_bwt(size_type i, const char_type c)const {
+ assert(i > 0);
+ comp_char_type cc = char2comp[c];
+ if (cc==0 and c!=0) // character is not in the text => return 0
+ return size();
+ assert(cc != 255);
+ if (C[cc]+i-1 < C[cc+1]) {
+ return m_psi[C[cc]+i-1];
+ } else
+ return size();
+ }
+};
+
+// == template functions ==
+
+template<class t_enc_vec, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::csa_sada(cache_config& config)
+{
+ create_buffer();
+ if (!cache_file_exists(key_trait<alphabet_type::int_width>::KEY_BWT, config)) {
+ return;
+ }
+ int_vector_buffer<alphabet_type::int_width> bwt_buf(cache_file_name(key_trait<alphabet_type::int_width>::KEY_BWT,config));
+ size_type n = bwt_buf.size();
+ {
+ auto event = memory_monitor::event("construct csa-alpbabet");
+ alphabet_type tmp_alphabet(bwt_buf, n);
+ m_alphabet.swap(tmp_alphabet);
+ }
+
+ int_vector<> cnt_chr(sigma, 0, bits::hi(n)+1);
+ for (typename alphabet_type::sigma_type i=0; i < sigma; ++i) {
+ cnt_chr[i] = C[i];
+ }
+ // calculate psi
+ {
+ auto event = memory_monitor::event("construct PSI");
+ // TODO: move PSI construct into construct_PSI.hpp
+ int_vector<> psi(n, 0, bits::hi(n)+1);
+ for (size_type i=0; i < n; ++i) {
+ psi[ cnt_chr[ char2comp[bwt_buf[i]] ]++ ] = i;
+ }
+ std::string psi_file = cache_file_name(conf::KEY_PSI, config);
+ if (!store_to_cache(psi, conf::KEY_PSI, config)) {
+ return;
+ }
+ }
+ {
+ auto event = memory_monitor::event("encode PSI");
+ int_vector_buffer<> psi_buf(cache_file_name(conf::KEY_PSI, config));
+ t_enc_vec tmp_psi(psi_buf);
+ m_psi.swap(tmp_psi);
+ }
+ {
+ auto event = memory_monitor::event("sample SA");
+ sa_sample_type tmp_sa_sample(config);
+ m_sa_sample.swap(tmp_sa_sample);
+ }
+ {
+ auto event = memory_monitor::event("sample ISA");
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config));
+ set_isa_samples<csa_sada>(sa_buf, m_isa_sample);
+ }
+}
+
+template<class t_enc_vec, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+inline auto csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::operator[](size_type i)const -> value_type
+{
+ size_type off = 0;
+while (!m_sa_sample.is_sampled(i)) { // while i mod t_dens != 0 (SA[i] is not sampled) SG: auf keinen Fall get_sample_dens nehmen, ist total langsam
+i = psi[i]; // go to the position where SA[i]+1 is located
+ ++off; // add 1 to the offset
+}
+value_type result = m_sa_sample.sa_value(i);
+if (result < off) {
+return m_psi.size()-(off-result);
+} else
+ return result-off;
+ }
+
+
+ template<class t_enc_vec, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+auto csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::serialize(std::ostream& out, structure_tree_node* v, std::string name)const -> size_type
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_psi.serialize(out, child, "psi");
+ written_bytes += m_sa_sample.serialize(out, child, "sa_samples");
+ written_bytes += m_isa_sample.serialize(out, child, "isa_samples");
+ written_bytes += m_alphabet.serialize(out, child, "alphabet");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<class t_enc_vec, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+void csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::load(std::istream& in)
+{
+ m_psi.load(in);
+ m_sa_sample.load(in);
+ m_isa_sample.load(in);
+ m_alphabet.load(in);
+}
+
+template<class t_enc_vec, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+void csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::swap(csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa)
+{
+ if (this != &csa) {
+ m_psi.swap(csa.m_psi);
+ m_sa_sample.swap(csa.m_sa_sample);
+ m_isa_sample.swap(csa.m_isa_sample);
+ m_alphabet.swap(csa.m_alphabet);
+ }
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/csa_sampling_strategy.hpp b/include/sdsl/csa_sampling_strategy.hpp
new file mode 100644
index 0000000..c04cd8a
--- /dev/null
+++ b/include/sdsl/csa_sampling_strategy.hpp
@@ -0,0 +1,392 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file csa_sampling_strategy.hpp
+ \brief csa_sampling_strategy.hpp includes different strategy classes for suffix array sampling in the CSAs.
+ \author Simon Gog
+*/
+
+#ifndef INCLUDED_CSA_SAMPLING_STRATEGY
+#define INCLUDED_CSA_SAMPLING_STRATEGY
+
+
+/*
+ * Text = ABCDEFABCDEF$
+ * 0123456789012
+ * sa_sample_dens = 2
+ * *1 SA *2
+ * * 12 * $
+ * 06 * ABCDEF$
+ * * 00 * ABCDEFABCDEF$
+ * 07 BCDEF$
+ * * 01 BCDEFABCDEF$
+ * 08 * CDEF$
+ * * 02 * CDEFABCDEF$
+ * 09 DEF$
+ * * 03 DEFABCDEF$
+ * 10 * EF$
+ * * 04 * EFABCDEF$
+ * 11 F$
+ * * 05 FABCDEF$
+ *
+ * The first sampling (*1) is called suffix order sampling. It has the advantage, that
+ * we don't need to store a bitvector, which marks the sampled suffixes, since a suffix
+ * at index \(i\) in the suffix array is marked if \( 0 \equiv i \mod sa_sample_dens \).
+ *
+ * The second sampling (*2) is called text order sampling. It is also called regular in [1].
+ *
+ * [1] P.Ferragina, J. Siren, R. Venturini: Distribution-Aware Compressed Full-Text Indexes, ESA 2011
+ */
+
+#include "int_vector.hpp"
+#include "csa_alphabet_strategy.hpp" // for key_trait
+#include <set>
+
+namespace sdsl
+{
+
+template<class t_csa, uint8_t t_width=0>
+class _sa_order_sampling : public int_vector<t_width>
+{
+ public:
+ typedef int_vector<t_width> base_type;
+ typedef typename base_type::size_type size_type; // make typedefs of base_type visible
+ typedef typename base_type::value_type value_type; //
+ enum { sample_dens = t_csa::sa_sample_dens };
+
+ //! Default constructor
+ _sa_order_sampling() {}
+
+ //! Constructor
+ /*
+ * \param cconfig Cache configuration (SA is expected to be cached.).
+ * \param csa Pointer to the corresponding CSA. Not used in this class.
+ * \par Time complexity
+ * Linear in the size of the suffix array.
+ */
+ _sa_order_sampling(const cache_config& cconfig, SDSL_UNUSED const t_csa* csa=nullptr) {
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, cconfig));
+ size_type n = sa_buf.size();
+ this->width(bits::hi(n)+1);
+ this->resize((n+sample_dens-1)/sample_dens);
+
+ for (size_type i=0, cnt_mod=sample_dens, cnt_sum=0; i < n; ++i, ++cnt_mod) {
+ size_type sa = sa_buf[i];
+ if (sample_dens == cnt_mod) {
+ cnt_mod = 0;
+ (*this)[cnt_sum++] = sa;
+ }
+ }
+ }
+
+ //! Determine if index i is sampled or not
+ inline bool is_sampled(size_type i) const {
+ return 0 == (i % sample_dens);
+ }
+
+ //! Return the suffix array value for the sampled index i
+ inline value_type sa_value(size_type i) const {
+ return (*this)[i/sample_dens];
+ }
+};
+
+template<uint8_t t_width=0>
+class sa_order_sa_sampling
+{
+ public:
+ template<class t_csa> // template inner class which is used in CSAs to parametrize the
+ class type // sampling strategy class with the Sampling density of the CSA
+ {
+ public:
+ typedef _sa_order_sampling<t_csa, t_width> sample_type;
+ };
+};
+
+
+template<class t_csa,
+ class bit_vector_type=bit_vector,
+ class rank_support_type=typename bit_vector_type::rank_1_type,
+ uint8_t t_width=0
+ >
+class _text_order_sampling : public int_vector<t_width>
+{
+ private:
+ bit_vector_type m_marked;
+ rank_support_type m_rank_marked;
+ public:
+ typedef int_vector<t_width> base_type;
+ typedef typename base_type::size_type size_type; // make typedefs of base_type visible
+ typedef typename base_type::value_type value_type; //
+ enum { sample_dens = t_csa::sa_sample_dens };
+
+ //! Default constructor
+ _text_order_sampling() {}
+
+ //! Constructor
+ /*
+ * \param cconfig Cache configuration (SA is expected to be cached.).
+ * \param csa Pointer to the corresponding CSA. Not used in this class.
+ * \par Time complexity
+ * Linear in the size of the suffix array.
+ */
+ _text_order_sampling(const cache_config& cconfig, SDSL_UNUSED const t_csa* csa=nullptr) {
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, cconfig));
+ size_type n = sa_buf.size();
+ bit_vector marked(n, 0); // temporary bitvector for the marked text positions
+ this->width(bits::hi(n)+1);
+ this->resize((n+sample_dens-1)/sample_dens);
+
+ for (size_type i=0, sa_cnt=0; i < n; ++i) {
+ size_type sa = sa_buf[i];
+ if (0 == (sa % sample_dens)) {
+ marked[i] = 1;
+ (*this)[sa_cnt++] = sa;
+ }
+ }
+ m_marked = std::move(bit_vector_type(marked));
+ util::init_support(m_rank_marked, &m_marked);
+ }
+
+ //! Copy constructor
+ _text_order_sampling(const _text_order_sampling& st) : base_type(st) {
+ m_marked = st.m_marked;
+ m_rank_marked = st.m_rank_marked;
+ m_rank_marked.set_vector(&m_marked);
+ }
+
+ //! Determine if index i is sampled or not
+ inline bool is_sampled(size_type i) const {
+ return m_marked[i];
+ }
+
+ //! Return the suffix array value for the sampled index i
+ inline value_type sa_value(size_type i) const {
+ return (*this)[m_rank_marked(i)];
+ }
+
+ //! Assignment operation
+ _text_order_sampling& operator=(const _text_order_sampling& st) {
+ if (this != &st) {
+ base_type::operator=(st);
+ m_marked = st.m_marked;
+ m_rank_marked = st.m_rank_marked;
+ m_rank_marked.set_vector(&m_marked);
+ }
+ return *this;
+ }
+
+ //! Swap operation
+ void swap(_text_order_sampling& st) {
+ base_type::swap(st);
+ m_marked.swap(st.m_marked);
+ util::swap_support(m_rank_marked, st.m_rank_marked, &m_marked, &(st.m_marked));
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v, std::string name)const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += base_type::serialize(out, child, "samples");
+ written_bytes += m_marked.serialize(out, child, "marked");
+ written_bytes += m_rank_marked.serialize(out, child, "rank_marked");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ base_type::load(in);
+ m_marked.load(in);
+ m_rank_marked.load(in);
+ m_rank_marked.set_vector(&m_marked);
+ }
+};
+
+template<class t_bit_vec=bit_vector, class t_rank_sup=typename t_bit_vec::rank_1_type, uint8_t t_width=0>
+class text_order_sa_sampling
+{
+ public:
+ template<class t_csa> // template inner class which is used in CSAs to parametrize the
+ class type // sampling strategy class with the Sampling density of the CSA
+ {
+ public:
+ typedef _text_order_sampling<t_csa,
+ t_bit_vec,
+ t_rank_sup,
+ t_width
+ > sample_type;
+ };
+};
+
+/*
+ * Text = ABCDEFABCDEF$
+ * 0123456789012
+ * sa_sample_dens = 4
+ * sa_sample_chars = {B,E}
+ * SA BWT (1)
+ * 12 F * $
+ * 06 F ABCDEF$
+ * 00 $ * ABCDEFABCDEF$
+ * 07 A BCDEF$
+ * 01 A BCDEFABCDEF$
+ * 08 B * CDEF$
+ * 02 B * CDEFABCDEF$
+ * 09 C DEF$
+ * 03 C DEFABCDEF$
+ * 10 D EF$
+ * 04 D * EFABCDEF$
+ * 11 E * F$
+ * 05 E * FABCDEF$
+ *
+ * In this sampling a suffix x=SA[i] is marked if x \( 0 \equiv x \mod sa_sample_dens \) or
+ * BWT[i] is contained in sa_sample_chars.
+ */
+
+template<class t_csa,
+ class bit_vector_type=bit_vector,
+ class rank_support_type=typename bit_vector_type::rank_1_type,
+ uint8_t t_width=0
+ >
+class _bwt_sampling : public int_vector<t_width>
+{
+ private:
+ bit_vector_type m_marked;
+ rank_support_type m_rank_marked;
+ public:
+ typedef int_vector<t_width> base_type;
+ typedef typename base_type::size_type size_type; // make typedefs of base_type visible
+ typedef typename base_type::value_type value_type; //
+ enum { sample_dens = t_csa::sa_sample_dens };
+
+ //! Default constructor
+ _bwt_sampling() {}
+
+ //! Constructor
+ /*
+ * \param cconfig Cache configuration (BWT,SA, and SAMPLE_CHARS are expected to be cached.).
+ * \param csa Pointer to the corresponding CSA. Not used in this class.
+ * \par Time complexity
+ * Linear in the size of the suffix array.
+ */
+ _bwt_sampling(const cache_config& cconfig, SDSL_UNUSED const t_csa* csa=nullptr) {
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, cconfig));
+ int_vector_buffer<t_csa::alphabet_type::int_width>
+ bwt_buf(cache_file_name(key_trait<t_csa::alphabet_type::int_width>::KEY_BWT,cconfig));
+ size_type n = sa_buf.size();
+ bit_vector marked(n, 0); // temporary bitvector for the marked text positions
+ this->width(bits::hi(n)+1);
+ int_vector<> sample_char;
+ typedef typename t_csa::char_type char_type;
+ std::set<char_type> char_map;
+ if (load_from_cache(sample_char, conf::KEY_SAMPLE_CHAR,cconfig)) {
+ for (uint64_t i=0; i<sample_char.size(); ++i) {
+ char_map.insert((char_type)sample_char[i]);
+ }
+ }
+ size_type sa_cnt = 0;
+ for (size_type i=0; i < n; ++i) {
+ size_type sa = sa_buf[i];
+ char_type bwt = bwt_buf[i];
+ if (0 == (sa % sample_dens)) {
+ marked[i] = 1;
+ ++sa_cnt;
+ } else if (char_map.find(bwt) != char_map.end()) {
+ marked[i] = 1;
+ ++sa_cnt;
+ }
+ }
+ this->resize(sa_cnt);
+ sa_cnt = 0;
+ for (size_type i=0; i < n; ++i) {
+ size_type sa = sa_buf[i];
+ if (marked[i]) {
+ (*this)[sa_cnt++] = sa;
+ }
+ }
+ util::assign(m_marked, marked);
+ util::init_support(m_rank_marked, &m_marked);
+ }
+
+ //! Copy constructor
+ _bwt_sampling(const _bwt_sampling& st) : base_type(st) {
+ m_marked = st.m_marked;
+ m_rank_marked = st.m_rank_marked;
+ m_rank_marked.set_vector(&m_marked);
+ }
+
+ //! Determine if index i is sampled or not
+ inline bool is_sampled(size_type i) const {
+ return m_marked[i];
+ }
+
+ //! Return the suffix array value for the sampled index i
+ inline value_type sa_value(size_type i) const {
+ return (*this)[m_rank_marked(i)];
+ }
+
+ //! Assignment operation
+ _bwt_sampling& operator=(const _bwt_sampling& st) {
+ if (this != &st) {
+ base_type::operator=(st);
+ m_marked = st.m_marked;
+ m_rank_marked = st.m_rank_marked;
+ m_rank_marked.set_vector(&m_marked);
+ }
+ return *this;
+ }
+
+ //! Swap operation
+ void swap(_bwt_sampling& st) {
+ base_type::swap(st);
+ m_marked.swap(st.m_marked);
+ util::swap_support(m_rank_marked, st.m_rank_marked, &m_marked, &(st.m_marked));
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v, std::string name)const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += base_type::serialize(out, child, "samples");
+ written_bytes += m_marked.serialize(out, child, "marked");
+ written_bytes += m_rank_marked.serialize(out, child, "rank_marked");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ base_type::load(in);
+ m_marked.load(in);
+ m_rank_marked.load(in);
+ m_rank_marked.set_vector(&m_marked);
+ }
+};
+
+template<class t_bit_vec=bit_vector, class t_rank_sup=typename t_bit_vec::rank_1_type, uint8_t t_width=0>
+class sa_bwt_sampling
+{
+ public:
+ template<class t_csa> // template inner class which is used in CSAs to parametrize the
+ class type // sampling strategy class with the Sampling density of the CSA
+ {
+ public:
+ typedef _bwt_sampling<t_csa,
+ t_bit_vec,
+ t_rank_sup,
+ t_width
+ > sample_type;
+ };
+};
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/csa_wt.hpp b/include/sdsl/csa_wt.hpp
new file mode 100644
index 0000000..db0492e
--- /dev/null
+++ b/include/sdsl/csa_wt.hpp
@@ -0,0 +1,384 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file csa_wt.hpp
+ \brief csa_wt.hpp contains an implementation of the compressed suffix array based on a wavelet tree.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CSA_WT
+#define INCLUDED_SDSL_CSA_WT
+
+#include "wavelet_trees.hpp"
+#include "suffix_array_helper.hpp"
+#include "iterators.hpp"
+#include "util.hpp"
+#include "fast_cache.hpp"
+#include "csa_sampling_strategy.hpp"
+#include "csa_alphabet_strategy.hpp"
+#include <iostream>
+#include <algorithm> // for std::swap
+#include <cassert>
+#include <cstring> // for strlen
+#include <iomanip>
+#include <iterator>
+
+namespace sdsl
+{
+
+template<class t_csa>
+class psi_of_csa_wt; // forward declaration of PSI-array class
+
+template<class t_csa>
+class bwt_of_csa_wt; // forward declaration of BWT-array class
+
+
+//! A class for the Compressed Suffix Array (CSA) based on a Wavelet Tree (WT) of the Burrow Wheeler Transform of the original text.
+/*!
+ * \tparam t_wt Wavelet tree
+ * \tparam t_dens Sampling density of SA values
+ * \tparam t_int_dens Sampling density of ISA values
+ * \tparam t_sa_sample_strat Policy of SA sampling. E.g. sample in SA-order or text-order.
+ * \tparam t_isa Vector type for ISA sample values.
+ * \tparam t_alphabet_strat Policy for alphabet representation.
+ *
+ * \sa sdsl::csa_sada, sdsl::csa_bitcompressed
+ * @ingroup csa
+ */
+template<class t_wt = wt_huff<>, // Wavelet tree type
+ uint32_t t_dens = 32, // Sample density for suffix array (SA) values
+ uint32_t t_inv_dens = 64, // Sample density for inverse suffix array (ISA) values
+ class t_sa_sample_strat = sa_order_sa_sampling<>, // Policy class for the SA sampling. Alternative text_order_sa_sampling.
+ class t_isa = int_vector<>, // Container for the ISA samples.
+ class t_alphabet_strat = // Policy class for the representation of the alphabet.
+ typename alphabet_trait<typename t_wt::alphabet_category>::type
+ >
+class csa_wt
+{
+ friend class bwt_of_csa_wt<csa_wt>;
+ public:
+ enum { sa_sample_dens = t_dens,
+ isa_sample_dens = t_inv_dens
+ };
+
+ typedef uint64_t value_type;
+ typedef random_access_const_iterator<csa_wt> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef size_type csa_size_type;
+ typedef ptrdiff_t difference_type;
+ typedef traverse_csa_wt<csa_wt,true> psi_type;
+ typedef traverse_csa_wt<csa_wt,false> lf_type;
+ typedef bwt_of_csa_wt<csa_wt> bwt_type;
+ typedef isa_of_csa_wt<csa_wt> isa_type;
+ typedef first_row_of_csa<csa_wt> first_row_type;
+ typedef text_of_csa<csa_wt> text_type;
+ typedef t_wt wavelet_tree_type;
+ typedef typename t_sa_sample_strat::template type<csa_wt>::sample_type sa_sample_type;
+ typedef t_isa isa_sample_type;
+ typedef t_alphabet_strat alphabet_type;
+ typedef typename alphabet_type::char_type char_type; // Note: This is the char type of the CSA not the WT!
+ typedef typename alphabet_type::comp_char_type comp_char_type;
+ typedef typename alphabet_type::string_type string_type;
+ typedef csa_wt csa_type;
+
+ typedef csa_tag index_category;
+ typedef lf_tag extract_category;
+ typedef typename alphabet_type::alphabet_category alphabet_category;
+
+ private:
+ t_wt m_wavelet_tree; // the wavelet tree
+ sa_sample_type m_sa_sample; // suffix array samples
+ isa_sample_type m_isa_sample; // inverse suffix array samples
+ alphabet_type m_alphabet;
+//#define USE_CSA_CACHE
+#ifdef USE_CSA_CACHE
+ mutable fast_cache csa_cache;
+#endif
+
+ void copy(const csa_wt& csa) {
+ m_wavelet_tree = csa.m_wavelet_tree;
+ m_sa_sample = csa.m_sa_sample;
+ m_isa_sample = csa.m_isa_sample;
+ m_alphabet = csa.m_alphabet;
+ }
+
+ public:
+ const typename alphabet_type::char2comp_type& char2comp = m_alphabet.char2comp;
+ const typename alphabet_type::comp2char_type& comp2char = m_alphabet.comp2char;
+ const typename alphabet_type::C_type& C = m_alphabet.C;
+ const typename alphabet_type::sigma_type& sigma = m_alphabet.sigma;
+ const psi_type psi = psi_type(*this);
+ const lf_type lf = lf_type(*this);
+ const bwt_type bwt = bwt_type(*this);
+ const text_type text = text_type(*this);
+ const first_row_type F = first_row_type(*this);
+ const bwt_type L = bwt_type(*this);
+ const isa_type isa = isa_type(*this);
+ const sa_sample_type& sa_sample = m_sa_sample;
+ const isa_sample_type& isa_sample = m_isa_sample;
+ const wavelet_tree_type& wavelet_tree = m_wavelet_tree;
+
+ //! Default constructor
+ csa_wt() {}
+
+ //! Copy constructor
+ csa_wt(const csa_wt& csa) {
+ copy(csa);
+ }
+
+ //! Move constructor
+ csa_wt(csa_wt&& csa) {
+ *this = std::move(csa);
+ }
+
+ //! Constructor taking a cache_config
+ csa_wt(cache_config& config);
+
+ //! Number of elements in the \f$\CSA\f$.
+ /*! Required for the Container Concept of the STL.
+ * \sa max_size, empty
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type size()const {
+ return m_wavelet_tree.size();
+ }
+
+ //! Returns the largest size that csa_wt can ever have.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ static size_type max_size() {
+ return bit_vector::max_size();
+ }
+
+ //! Returns if the data strucutre is empty.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ bool empty()const {
+ return m_wavelet_tree.empty();
+ }
+
+ //! Swap method for csa_wt
+ /*! The swap method can be defined in terms of assignment.
+ This requires three assignments, each of which, for a container type, is linear
+ in the container's size. In a sense, then, a.swap(b) is redundant.
+ This implementation guaranties a run-time complexity that is constant rather than linear.
+ \param csa csa_wt to swap.
+
+ Required for the Assignable Conecpt of the STL.
+ */
+ void swap(csa_wt& csa);
+
+ //! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ * Required for the STL Random Access Container Concept.
+ * \par Time complexity
+ * \f$ \Order{s_{SA}\cdot t_{\Psi}} \f$, where every \f$s_{SA}\f$th suffix array entry is sampled and \f$t_{\Psi}\f$
+ * is the access time for an element in the \f$\Psi\f$-function.
+ */
+ inline value_type operator[](size_type i)const;
+
+ //! Assignment Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ csa_wt& operator=(const csa_wt& csa);
+
+ //! Assignment Move Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ csa_wt& operator=(csa_wt&& csa);
+
+ //! Serialize to a stream.
+ /*! \param out Output stream to write the data structure.
+ * \return The number of written bytes.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ //! Load from a stream.
+ /*! \param in Input stream to load the data structure from.
+ */
+ void load(std::istream& in);
+
+ private:
+
+ // Calculates how many symbols c are in the prefix [0..i-1] of the BWT of the original text.
+ /*
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in [0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the BWT.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ size_type rank_bwt(size_type i, const char_type c)const {
+ return m_wavelet_tree.rank(i, c);
+ }
+
+ // Calculates the position of the i-th c in the BWT of the original text.
+ /*
+ * \param i The i-th occurrence. \f$i\in [1..rank(size(),c)]\f$.
+ * \param c Symbol c.
+ * \returns The position of the i-th c in the BWT or size() if c does occur less then i times.
+ * \par Time complexity
+ * \f$ \Order{t_{\Psi}} \f$
+ */
+ size_type select_bwt(size_type i, const char_type c)const {
+ assert(i > 0);
+ char_type cc = char2comp[c];
+ if (cc==0 and c!=0) // character is not in the text => return size()
+ return size();
+ assert(cc != 255);
+ if (C[cc]+i-1 < C[cc+1]) {
+ return m_wavelet_tree.select(i, c);
+ } else
+ return size();
+ }
+};
+
+// == template functions ==
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::csa_wt(cache_config& config)
+{
+ if (!cache_file_exists(key_trait<alphabet_type::int_width>::KEY_BWT, config)) {
+ return;
+ }
+
+ {
+ auto event = memory_monitor::event("construct csa-alpbabet");
+ int_vector_buffer<alphabet_type::int_width> bwt_buf(cache_file_name(key_trait<alphabet_type::int_width>::KEY_BWT,config));
+ size_type n = bwt_buf.size();
+ alphabet_type tmp_alphabet(bwt_buf, n);
+ m_alphabet.swap(tmp_alphabet);
+ }
+
+ {
+ auto event = memory_monitor::event("construct wavelet tree");
+ int_vector_buffer<alphabet_type::int_width> bwt_buf(cache_file_name(key_trait<alphabet_type::int_width>::KEY_BWT,config));
+ size_type n = bwt_buf.size();
+ wavelet_tree_type tmp_wt(bwt_buf, n);
+ m_wavelet_tree.swap(tmp_wt);
+ }
+
+ {
+ auto event = memory_monitor::event("sample SA");
+ sa_sample_type tmp_sa_sample(config);
+ m_sa_sample.swap(tmp_sa_sample);
+ }
+
+ {
+ auto event = memory_monitor::event("sample ISA");
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config));
+ set_isa_samples<csa_wt>(sa_buf, m_isa_sample);
+ }
+}
+
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+inline auto csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::operator[](size_type i)const -> value_type
+{
+ size_type off = 0;
+while (!m_sa_sample.is_sampled(i)) {
+i = lf[i];
+ ++off;
+}
+value_type result = m_sa_sample.sa_value(i);
+if (result + off < size()) {
+return result + off;
+} else {
+return result + off - size();
+}
+}
+
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+auto csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::operator=(const csa_wt<t_wt,t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa) -> csa_wt& {
+ if (this != &csa) {
+ copy(csa);
+ }
+ return *this;
+}
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+auto csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::operator=(csa_wt<t_wt,t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>&& csa) -> csa_wt& {
+ if (this != &csa) {
+ m_wavelet_tree = std::move(csa.m_wavelet_tree);
+ m_sa_sample = std::move(csa.m_sa_sample);
+ m_isa_sample = std::move(csa.m_isa_sample);
+ m_alphabet = std::move(csa.m_alphabet);
+ }
+ return *this;
+}
+
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+auto csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::serialize(std::ostream& out, structure_tree_node* v, std::string name)const -> size_type
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_wavelet_tree.serialize(out, child, "wavelet_tree");
+ written_bytes += m_sa_sample.serialize(out, child, "sa_samples");
+ written_bytes += m_isa_sample.serialize(out, child, "isa_samples");
+ written_bytes += m_alphabet.serialize(out, child, "alphabet");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+void csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::load(std::istream& in)
+{
+ m_wavelet_tree.load(in);
+ m_sa_sample.load(in);
+ m_isa_sample.load(in);
+ m_alphabet.load(in);
+}
+
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+void csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::swap(csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa)
+{
+ if (this != &csa) {
+ m_wavelet_tree.swap(csa.m_wavelet_tree);
+ m_sa_sample.swap(csa.m_sa_sample);
+ m_isa_sample.swap(csa.m_isa_sample);
+ m_alphabet.swap(csa.m_alphabet);
+ }
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/cst_iterators.hpp b/include/sdsl/cst_iterators.hpp
new file mode 100644
index 0000000..e531a44
--- /dev/null
+++ b/include/sdsl/cst_iterators.hpp
@@ -0,0 +1,343 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file cst_iterators.hpp
+ \brief cst_iterators.hpp contains iterator classes for traversing (compressed) suffix arrays.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CST_ITERATORS
+#define INCLUDED_SDSL_CST_ITERATORS
+
+namespace sdsl
+{
+
+//! An forward iterator for (compressed) suffix trees.
+/*! The cst_dfs_const_forward_iterator iterates through the nodes of a (compressed) suffix tree in
+ depth first search (dfs) order. Note, that
+ - each inner node is visited twice, and
+ - each leaf node is visited only once.
+
+ If the current node is a inner node, the method visit() returns 1 for the first visit and 2 for
+ the second one.
+
+ \par Time complexity
+ \f$\Order{1}\f$ for all methods
+ \par Space complexity
+ \f$\Order{1} \f$
+
+ This iterator is the standard iterator for the classes
+ - sdsl::cst_sada,
+ - sdsl::cst_sct3
+ */
+// TODO: implement operator--
+template<class Cst, uint32_t cache_size=128>
+class cst_dfs_const_forward_iterator: public std::iterator<std::forward_iterator_tag, typename Cst::node_type>
+{
+ public:
+ typedef typename Cst::node_type value_type;
+ typedef const value_type const_reference;
+ typedef typename Cst::size_type size_type;
+ typedef cst_dfs_const_forward_iterator<Cst> iterator;
+ typedef typename Cst::node_type node_type;
+ private:
+ const Cst* m_cst;
+ node_type m_v;
+ bool m_visited;
+ bool m_valid;
+ node_type* m_stack_cache;
+ uint32_t m_stack_size;
+
+
+ inline node_type parent() {
+ --m_stack_size; // decrease stack size
+ if (m_stack_cache != nullptr and m_stack_size < cache_size) {
+ return m_stack_cache[m_stack_size];
+ } else
+ return m_cst->parent(m_v);
+ }
+
+ inline node_type first_child() {
+ if (m_stack_cache != nullptr and m_stack_size < cache_size) // push node to the stack
+ m_stack_cache[ m_stack_size ] = m_v;
+ m_stack_size++;
+ return m_cst->select_child(m_v, 1);
+ }
+
+ //! Default constructor
+ cst_dfs_const_forward_iterator():m_cst(nullptr),m_visited(false),m_valid(false), m_stack_cache(nullptr)
+ {}
+ public:
+
+ //! Constructor
+ cst_dfs_const_forward_iterator(const Cst* cst, const value_type node, bool visited=false, bool valid=true):m_visited(visited), m_valid(valid), m_stack_cache(nullptr) {
+ m_cst = cst;
+ m_v = node;
+ if (m_cst == nullptr) {
+ m_valid = false;
+ } else if (m_v == m_cst->root() and !m_visited and m_valid) { // if the iterator equal cst.begin()
+ m_stack_cache = new node_type[cache_size];
+ m_stack_size = 0;
+// std::cerr<<"#creating stack "<<m_cst->lb(m_v)<<" "<<m_cst->rb(m_v)<<std::endl;
+ }
+ }
+
+ //! Copy Constructor
+// cst_dfs_const_forward_iterator(const cst_dfs_const_forward_iterator &it):m_cst(it.cst),m_v(it.m_v),m_valid(m_valid), m_stack_cache(nullptr),m_stack_size(0){
+// }
+
+ ~cst_dfs_const_forward_iterator() {
+ if (m_stack_cache != nullptr) {
+// std::cerr<<"#deleting stack "<<m_cst->lb(m_v)<<" "<<m_cst->rb(m_v)<<std::endl;
+ delete [] m_stack_cache;
+ }
+ }
+
+ //! Returns how often the current node was already visited.
+ uint8_t visit()const {
+ return 1+(uint8_t)m_visited;
+ }
+
+ void skip_subtree() {
+ if (m_valid) {
+ if (!m_visited) {
+ m_visited = true;
+ }
+ }
+ }
+
+ //! Method for dereferencing the iterator.
+ const_reference operator*()const {
+ return m_v;
+ }
+
+ //! Prefix increment of the iterator.
+ iterator& operator++() {
+ if (!m_valid)
+ return *this;
+ if (m_v == m_cst->root() and m_visited) {
+ m_valid = false;
+ return *this;
+ }
+ value_type w;
+ if (!m_visited) { // go down, if possible
+ if (m_cst->is_leaf(m_v)) {
+ w = m_cst->sibling(m_v); // determine sibling of leaf v
+ if (w == m_cst->root()) { // if there exists no right sibling of the leaf v
+// w = m_cst->parent(m_v);
+ w = parent();
+ m_visited = true; // go up
+ }
+ } else { // v is not a leaf => go down the tree
+ w = first_child();
+ }
+ } else { //
+ w = m_cst->sibling(m_v);
+ if (w == m_cst->root()) { // if there exists no right sibling
+ w = parent();
+ } else {
+ m_visited = false;
+ }
+ }
+ m_v = w;
+ return *this;
+ }
+
+ //! Postfix increment of the iterator.
+ void operator++(int) {
+ ++(*this);
+ }
+
+ //! Equality operator.
+ bool operator==(const iterator& it)const {
+ return (it.m_visited == m_visited) // visited status is equal
+ and (it.m_valid == m_valid) // valid status is equal => for end() iterator
+ and (it.m_v == m_v) // nodes are equal
+ and (it.m_cst == m_cst); // iterator belongs to the same cst
+ }
+
+ //! Inequality operator.
+ bool operator!=(const iterator& it)const {
+ return !(*this==it);
+ }
+
+};
+
+//! A forward iterator for a bottom up traversal of a suffix tree
+template<class Cst>
+class cst_bottom_up_const_forward_iterator: public std::iterator<std::forward_iterator_tag, typename Cst::node_type>
+{
+ public:
+ typedef typename Cst::node_type value_type;
+ typedef const value_type const_reference;
+ typedef typename Cst::size_type size_type;
+ typedef cst_bottom_up_const_forward_iterator<Cst> iterator;
+ private:
+ const Cst* m_cst;
+ typename Cst::node_type m_v;
+ bool m_valid;
+ public:
+
+ //! Default constructor
+ cst_bottom_up_const_forward_iterator():m_cst(nullptr),m_valid(false) {}
+
+ //! Constructor
+ cst_bottom_up_const_forward_iterator(const Cst* cst, const value_type node, bool valid=true):m_valid(valid) {
+ m_cst = cst;
+ m_v = node;
+ if (m_cst == nullptr)
+ m_valid = false;
+ }
+
+ //! Method for dereferencing the iterator.
+ const_reference operator*()const {
+ return m_v;
+ }
+
+ //! Prefix increment of the iterator.
+ iterator& operator++() {
+ if (!m_valid)
+ return *this;
+ if (m_v == m_cst->root()) {
+ m_valid = false;
+ return *this;
+ }
+ value_type w = m_cst->sibling(m_v);
+ if (w == m_cst->root()) { // if no next right sibling exist
+ m_v = m_cst->parent(m_v); // go to parent
+ } else { // if next right sibling exist
+ m_v = m_cst->leftmost_leaf(w); // go to leaftmost leaf in the subtree of w
+ }
+ return *this;
+ }
+
+ //! Postfix increment of the iterator.
+ iterator operator++(int) {
+ iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ //! Equality operator.
+ bool operator==(const iterator& it)const {
+ return (it.m_valid == m_valid) // valid status is equal => for end() iterator
+ and (it.m_v == m_v) // nodes are equal
+ and (it.m_cst == m_cst); // iterator belongs to the same cst
+ }
+
+ //! Inequality operator.
+ bool operator!=(const iterator& it)const {
+ return !(*this==it);
+ }
+
+};
+
+//! A forward iterator for a breath first traversal of a tree
+/*!
+ * \tparam Cst A class which fulfills the CST concept
+ * \tparam Queue A queue for the traversal. Note that for large data,
+ * you should use an external implementation of a queue.
+ */
+template<class Cst, class Queue = std::queue<typename Cst::node_type> >
+class cst_bfs_iterator: public std::iterator<std::forward_iterator_tag, typename Cst::node_type>
+{
+ public:
+ typedef typename Cst::node_type value_type;
+ typedef const value_type const_reference;
+ typedef typename Cst::size_type size_type;
+ typedef cst_bfs_iterator<Cst, Queue> iterator;
+ typedef Queue queue_type;
+ private:
+ const Cst* m_cst; // Pointer to the cst.
+ queue_type m_queue; //
+ bool m_valid; // State of the iterator.
+
+ public:
+
+ //! Constructor
+ /*!
+ * \param cst Pointer to the compressed suffix tree.
+ * \param node Root node of the traversal.
+ * \param valid State of the iterator.
+ * \param end If valid=true and end=true, we get the end() iterator otherwise ``end'' has no effect.
+ */
+ cst_bfs_iterator(const Cst* cst, const value_type node, bool valid=true, bool end_it=false) {
+ m_cst = cst;
+ m_valid = valid;
+ if (m_cst != nullptr and !end_it) {
+ m_queue.push(node);
+ }
+ }
+
+ //! Returns the current number of nodes in the queue.
+ size_type size()const {
+ return m_queue.size();
+ }
+
+ //! Method for dereferencing the iterator.
+ const_reference operator*()const {
+ return m_queue.front();
+ }
+
+ //! Prefix increment of the iterator.
+ iterator& operator++() {
+ if (!m_valid)
+ return *this;
+ if (m_queue.empty()) {
+ m_valid = false;
+ return *this;
+ }
+ value_type v = m_queue.front();
+ m_queue.pop();
+ value_type child = m_cst->select_child(v, 1);
+ while (m_cst->root() != child) {
+ m_queue.push(child);
+ child = m_cst->sibling(child);
+ }
+ return *this;
+ }
+
+ //! Postfix increment of the iterator.
+ iterator operator++(int) {
+ iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ //! Equality operator.
+ bool operator==(const iterator& it)const {
+ if (m_queue.size() != it.m_queue.size()) { // if the queue size is different
+ return false; // the state of the to iterator are different
+ }
+ if (m_queue.empty()) { // if the queue is empty, we have to check if they are valid and
+ return it.m_valid == m_valid and it.m_cst == m_cst; // belong to the same cst
+ }
+ return (it.m_valid == m_valid) // valid status is equal => for end() iterator
+ and (it.m_cst == m_cst) // iterator belongs to the same cst
+ and (it.m_queue.front() == m_queue.front()) // front element and
+ and (it.m_queue.back() == m_queue.back()); // back element are the same.
+ }
+
+ //! Inequality operator.
+ bool operator!=(const iterator& it)const {
+ return !(*this==it);
+ }
+
+};
+
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/cst_sada.hpp b/include/sdsl/cst_sada.hpp
new file mode 100644
index 0000000..22e7d4a
--- /dev/null
+++ b/include/sdsl/cst_sada.hpp
@@ -0,0 +1,796 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file cst_sada.hpp
+ \brief cst_sada.hpp contains an implementation of Sadakane's CST.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CST_SADA
+#define INCLUDED_SDSL_CST_SADA
+
+#include "int_vector.hpp"
+#include "suffix_tree_helper.hpp"
+#include "iterators.hpp"
+#include "lcp_support_sada.hpp"
+#include "select_support_mcl.hpp"
+#include "bp_support.hpp"
+#include "bp_support_sada.hpp"
+#include "csa_sada.hpp" // for std initialization of cst_sada
+#include "cst_iterators.hpp"
+#include "cst_sct3.hpp" // this CST is used in the construction
+#include "util.hpp"
+#include <iostream>
+#include <algorithm>
+#include <cassert>
+#include <cstring> // for strlen
+#include <iomanip>
+#include <iterator>
+
+namespace sdsl
+{
+
+//! A class for the Compressed Suffix Tree (CST) proposed by Sadakane.
+/*!
+ * \tparam t_csa Type of a CSA (member of this type is accessible via
+ * member `csa`, default class is sdsl::csa_sada).
+ * \tparam t_lcp Type of a LCP structure (member is accessible via member
+ * `lcp`, default class is sdsl::lcp_support_sada),
+ * \tparam t_bp_support Type of a BPS structure (member accessible via member
+ * `bp_support`, default class is sdsl::bp_support_sada),
+ * \tparam t_rank_10 Type of a rank structure for the 2-bit pattern `10`
+ * (accessible via member `bp_rank_10`, default class is
+ * sdsl::rank_support_v5)
+ * \tparam t_select_10 Type of a select structure for the 2-bit pattern `10`
+ * (accessible via member \f$bp\_select\_10\f$, default
+ * class is sdsl::select_support_mcl).
+ *
+ * It also contains a sdsl::bit_vector which represents the balanced
+ * parentheses sequence of the suffix tree. This bit_vector can be accessed
+ * via member `bp`.
+ *
+ * A node `v` of the `csa_sada` is represented by an integer `i` which
+ * corresponds to the position of the opening parenthesis of the parentheses
+ * pair \f$(i,\mu(i))\f$ that corresponds to `v` in `bp`.
+ *
+ * \par Reference
+ * Kunihiko Sadakane:
+ * Compressed Suffix Trees with Full Functionality.
+ * Theory Comput. Syst. 41(4): 589-607 (2007)
+ *
+ * @ingroup cst
+ */
+template<class t_csa = csa_sada<>,
+ class t_lcp = lcp_support_sada<>,
+ class t_bp_support = bp_support_sada<>,
+ class t_rank_10 = rank_support_v5<10,2>,
+ class t_select_10 = select_support_mcl<10,2>
+ >
+class cst_sada
+{
+ public:
+ typedef cst_dfs_const_forward_iterator<cst_sada> const_iterator;
+ typedef cst_bottom_up_const_forward_iterator<cst_sada> const_bottom_up_iterator;
+ typedef typename t_csa::size_type size_type;
+ typedef ptrdiff_t difference_type;
+ typedef t_csa csa_type;
+ typedef typename t_lcp::template type<cst_sada> lcp_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::string_type string_type;
+ typedef size_type node_type; //!< Type for the nodes in the tree.
+ typedef t_bp_support bp_support_type;
+ typedef t_rank_10 rank_10_type;
+ typedef t_select_10 select_10_type;
+
+ typedef typename t_csa::alphabet_type::comp_char_type comp_char_type;
+ typedef typename t_csa::alphabet_type::sigma_type sigma_type;
+
+ typedef typename t_csa::alphabet_category alphabet_category;
+ typedef cst_tag index_category;
+ private:
+ t_csa m_csa; // suffix array
+ lcp_type m_lcp; // lcp information
+ bit_vector m_bp; // balanced parentheses sequence for suffix tree
+ bp_support_type m_bp_support; // support for the balanced parentheses sequence
+ rank_10_type m_bp_rank10; // rank_support for leaves, i.e. "10" bit pattern
+ select_10_type m_bp_select10;// select_support for leaves, i.e. "10" bit pattern
+
+ /* Get the number of leaves that are in the subtree rooted at the first child of v +
+ * number of leafs in the subtrees rooted at the children of parent(v) which precede v in the tree.
+ */
+ size_type inorder(node_type v)const {
+ return m_bp_rank10(m_bp_support.find_close(v+1)+1);
+ }
+
+ void copy(const cst_sada& cst) {
+ m_csa = cst.m_csa;
+ copy_lcp(m_lcp, cst.m_lcp, *this);
+ m_bp = cst.m_bp;
+ m_bp_support = cst.m_bp_support;
+ m_bp_support.set_vector(&m_bp);
+ m_bp_rank10 = cst.m_bp_rank10;
+ m_bp_rank10.set_vector(&m_bp);
+ m_bp_select10 = cst.m_bp_select10;
+ m_bp_select10.set_vector(&m_bp);
+ }
+
+ public:
+ const t_csa& csa = m_csa;
+ const lcp_type& lcp = m_lcp;
+ const bit_vector& bp = m_bp;
+ const bp_support_type& bp_support = m_bp_support;
+ const rank_10_type& bp_rank_10 = m_bp_rank10;
+ const select_10_type& bp_select_10 = m_bp_select10;
+
+//! Default constructor
+ cst_sada() { }
+
+
+//! Copy constructor
+ cst_sada(const cst_sada& cst) {
+ copy(cst);
+ }
+
+//! Move constructor
+ cst_sada(cst_sada&& cst) {
+ *this = std::move(cst);
+ }
+
+//! Construct CST from file_map
+ cst_sada(cache_config& config) {
+ {
+ auto event = memory_monitor::event("bps-dfs");
+ cst_sct3<> temp_cst(config, true);
+ m_bp.resize(4*(temp_cst.bp.size()/2));
+ util::set_to_value(m_bp, 0);
+ size_type idx=0;
+ for (cst_sct3<>::const_iterator it=temp_cst.begin(), end=temp_cst.end(); it!=end; ++it) {
+ if (1 == it.visit())
+ m_bp[idx] = 1;
+ if (temp_cst.is_leaf(*it) and temp_cst.root()!= *it)
+ ++idx;
+ ++idx;
+ }
+ m_bp.resize(idx);
+ }
+ {
+ auto event = memory_monitor::event("bpss-dfs");
+ util::assign(m_bp_support, bp_support_type(&m_bp));
+ util::init_support(m_bp_rank10, &m_bp);
+ util::init_support(m_bp_select10, &m_bp);
+ }
+ {
+ auto event = memory_monitor::event("clcp");
+ cache_config tmp_config(false, config.dir, config.id, config.file_map);
+ construct_lcp(m_lcp, *this, tmp_config);
+ config.file_map = tmp_config.file_map;
+ }
+ {
+ auto event = memory_monitor::event("load csa");
+ load_from_cache(m_csa,std::string(conf::KEY_CSA)+"_"+util::class_to_hash(m_csa), config);
+ }
+ }
+
+//! Number of leaves in the suffix tree.
+ /*! Required for the Container Concept of the STL.
+ * \sa max_size, empty
+ */
+ size_type size()const {
+ return m_csa.size();
+ }
+
+//! Returns the maximal lenght of text for that a suffix tree can be build.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ static size_type max_size() {
+ return t_csa::max_size();
+ }
+
+//! Returns if the data strucutre is empty.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ bool empty()const {
+ return m_csa.empty();
+ }
+
+//! Swap method for cst_sada
+ /*! The swap method can be defined in terms of assignment.
+ This requires three assignments, each of which, for a container type, is linear
+ in the container's size. In a sense, then, a.swap(b) is redundant.
+ This implementation guaranties a run-time complexity that is constant rather than linear.
+ \param cst cst_sada to swap.
+
+ Required for the Assignable Conecpt of the STL.
+ */
+ void swap(cst_sada& cst) {
+ if (this != &cst) {
+ m_csa.swap(cst.m_csa);
+ m_bp.swap(cst.m_bp);
+ util::swap_support(m_bp_support, cst.m_bp_support, &m_bp, &(cst.m_bp));
+ util::swap_support(m_bp_rank10, cst.m_bp_rank10, &m_bp, &(cst.m_bp));
+ util::swap_support(m_bp_select10, cst.m_bp_select10, &m_bp, &(cst.m_bp));
+ // anything else has to be swapped before swapping lcp
+ swap_lcp(m_lcp, cst.m_lcp, *this, cst);
+ }
+ }
+
+//! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ if (0 == m_bp.size()) // special case: tree is uninitialized
+ return end();
+ return const_iterator(this, root(), false, true);
+ }
+
+ //! Returns a const_iterator to the first element of a depth first traversal of the subtree rooted at node v.
+ const_iterator begin(const node_type& v)const {
+ if (0 == m_bp.size() and root()==v)
+ return end();
+ return const_iterator(this, v, false, true);
+ }
+
+//! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, root(), true, false);
+ }
+
+ //! Returns a const_iterator to the element past the end of a depth first traversal of the subtree rooted at node v.
+ const_iterator end(const node_type& v)const {
+ if (root() == v)
+ return end();
+ return ++const_iterator(this, v, true, true);
+ }
+
+//! Returns an iterator to the first element of a bottom-up traversal of the tree.
+ const_bottom_up_iterator begin_bottom_up()const {
+ if (0 == m_bp.size()) // special case: tree is uninitialized
+ return end_bottom_up();
+ return const_bottom_up_iterator(this, leftmost_leaf(root()));
+ }
+
+//! Returns an iterator to the element after the last element of a bottom-up traversal of the tree.
+ const_bottom_up_iterator end_bottom_up()const {
+ return const_bottom_up_iterator(this, root(), false);
+ }
+
+//! Assignment Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ cst_sada& operator=(const cst_sada& cst) {
+ if (this != &cst) {
+ copy(cst);
+ }
+ return *this;
+ }
+
+//! Assignment Move Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ cst_sada& operator=(cst_sada&& cst) {
+ if (this != &cst) {
+ m_csa = std::move(cst.m_csa);
+ move_lcp(m_lcp, cst.m_lcp, *this);
+ m_bp = std::move(cst.m_bp);
+ m_bp_support = std::move(cst.m_bp_support);
+ m_bp_support.set_vector(&m_bp);
+ m_bp_rank10 = std::move(cst.m_bp_rank10);
+ m_bp_rank10.set_vector(&m_bp);
+ m_bp_select10 = std::move(cst.m_bp_select10);
+ m_bp_select10.set_vector(&m_bp);
+ }
+ return *this;
+ }
+
+//! Serialize to a stream.
+ /*! \param out Outstream to write the data structure.
+ * \return The number of written bytes.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_csa.serialize(out, child, "csa");
+ written_bytes += m_lcp.serialize(out, child, "lcp");
+ written_bytes += m_bp.serialize(out, child, "bp");
+ written_bytes += m_bp_support.serialize(out, child, "bp_support");
+ written_bytes += m_bp_rank10.serialize(out, child, "bp_rank_10");
+ written_bytes += m_bp_select10.serialize(out, child, "bp_select_10");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+//! Load from a stream.
+ /*! \param in Inputstream to load the data structure from.
+ */
+ void load(std::istream& in) {
+ m_csa.load(in);
+ load_lcp(m_lcp, in, *this);
+ m_bp.load(in);
+ m_bp_support.load(in, &m_bp);
+ m_bp_rank10.load(in, &m_bp);
+ m_bp_select10.load(in, &m_bp);
+ }
+
+ /*! \defgroup cst_sada_tree_methods Tree methods of cst_sada */
+ /* @{ */
+
+//! Return the root of the suffix tree.
+ /*!
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type root() const {
+ return 0;
+ }
+
+//! Decide if a node is a leaf in the suffix tree.
+ /*!
+ * \param v A valid node of a cst_sada.
+ * \returns A boolean value indicating if v is a leaf.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ bool is_leaf(node_type v)const {
+ assert(m_bp[v]==1); // assert that v is a valid node of the suffix tree
+ // if there is a closing parenthesis at position v+1, the node is a leaf
+ return !m_bp[v+1];
+ }
+
+//! Return the i-th leaf (1-based from left to right) of the suffix tree.
+ /*!
+ * \param i 1-based position of the leaf. \f$1\leq i\leq csa.size()\f$.
+ * \return The i-th leave.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \pre \f$ 1 \leq i \leq csa.size() \f$
+ */
+ node_type select_leaf(size_type i)const {
+ assert(i > 0 and i <= m_csa.size());
+ // -1 as select(i) returns the postion of the 0 of pattern 10
+ return m_bp_select10.select(i)-1;
+ }
+
+//! Returns the depth of node v.
+ /*!
+ * \param v A valid node of the suffix tree.
+ * \return The depth of the node.
+ * \par Time complexity
+ * \f$ \Order{\lcpaccess \vee \saaccess} \f$
+ */
+ size_type depth(node_type v)const {
+ if (v == root()) // if v is the root
+ return 0;
+
+ if (is_leaf(v)) { // if v is a leave
+ size_type i = m_bp_rank10(v); // get the index in the suffix array
+ return m_csa.size() - m_csa[i];
+ }
+ assert(inorder(v)>0);
+ return m_lcp[inorder(v)];
+ }
+
+//! Returns the node depth of node v.
+ /*!
+ * \param v A valid node of a cst_sada.
+ * \return The node depth of node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type node_depth(node_type v)const {
+ // -2 as the root() we assign depth=0 to the root
+ return (m_bp_support.rank(v)<<1)-v-2;
+ }
+
+//! Calculate the number of leaves in the subtree rooted at node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The number of leaves in the subtree rooted at node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ *
+ * This method is used e.g. in the count method.
+ */
+ size_type size(node_type v)const {
+ size_type r = m_bp_support.find_close(v);
+ return m_bp_rank10(r+1) - m_bp_rank10(v);
+ }
+
+//! Calculates the leftmost leaf in the subtree rooted at node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The leftmost leaf in the subtree rooted at node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type leftmost_leaf(const node_type v)const {
+ return m_bp_select10(m_bp_rank10(v)+1)-1;
+ }
+
+//! Calculates the rightmost leaf in the subtree rooted at node v.
+ /*!\param v A valid node of the suffix tree.
+ * \return The rightmost leaf in the subtree rooted at node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type rightmost_leaf(const node_type v)const {
+ size_type r = m_bp_support.find_close(v);
+ return m_bp_select10(m_bp_rank10(r+1))-1;
+ }
+
+//!Calculates the index of the leftmost leaf in the corresponding suffix array.
+ /*!\param v A valid node of the suffix tree.
+ * \return The index of the leftmost leaf in the corresponding suffix array.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \par Note
+ * lb is an abbreviation for ,,left bound''
+ */
+ size_type lb(const node_type v)const {
+ return m_bp_rank10(v);
+ }
+
+//! Calculates the index of the rightmost leaf in the corresponding suffix array.
+ /*! \param v A valid node of the suffix tree.
+ * \return The index of the rightmost leaf in the corresponding suffix array.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \par Note
+ * rb is an abbreviation for ,,right bound''
+ */
+ size_type rb(const node_type v)const {
+ size_type r = m_bp_support.find_close(v);
+ return m_bp_rank10(r+1)-1;
+ }
+
+//! Calculate the parent node of a node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The parent node of v or root() if v equals root().
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type parent(node_type v) const {
+ assert(m_bp[v]==1); // assert a valid node
+ if (v == root())
+ return root();
+ else {
+ return m_bp_support.enclose(v);
+ }
+ }
+
+ //! Return a proxy object which allows iterating over the children of a node
+ /*! \param v A valid node of the suffix tree.
+ * \return The proxy object of v containing all children
+ * \par Time complexity
+ * \f$ \Order{1}\f$
+ */
+ cst_node_child_proxy<cst_sada> children(node_type v) const {
+ return cst_node_child_proxy<cst_sada>(this,v);
+ }
+
+
+//! Returns the next sibling of node v.
+ /*!
+ * \param v A valid node v of the suffix tree.
+ * \return The next (right) sibling of node v or root() if v has no next (right) sibling.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type sibling(node_type v)const {
+ if (v==root())
+ return root();
+ node_type sib = m_bp_support.find_close(v)+1;
+ if (m_bp[sib])
+ return sib;
+ else
+ return root();
+ }
+
+//! Get the child w of node v which edge label (v,w) starts with character c.
+ /*
+ * \param v A valid tree node of the cst.
+ * \param c First character of the edge label from v to the desired child.
+ * \param char_pos Reference which will hold the position (0-based) of the matching char c in the sorted text/suffix array.
+ * \return The child node w which edge label (v,w) starts with c or root() if it does not exist.
+ * \par Time complexity
+ * \f$ \Order( (\saaccess+\isaaccess) \cdot \sigma + \lcpaccess) \f$
+ * \par Note
+ * With range median mimimum queries (RMMQ) one can code this operation in \f$\log \sigma \f$ time
+ */
+ node_type child(node_type v, const char_type c, size_type& char_pos)const {
+ if (is_leaf(v)) // if v is a leaf = (), v has no child
+ return root();
+ // else v = ( ( ))
+ comp_char_type cc = m_csa.char2comp[c];
+ if (cc==0 and c!=0) // TODO: aendere char2comp so ab, dass man diesen sonderfall nicht braucht
+ return root();
+ size_type char_ex_max_pos = m_csa.C[cc+1], char_inc_min_pos = m_csa.C[cc];
+
+ size_type d = depth(v); // time complexity: \lcpaccess
+ size_type res = v+1;
+ while (true) {
+ if (is_leaf(res)) {
+ char_pos = get_char_pos(m_bp_rank10(res), d, m_csa);
+ } else {
+ char_pos = get_char_pos(inorder(res), d, m_csa);
+ }
+ if (char_pos >= char_ex_max_pos) // if the current char is lex. greater than the searched char: exit
+ return root();
+ if (char_pos >= char_inc_min_pos) // if the current char is lex. equal with the
+ return res;
+ res = m_bp_support.find_close(res)+1;
+ if (!m_bp[res]) // closing parenthesis: there exists no next child
+ return root();
+ }
+ }
+
+//! Get the child w of node v which edge label (v,w) starts with character c.
+// \sa child(node_type v, const char_type c, size_type &char_pos)
+ node_type child(node_type v, const char_type c) {
+ size_type char_pos;
+ return child(v, c, char_pos);
+ }
+
+//! Get the i-th child of a node v.
+ /*!
+ * \param v A valid tree node of the cst.
+ * \param i 1-based Index of the child which should be returned. \f$i \geq 1\f$.
+ * \return The i-th child node of v or root() if v has no i-th child.
+ * \par Time complexity
+ * \f$ \Order{i} \f$ for \f$ i \leq \sigma \f$
+ * \pre \f$ 1 \leq i \leq degree(v) \f$
+ */
+ node_type select_child(node_type v, size_type i)const {
+ if (is_leaf(v)) // if v is a leave, v has no child
+ return root();
+ size_type res = v+1;
+ while (i > 1) {
+ res = m_bp_support.find_close(res)+1;
+ if (!m_bp[res]) {// closing parenthesis: there exists no next child
+ return root();
+ }
+ --i;
+ }
+ return res;
+ }
+
+//! Returns the d-th character (1-based indexing) of the edge-label pointing to v.
+ /*!\param v The node at which the edge path ends.
+ * \param d The position (1-based indexing) of the requested character on the edge path from the root to v. \f$ d > 0 \wedge d <= depth(v) \f$
+ * \return The character at position d on the edge path from the root to v.
+ * \par Time complexity
+ * \f$ \Order{ \log\sigma + (\saaccess+\isaaccess) } \f$
+ * \pre \f$ 1 \leq d \leq depth(v) \f$
+ */
+ char_type edge(node_type v, size_type d)const {
+ assert(1 <= d);
+ assert(d <= depth(v));
+ size_type i = 0;// index of the first suffix in the subtree of v
+ if (is_leaf(v)) { // if v is a leave
+ i = m_bp_rank10(v); // get the index in the suffix array
+ } else {
+ i = inorder(v);
+ }
+ size_type order = get_char_pos(i, d-1, m_csa);
+ size_type c_begin = 1, c_end = ((size_type)m_csa.sigma)+1, mid;
+ while (c_begin < c_end) {
+ mid = (c_begin+c_end)>>1;
+ if (m_csa.C[mid] <= order) {
+ c_begin = mid+1;
+ } else {
+ c_end = mid;
+ }
+ }
+ return m_csa.comp2char[c_begin-1];
+ }
+
+//! Calculate the lowest common ancestor (lca) of two nodes v and w of the suffix tree.
+ /*!
+ * \param v The first node for which the lca with the second node should be computed.
+ * \param w The second node for which the lca with the first node should be computed.
+ * \return A node that is the lowest common ancestor of v and w in the suffix tree.
+ * \par Time complexity
+ * \f$ \Order{\rrenclose}\ \f$
+ */
+ node_type lca(node_type v, node_type w)const {
+ assert(m_bp[v] == 1 and m_bp[w] == 1);
+ if (v > w) {
+ std::swap(v,w);
+ } else if (v==w) {
+ return v;
+ }
+ if (v == root())
+ return root();
+ return m_bp_support.double_enclose(v, w);
+ }
+
+//! Compute the suffix link of node v.
+ /*!
+ * \param v A valid node of a cst_sada.
+ * \return The suffix link of node v.
+ * \par Time complexity
+ * \f$ \Order{ 1 } \f$
+ */
+ node_type sl(node_type v)const {
+ if (v == root())
+ return root();
+ // get leftmost leaf in the tree rooted at v
+ size_type left = m_bp_rank10(v);
+ if (is_leaf(v)) {
+ return select_leaf(m_csa.psi[left]+1);
+ }
+ // get the rightmost leaf in the tree rooted at v
+ size_type right = m_bp_rank10(m_bp_support.find_close(v))-1;
+ assert(left < right);
+ node_type left_leaf = select_leaf(m_csa.psi[left]+1);
+ node_type right_leaf= select_leaf(m_csa.psi[right]+1);
+ return lca(left_leaf, right_leaf);
+ }
+
+//! Compute the Weiner link of node v and character c.
+ /*
+ * \param v A valid not of a cst_sada.
+ * \param c The character which should be prepended to the string of the current node.
+ * \return root() if the Weiner link of (v, c) does not exist, otherwise the Weiner link is returned.
+ * \par Time complexity
+ * \f$ \Order{ t_{rank\_bwt} + t_{lca}}\f$
+ */
+ node_type wl(node_type v, const char_type c) const {
+ // get leftmost leaf in the tree rooted at v
+ size_type left = m_bp_rank10(v);
+ // get the rightmost leaf in the tree rooted at v
+ size_type right = is_leaf(v) ? left : m_bp_rank10(m_bp_support.find_close(v))-1;
+
+ size_type c_left = m_csa.bwt.rank(left, c);
+ size_type c_right = m_csa.bwt.rank(right+1, c);
+
+ if (c_left == c_right) // there exists no Weiner link
+ return root();
+ if (c_left+1 == c_right)
+ return select_leaf(m_csa.C[m_csa.char2comp[c]] + c_left + 1);
+ else {
+ size_type left = m_csa.C[m_csa.char2comp[c]] + c_left;
+ size_type right = m_csa.C[m_csa.char2comp[c]] + c_right - 1;
+ assert(left < right);
+ node_type left_leaf = select_leaf(left+1);
+ node_type right_leaf= select_leaf(right+1);
+ return lca(left_leaf, right_leaf);
+ }
+ }
+
+//! Compute the suffix number of a leaf node v.
+ /*!\param v A valid leaf node of a cst_sada.
+ * \return The suffix array value corresponding to the leaf node v.
+ * \par Time complexity
+ * \f$ \Order{ \saaccess } \f$
+ */
+ size_type sn(node_type v)const {
+ assert(is_leaf(v));
+ // count the leaves left to leaf v
+ return m_csa[m_bp_rank10(v)];
+ }
+
+//! Computes a unique identification number for a node of the suffix tree in the range [0..nodes()-1]
+ /*!
+ *\param v A valid node of a cst_sada.
+ * \return A unique identification number for the node v in the range [0..nodes()-1]
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \sa inv_id(size_type id)
+ */
+ size_type id(node_type v)const {
+ // v+1 is < m_bp.size(), as v is the position of an open parenthesis
+ if (m_bp[v+1]) { // case (a) inner node
+ return size() + (m_bp_support.rank(v) - 1) - m_bp_rank10(v);
+ } else { // case (b) leaf
+ return m_bp_rank10(v);
+ }
+ }
+
+//! Computes the node for such that id(v)=id.
+ /*!
+ * \param id An id in the range [0..nodes()-1].
+ * \return A node v of the CST such that id(v)=id.
+ * \par Time complexity
+ * \f$ \Order{1} \f$ for leaves and \f$ \log n \f$ for inner nodes
+ * \sa id(node_type v)
+ */
+ size_type inv_id(size_type id) {
+ if (id < size()) { // the corresponding node is a leaf
+ return select_leaf(id+1);
+ } else { // the corresponding node is a inner node
+ id = id + 1 - size();
+ // solved by binary search; TODO: can be done in constant time by using a select structure on the bitpattern 11
+ size_type lb = 0, rb = m_bp.size(); // lb inclusive, rb exclusive
+ // invariant: arg(lb) < id, arg(rb)>= id
+ while (rb-lb > 1) {
+ size_type mid = lb + (rb-lb)/2; // mid \in [0..m_bp.size()-1]
+ if (m_bp[mid] == 0 and m_bp[mid-1] == 1) { // if we are ``half on a leaf''
+ ++mid; //we step one to the right to include it
+ }
+ // get the number of open inner nodes before position mid, i.e. arg(mid)
+ size_type mid_id = m_bp_support.rank(mid-1) - m_bp_rank10(mid); // Note: mid-1 is valid of mid is of type ``size_type'' as us the parameter of rank
+ if (mid_id < id) {
+ lb = mid;
+ } else { // mid_id >= x
+ rb = mid;
+ }
+ }
+ return lb;
+ }
+ }
+
+//! Get the number of nodes of the suffix tree.
+ /*
+ * \return The number of nodes of the suffix tree.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type nodes()const {
+ return m_bp.size()>>1;
+ }
+
+//! Get the node in the suffix tree which corresponds to the lcp-interval [lb..rb]
+ /* \param lb Left bound of the lcp-interval [lb..rb] (inclusive).
+ * \param rb Right bound of the lcp-interval [lb..rb] (inclusive).
+ *\ return The node in the suffix tree corresponding lcp-interval [lb..rb]
+ */
+ node_type node(size_type lb, size_type rb) const {
+ return lca(select_leaf(lb+1), select_leaf(rb+1));
+ }
+
+//! Get the number of children of a node v.
+ /*!
+ * \param v A valid node v of a cst_sada.
+ * \returns The number of children of node v.
+ * \par Time complexity
+ * \f$ \Order{\sigma} \f$
+ */
+ size_type degree(node_type v)const {
+ size_type res = 0;
+ v = v+1;
+ while (m_bp[v]) { // found open parentheses
+ ++res;
+ v = m_bp_support.find_close(v)+1;
+ }
+ return res;
+ }
+
+//! Maps an index i to the position in TLCP where LCP[i] can be found
+ /*!
+ * \param i The index in the LCP array
+ * \return The corresponding position in the TLCP array
+ */
+ size_type tlcp_idx(size_type i) const {
+ size_type ii = 0;
+ if (i > 0) {
+ size_type ipos = m_bp_select10(i) - 1; // -1 as select returns the position of the zero
+ size_type ip1pos = m_bp_select10(i+1) - 1;// " " " " " " " " "
+ ii = m_bp_support.double_enclose(ipos, ip1pos);
+ }
+ ii = m_bp_support.find_close(ii);
+ // all right, as bp[ii] = 0
+ return ii - m_bp_support.rank(ii) - m_bp_rank10(ii);
+ }
+ /* @} */
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/cst_sct3.hpp b/include/sdsl/cst_sct3.hpp
new file mode 100644
index 0000000..b8c3ae1
--- /dev/null
+++ b/include/sdsl/cst_sct3.hpp
@@ -0,0 +1,1238 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file cst_sct3.hpp
+ \brief cst_sct3.hpp contains an implementation of the interval based CST.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CST_SCT3
+#define INCLUDED_SDSL_CST_SCT3
+
+#include "int_vector.hpp"
+#include "suffix_tree_helper.hpp"
+#include "iterators.hpp"
+#include "lcp.hpp"
+#include "bp_support.hpp"
+#include "csa_wt.hpp" // for std initialization of cst_sct3
+#include "cst_iterators.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "util.hpp"
+#include "sdsl_concepts.hpp"
+#include <iostream>
+#include <algorithm>
+#include <cassert>
+#include <cstring> // for strlen
+#include <iomanip>
+#include <iterator>
+#include <stack> // for the calculation of the balanced parentheses sequence
+#include <ostream>
+#include <type_traits>
+
+namespace sdsl
+{
+
+// Declaration of the CST's node type
+template<class t_int = int_vector<>::size_type>
+struct bp_interval;
+
+//! A class for the Compressed Suffix Tree (CST) proposed by Ohlebusch and Gog.
+/*!
+ * \tparam t_csa Type of a CSA (member of this type is accessible via
+ * member `csa`, default class is sdsl::csa_sada).
+ * \tparam t_lcp Type of a LCP structure (member is accessible via member
+ * `lcp`, default class is sdsl::lcp_support_sada),
+ * \tparam t_bp_support Type of a BPS structure (member accessible via member
+ * `bp_support`, default class is sdsl::bp_support_sada),
+ * \tparam t_rank Type of rank structure which supports the bitvector
+ * which indicates the leftmost child of the nodes.
+ *
+ * It also contains a sdsl::bit_vector which represents the BP sequence of the
+ * Super-Cartesian tree of the LCP array. This bitvector can be accessed via
+ * the member `bp`. Another sdsl::bit_vector stores information, if a node is
+ * the leftmost child of another node. This bitvector can be access via the
+ * member first_child_bv and takes n bits.
+ *
+ * A node \f$v\f$ of the csa_sct is represented by an sdsl::bp_interval. The
+ * size of the sdsl::cst_sct3 is smaller than the size of a sdsl::cst_sada
+ * since the tree topology needs only \f$2n+n=3n\f$ bits in contrast to the
+ * \f$4n\f$ bits in sdsl::cst_sada.
+ *
+ * \par Reference
+ * Enno Ohlebusch, Johannes Fischer, Simon Gog:
+ * CST++.
+ * SPIRE 2010: 322-333
+ *
+ * \par Applications of the CST
+ * The compressed suffix tree could be used for string matching and many other
+ * application in sequence analysis. 17 applications are in the book
+ * "Algorithms on Strings, Trees, and Sequences" of Dan Gusfield.
+ *
+ * @ingroup cst
+ */
+template<class t_csa = csa_wt<>,
+ class t_lcp = lcp_dac<>,
+ class t_bp_support = bp_support_sada<>,
+ class t_bv = bit_vector,
+ class t_rank = typename std::conditional<
+ std::is_same<t_bv, bit_vector>::value,
+ rank_support_v5<>, typename t_bv::rank_1_type
+ >::type,
+ class t_sel = typename std::conditional<
+ std::is_same<t_bv, bit_vector>::value and
+ std::is_same<typename t_csa::alphabet_category, byte_alphabet_tag>::value,
+ select_support_scan<>, typename t_bv::select_1_type
+ >::type
+ >
+class cst_sct3
+{
+ public:
+ typedef cst_dfs_const_forward_iterator<cst_sct3> const_iterator;
+ typedef cst_bottom_up_const_forward_iterator<cst_sct3> const_bottom_up_iterator;
+ typedef typename t_csa::size_type size_type;
+ typedef ptrdiff_t difference_type;
+ typedef t_csa csa_type;
+ typedef typename t_lcp::template type<cst_sct3> lcp_type;
+ typedef t_bp_support bp_support_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::string_type string_type;
+ typedef bp_interval<size_type> node_type; //!< Type for the nodes in the tree
+ typedef t_bv bv_type;
+ typedef t_rank rank_type;
+ typedef t_sel sel_type;
+
+ typedef typename t_csa::alphabet_type::comp_char_type comp_char_type;
+ typedef typename t_csa::alphabet_type::sigma_type sigma_type;
+
+ typedef typename t_csa::alphabet_category alphabet_category;
+ typedef cst_tag index_category;
+ private:
+ csa_type m_csa;
+ lcp_type m_lcp;
+ bit_vector m_bp;
+ bp_support_type m_bp_support;
+ bv_type m_first_child;
+ rank_type m_first_child_rank;
+ sel_type m_first_child_select;
+ size_type m_nodes;
+
+ void copy(const cst_sct3& cst) {
+ m_csa = cst.m_csa;
+ copy_lcp(m_lcp, cst.m_lcp, *this);
+ m_bp = cst.m_bp;
+ m_bp_support = cst.m_bp_support;
+ m_bp_support.set_vector(&m_bp);
+ m_first_child = cst.m_first_child;
+ m_first_child_rank = cst.m_first_child_rank;
+ m_first_child_rank.set_vector(&m_first_child);
+ m_first_child_select = cst.m_first_child_select;
+ m_first_child_select.set_vector(&m_first_child);
+ m_nodes = cst.m_nodes;
+ }
+
+ // Get the first l index of a [i,j] interval.
+ /* I.e. given an interval [i,j], the function returns the position of
+ * the smallest entry lcp[k] with \f$ i<k\leq j \f$
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ inline size_type first_l_index(const node_type& node, size_type& kpos, size_type& ckpos)const {
+ if (node.cipos > node.jp1pos) { // corresponds to m_lcp[i] <= m_lcp[j+1]
+ ckpos = node.jp1pos-1;
+ } else { // corresponds to m_lcp[i] > m_lcp[j+1]
+ ckpos = node.cipos-1;
+ }
+ assert(m_bp[ckpos]==0);
+ kpos = m_bp_support.find_open(ckpos);
+ return m_bp_support.rank(kpos)-1;
+ }
+
+ // Get the i-th l-index of a node
+ // if there exists no ith l-index return node.j+1
+ /* \param v Node
+ * \param i l-index in [1..degree()]
+ * \paran
+ */
+ size_type select_l_index(const node_type& v, size_type i, size_type& kpos, size_type& ckpos)const {
+ assert(i > 0);
+ if (v.cipos > v.jp1pos) { // corresponds to m_lcp[i] <= m_lcp[j+1]
+ ckpos = v.jp1pos-1;
+ } else { // corresponds to m_lcp[i] > m_lcp[j+1]
+ ckpos = v.cipos-1;
+ }
+ assert(m_bp[ckpos] == 0); // at least the first l-index should be present, i.e. node is not leaf
+ if (1 == i) {
+ kpos = m_bp_support.find_open(ckpos);
+ return m_bp_support.rank(kpos)-1;
+ } else { // i > 1
+ // numbers of closing parentheses - 1 = index of first child in m_first_child
+ size_type r = ckpos - m_bp_support.rank(ckpos);
+ if (r+1 >= i) { // if there exist more than i l-indices
+ // check if m_first_child[r-i+1..r-1] consists of zeros
+ if (i < degree(v)) { // there exists an i-th l-index
+ ckpos -= (i-1);
+ assert(m_bp[ckpos] == 0);
+ kpos = m_bp_support.find_open(ckpos);
+ return m_bp_support.rank(kpos)-1;
+ }
+ }
+ // if i >= degree(node)
+ kpos = v.jp1pos;
+ if (kpos < m_bp.size())
+ ckpos = m_bp_support.find_close(kpos);
+ else
+ ckpos = m_bp.size();
+ return v.j+1;
+ }
+ }
+
+ // Position of the first l-index of a l-[i,j] interval in the BP.
+ /* \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ inline size_type closing_pos_of_first_l_index(const node_type& node)const {
+ if (node.cipos > node.jp1pos) { // corresponds to m_lcp[i] <= m_lcp[j+1]
+ return node.jp1pos-1;
+ } else { // corresponds to m_lcp[i] > m_lcp[j+1]
+ return node.cipos-1;
+ }
+ }
+
+ // Get the next smaller value.
+ /*
+ * \param i Position in the original vector.
+ * \param ipos Position of the corresponding opening parenthesis in BP.
+ * \return Position of the next smaller value in [i+1..n-1], and n when
+ * no such value exists.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ // possible optimization: calculate also position of nsv,
+ // i.e. next ( following position cipos
+ inline size_type nsv(SDSL_UNUSED size_type i, size_type ipos)const {
+ size_type cipos = m_bp_support.find_close(ipos);
+ size_type result = m_bp_support.rank(cipos);
+ return result;
+ }
+
+ // Get the previous smaller value.
+ /*
+ * \param i Position in the original vector.
+ * \param ipos Corresponding opening parenthesis in m_bp
+ * \param cipos Corresponding closing parenthesis to ipos
+ * \par Time complexity
+ * \f$ \Order{\frac{\sigma}{w}} \f$, where w=64 is the word size,
+ * can be implemented in \f$\Order{1}\f$ with rank and select.
+ */
+ inline size_type psv(SDSL_UNUSED size_type i, size_type ipos,
+ size_type cipos, size_type& psvpos,
+ size_type& psvcpos)const {
+ // if lcp[i]==0 => psv is the 0-th index by definition
+ if ((cipos + (size_type)m_csa.sigma) >= m_bp.size()) {
+ psvpos = 0;
+ psvcpos = m_bp.size()-1;
+ return 0;
+ }
+ if (m_bp[cipos+1]) {
+ psvpos = m_bp_support.enclose(ipos);
+ psvcpos = m_bp_support.find_close(psvpos);
+ return m_bp_support.rank(psvpos)-1;
+ }
+ // r0 = index of clothing parenthesis in m_first_child
+ size_type r0 = cipos - m_bp_support.rank(cipos);
+ size_type next_first_child = 0;
+ const uint64_t* p = m_first_child.data() + (r0>>6);
+ uint64_t w = (*p) >> (r0&0x3F);
+ if (w) { // if w!=0
+ next_first_child = cipos + bits::lo(w);
+ if (cipos == next_first_child and m_bp[next_first_child+1]) {
+ psvpos = m_bp_support.enclose(ipos);
+ psvcpos = m_bp_support.find_close(psvpos);
+ return m_bp_support.rank(psvpos)-1;
+ }
+ } else {
+ size_type delta = 63-(r0&0x3F);
+ ++p;
+ int steps = 4;
+ while (!(w=*p) and steps-- > 0) { // while w==0
+ ++p;
+ delta += 64;
+ }
+ if (w != 0) {
+ delta += bits::lo(w) + 1;
+ } else {
+ auto pos = m_first_child_select(m_first_child_rank(r0+1)+1);
+ delta = pos - r0;
+ }
+ next_first_child = cipos + delta;
+ }
+ if (!m_bp[next_first_child+1]) { // if next parenthesis is a closing one
+ psvcpos = next_first_child+1;
+ psvpos = m_bp_support.find_open(psvcpos);
+ return m_bp_support.rank(psvpos)-1;
+ } else {
+ psvpos = m_bp_support.enclose(m_bp_support.find_open(next_first_child));
+ psvcpos = m_bp_support.find_close(psvpos);
+ return m_bp_support.rank(psvpos)-1;
+ }
+ }
+
+ // Range minimum query based on the rr_enclose method.
+ /* \par Time complexity
+ * \f$ \Order{\rrenclose} \f$
+ */
+ inline size_type rmq(size_type l, size_type r)const {
+ size_type i = m_bp_support.select(l+1);
+ size_type j = m_bp_support.select(r+1);
+ size_type fc_i = m_bp_support.find_close(i);
+ if (j < fc_i) { // i < j < find_close(j) < find_close(i)
+ return l;
+ } else { // i < find_close(i) < j < find_close(j)
+ size_type ec = m_bp_support.rr_enclose(i,j);
+ if (ec == m_bp_support.size()) {// no restricted enclosing pair found
+ return r;
+ } else { // found range restricted enclosing pair
+ return m_bp_support.rank(ec)-1; // subtract 1, as the index is 0 based
+ }
+ }
+ }
+
+ public:
+ const csa_type& csa = m_csa;
+ const lcp_type& lcp = m_lcp;
+ const bit_vector& bp = m_bp;
+ const bp_support_type& bp_support = m_bp_support;
+
+ const bv_type& first_child_bv = m_first_child;
+ const rank_type& first_child_rank = m_first_child_rank;
+ const sel_type& first_child_select = m_first_child_select;
+
+ /*! \defgroup cst_sct3_constructors Constructors of cst_sct3 */
+ /* @{ */
+
+ //! Default constructor
+ cst_sct3() {}
+
+ //! Construct CST from cache config
+ cst_sct3(cache_config& cache, bool build_only_bps=false);
+
+ //! Copy constructor
+ /*!
+ * \param cst The cst_sct3 which should be copied.
+ * \par Time complexity
+ * \f$ \Order{n} \f$, where \f$n=\f$cst_sct3.size()
+ */
+ cst_sct3(const cst_sct3& cst) {
+ copy(cst);
+ }
+
+ //! Move constructor
+ /*!
+ * \param cst The cst_sct3 which should be moved.
+ */
+ cst_sct3(cst_sct3&& cst) {
+ *this = std::move(cst);
+ }
+
+ /* @} */
+
+ //! Number of leaves of the suffix tree.
+ /*! Required for the Container Concept of the STL.
+ * \sa max_size, empty
+ */
+ size_type size()const {
+ return m_bp.size()>>1;
+ }
+
+ //! Returns the largest size that cst_sct3 can ever have.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ static size_type max_size() {
+ return t_csa::max_size();
+ }
+
+ //! Returns if the data structure is empty.
+ /*! Required for the Container Concept of the STL.
+ * \sa size
+ */
+ bool empty()const {
+ return m_csa.empty();
+ }
+
+ //! Swap method for cst_sct3
+ /*! The swap method can be defined in terms of assignment.
+ This requires three assignments, each of which, for a container type, is linear
+ in the container's size. In a sense, then, a.swap(b) is redundant.
+ This implementation guaranties a run-time complexity that is constant rather than linear.
+ \param cst cst_sct3 to swap.
+
+ Required for the Assignable Conecpt of the STL.
+ */
+ void swap(cst_sct3& cst) {
+ if (this != &cst) {
+ m_csa.swap(cst.m_csa);
+ m_bp.swap(cst.m_bp);
+ util::swap_support(m_bp_support, cst.m_bp_support, &m_bp, &(cst.m_bp));
+ m_first_child.swap(cst.m_first_child);
+ util::swap_support(m_first_child_rank, cst.m_first_child_rank, &m_first_child, &(cst.m_first_child));
+ util::swap_support(m_first_child_select, cst.m_first_child_select, &m_first_child, &(cst.m_first_child));
+ std::swap(m_nodes, cst.m_nodes);
+ // anything else has to be swapped before swapping lcp
+ swap_lcp(m_lcp, cst.m_lcp, *this, cst);
+ }
+ }
+
+ //! Returns a const_iterator to the first element of a depth first traversal of the tree.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ if (0 == m_bp.size()) // special case: tree is uninitialized
+ return end();
+ return const_iterator(this, root(), false, true);
+ };
+
+ //! Returns a const_iterator to the first element of a depth first traversal of the subtree rooted at node v.
+ const_iterator begin(const node_type& v)const {
+ if (0 == m_bp.size() and root()==v)
+ return end();
+ return const_iterator(this, v, false, true);
+ }
+
+ //! Returns a const_iterator to the element after the last element of a depth first traversal of the tree.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, root(), true, false);
+ }
+
+ //! Returns a const_iterator to the element past the end of a depth first traversal of the subtree rooted at node v.
+ const_iterator end(const node_type& v)const {
+ if (root() == v)
+ return end();
+ return ++const_iterator(this, v, true, true);
+ }
+
+ //! Returns an iterator to the first element of a bottom-up traversal of the tree.
+ const_bottom_up_iterator begin_bottom_up()const {
+ if (0 == m_bp.size()) // special case: tree is uninitialized
+ return end_bottom_up();
+ return const_bottom_up_iterator(this, leftmost_leaf(root()));
+ }
+
+ //! Returns an iterator to the element after the last element of a bottom-up traversal of the tree.
+ const_bottom_up_iterator end_bottom_up()const {
+ return const_bottom_up_iterator(this, root(), false);
+ }
+
+ //! Assignment Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ cst_sct3& operator=(const cst_sct3& cst);
+
+ //! Assignment Move Operator.
+ /*!
+ * Required for the Assignable Concept of the STL.
+ */
+ cst_sct3& operator=(cst_sct3&& cst);
+
+ //! Serialize to a stream.
+ /*! \param out Outstream to write the data structure.
+ * \return The number of written bytes.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ //! Load from a stream.
+ /*! \param in Inputstream to load the data structure from.
+ */
+ void load(std::istream& in);
+
+ /*! \defgroup cst_sct3_tree_methods Tree methods of cst_sct3 */
+ /* @{ */
+
+ //! Return the root of the suffix tree.
+ /*!
+ * \par Time complexity O(1)
+ * \f$ \Order{1} \f$
+ */
+ node_type root() const {
+ return node_type(0, size()-1, 0, m_bp.size()-1, m_bp.size());
+ }
+
+ //! Decide if a node is a leaf.
+ /*!
+ * \param v A valid node.
+ * \returns A boolean value indicating if v is a leaf.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ bool is_leaf(const node_type& v)const {
+ return v.i==v.j;
+ }
+
+ //! Return the i-th leaf (1-based from left to right).
+ /*!
+ * \param i 1-based position of the leaf.
+ * \return The i-th leave.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \pre \f$ 1 \leq i \leq size() \f$
+ */
+ node_type select_leaf(size_type i)const {
+ assert(i > 0 and i <= size());
+ size_type ipos = m_bp_support.select(i);
+ size_type jp1pos;
+ if (i == size())
+ jp1pos = m_bp.size();
+ else if (m_bp[ipos+1])
+ jp1pos = ipos+1;
+ else
+ jp1pos = m_bp_support.select(i+1);
+ return node_type(i-1, i-1, ipos, m_bp_support.find_close(ipos), jp1pos);
+ }
+
+ //! Calculate the number of leaves in the subtree rooted at node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The number of leaves in the subtree rooted at node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type size(const node_type& v)const {
+ return v.j-v.i+1;
+ }
+
+ //! Calculates the leftmost leaf in the subtree rooted at node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The leftmost leaf in the subtree rooted at node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type leftmost_leaf(const node_type& v)const {
+ return select_leaf(v.i+1);
+ }
+
+ //! Calculates the rightmost leaf in the subtree rooted at node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The rightmost leaf in the subtree rooted at node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type rightmost_leaf(const node_type& v)const {
+ return select_leaf(v.j+1);
+ }
+
+ //! Calculates the index of the leftmost leaf in the corresponding suffix array.
+ /*! \param v A valid node of the suffix tree.
+ * \return The index of the leftmost leaf in the corresponding suffix array.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \par Note
+ * lb is an abbreviation for ,,left bound''
+ */
+ size_type lb(const node_type& v)const {
+ return v.i;
+ }
+
+ //! Calculates the index of the rightmost leaf in the corresponding suffix array.
+ /*! \param v A valid node of the suffix tree.
+ * \return The index of the rightmost leaf in the corresponding suffix array.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \par Note
+ * rb is an abbreviation for ,,right bound''
+ */
+ size_type rb(const node_type& v)const {
+ return v.j;
+ }
+
+ //! Calculate the parent node of a node v.
+ /*! \param v A valid node of the suffix tree.
+ * \return The parent node of v or the root if v==root().
+ * \par Time complexity
+ * \f$ \Order{1}\f$
+ */
+ node_type parent(const node_type& v) const {
+ if (v.cipos > v.jp1pos) { // LCP[i] <= LCP[j+1]
+ size_type psv_pos, psv_cpos, psv_v, nsv_v, nsv_p1pos;
+ psv_v = psv(v.j+1, v.jp1pos, m_bp_support.find_close(v.jp1pos), psv_pos, psv_cpos);
+ nsv_v = nsv(v.j+1, v.jp1pos)-1;
+ if (nsv_v == size()-1) {
+ nsv_p1pos = m_bp.size();
+ } else { // nsv_v < size()-1
+ nsv_p1pos = m_bp_support.select(nsv_v+2);
+ }
+ return node_type(psv_v, nsv_v, psv_pos, psv_cpos, nsv_p1pos);
+ } else { // LCP[i] > LCP[j+1]
+ size_type psv_pos, psv_cpos, psv_v;
+ psv_v = psv(v.i, v.ipos, v.cipos, psv_pos, psv_cpos);
+ return node_type(psv_v, v.j, psv_pos, psv_cpos, v.jp1pos);
+ }
+ }
+
+ //! Return a proxy object which allows iterating over the children of a node
+ /*! \param v A valid node of the suffix tree.
+ * \return The proxy object of v containing all children
+ * \par Time complexity
+ * \f$ \Order{1}\f$
+ */
+ cst_node_child_proxy<cst_sct3> children(const node_type v) const {
+ return cst_node_child_proxy<cst_sct3>(this,v);
+ }
+
+ //! Returns the next sibling of node v.
+ /*!
+ * \param v A valid node v of the suffix tree.
+ * \return The next (right) sibling of node v or root() if v has no next (right) sibling.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type sibling(const node_type& v)const {
+//Procedure:(1) Determine, if v has a right sibling.
+ if (v.cipos < v.jp1pos) { // LCP[i] > LCP[j+1] => v has the same right border as parent(v) => no right sibling
+ return root();
+ }
+// (2) There exists a right sibling, LCP[j+1] >= LCP[i] and j>i
+ // Now it holds: v.cipos > v.jp1pos
+ size_type cjp1posm1 = m_bp_support.find_close(v.jp1pos)-1; // v.cipos-2 ???
+ // m_bp[cjp1posm1] equals 1 => v is the last child
+ bool last_child = m_bp[cjp1posm1];
+ // otherwise if m_bp[cjp1posm1] equals 0 => we don't know if it is the last child
+ if (!last_child) {
+ size_type first_child_idx = cjp1posm1 - m_bp_support.rank(cjp1posm1);
+ last_child = m_first_child[first_child_idx]; // if first_child indicator is true => the new sibling is the rightmost sibling
+ }
+ if (last_child) {
+ size_type nsv_v = nsv(v.j+1, v.jp1pos)-1, nsv_p1pos;
+ if (nsv_v == size()-1) {
+ nsv_p1pos = m_bp.size();
+ } else {
+ nsv_p1pos = m_bp_support.select(nsv_v+2);
+ }
+ return node_type(v.j+1, nsv_v, v.jp1pos, m_bp_support.find_close(v.jp1pos), nsv_p1pos);
+ } else {
+ size_type new_j = m_bp_support.rank(m_bp_support.find_open(cjp1posm1))-2;
+ return node_type(v.j+1, new_j, v.jp1pos, m_bp_support.find_close(v.jp1pos), m_bp_support.select(new_j+2));
+ }
+ }
+
+ //! Get the i-th child of a node v.
+ /*!
+ * \param v A valid tree node of the cst.
+ * \param i 1-based index of the child which should be returned.
+ * \return The i-th child node of v or root() if v has no i-th child.
+ * \par Time complexity
+ * \f$ \Order{\frac{\sigma}{w}} \f$, where w=64 is the word size,
+ * can be implemented in \f$\Order{1}\f$ with rank and select.
+ * \pre \f$ 1 \leq i \leq degree(v) \f$
+ */
+
+ node_type select_child(const node_type& v, size_type i)const {
+ assert(i > 0);
+ if (is_leaf(v)) // if v is a leave, v has no child
+ return root();
+ if (1 == i) {
+ size_type k = 0, kpos = 0, k_find_close = 0;
+ // v is not a leave: v has at least two children
+ k = select_l_index(v, 1, kpos, k_find_close);// get first l-index k and the position of k
+ return node_type(v.i, k-1, v.ipos, v.cipos, kpos);
+ } else { // i > 1
+ size_type k1, kpos1, k_find_close1;
+ k1 = select_l_index(v, i-1, kpos1, k_find_close1);
+ if (k1 == v.j+1)
+ return root();
+ size_type k2, kpos2, k_find_close2;
+ k2 = select_l_index(v, i, kpos2, k_find_close2);
+ return node_type(k1, k2-1, kpos1, k_find_close1, kpos2);
+ }
+ }
+
+ //! Get the number of children of a node v.
+ /*!
+ * \param v A valid node v.
+ * \returns The number of children of node v.
+ * \par Time complexity
+ * \f$ \Order{\frac{\sigma}{w}} \f$, where w=64 is the word size,
+ * can be implemented in \f$\Order{1}\f$ with rank and select.
+ */
+ size_type degree(const node_type& v)const {
+ if (is_leaf(v)) // if v is a leave, v has no child
+ return 0;
+ // v is not a leave: v has at least two children
+ size_type r = closing_pos_of_first_l_index(v);
+ size_type r0 = r - m_bp_support.rank(r);
+ const uint64_t* p = m_first_child.data() + (r0>>6);
+ uint8_t offset = r0&0x3F;
+
+ uint64_t w = (*p) & bits::lo_set[offset];
+ if (w) { // if there is a bit set in the current word
+ return offset-bits::hi(w)+1;
+ } else if (m_first_child.data() == p) { // no bit set and we are in the first word
+ return offset+2; // since would have to be bits::hi(w)=-1, child marked in previous word
+ } else {
+ size_type res = offset+2;
+ int steps = 4;
+ // search in previous four words for result
+ while (p > m_first_child.data() and steps-- > 0) {
+ w = *(--p);
+ if (0 == w)
+ res += 64;
+ else {
+ return res + (63-bits::hi(w));
+ }
+ }
+ // if not found: use rank + select to answer query
+ auto goal_rank = m_first_child_rank(r0);
+ if (goal_rank == 0) {
+ return r0+2;
+ } else {
+ return r0-m_first_child_select(goal_rank)+1;
+ }
+ }
+ }
+
+ //! Get the child w of node v which edge label (v,w) starts with character c.
+ /*!
+ * \param v A valid tree node of the cst.
+ * \param c First character on the edge label.
+ * \param char_pos Reference which will hold the position (0-based) of
+ * the matching char c in the sorted text/suffix array.
+ * \return The child node w which edge label (v,w) starts with c or
+ * root() if it does not exist.
+ * \par Time complexity
+ * \f$ \Order{(\saaccess+\isaaccess) \cdot \log\sigma + \lcpaccess} \f$
+ */
+ node_type child(const node_type& v, const char_type c, size_type& char_pos)const {
+ if (is_leaf(v)) // if v is a leaf = (), v has no child
+ return root();
+ // else v = ( ( ))
+ comp_char_type cc = m_csa.char2comp[c];
+ if (cc==0 and c!=0) // TODO: change char2comp so that we don't need this special case
+ return root();
+ size_type char_ex_max_pos = m_csa.C[((size_type)1)+cc], char_inc_min_pos = m_csa.C[cc];
+
+ size_type d = depth(v);
+
+// (1) check the first child
+ char_pos = get_char_pos(v.i, d, m_csa);
+ if (char_pos >= char_ex_max_pos) {// the first character of the first child interval is lex. greater than c
+ // => all other first characters of the child intervals are also greater than c => no solution
+ return root();
+ } else if (char_pos >= char_inc_min_pos) { // i.e. char_pos < char_ex_max_pos and char_pos >= char_inc_min_pos
+ return select_child(v, 1);
+ }
+
+ size_type child_cnt = degree(v);
+
+// (2) check the last child
+ char_pos = get_char_pos(v.j, d, m_csa);
+ if (char_pos < char_inc_min_pos) {// the first character of the last child interval is lex. smaller than c
+ // => all other first characters of the child intervals are also smaller than c => no solution
+ return root();
+ } else if (char_pos < char_ex_max_pos) { // i.e. char_pos < char_ex_max_pos and char_pos >= char_inc_min_pos
+ return select_child(v, child_cnt);
+ }
+
+// (3) binary search for c in the children [2..children)
+ size_type l_bound = 2, r_bound = child_cnt, mid, kpos, ckpos, l_index;
+ while (l_bound < r_bound) {
+ mid = (l_bound + r_bound) >> 1;
+
+ l_index = select_l_index(v, mid-1, kpos, ckpos);
+ char_pos = get_char_pos(l_index, d, m_csa);
+
+ if (char_inc_min_pos > char_pos) {
+ l_bound = mid+1;
+ } else if (char_ex_max_pos <= char_pos) {
+ r_bound = mid;
+ } else { // char_inc_min_pos <= char_pos < char_ex_max_pos => found child
+ // we know that the child is not the last child, see (2)
+ // find next l_index: we know that a new l_index exists: i.e. assert( 0 == m_bp[ckpos-1]);
+ size_type lp1_index = m_bp_support.rank(m_bp_support.find_open(ckpos-1))-1;
+ size_type jp1pos = m_bp.size();
+ if (lp1_index-1 < size()-1) {
+ jp1pos = m_bp_support.select(lp1_index+1);
+ }
+ return node_type(l_index, lp1_index-1, kpos, ckpos, jp1pos);
+ }
+ }
+ return root();
+ }
+
+ //! Get the child w of node v which edge label (v,w) starts with character c.
+ // \sa child(node_type v, const char_type c, size_type &char_pos)
+ node_type child(const node_type& v, const char_type c) {
+ size_type char_pos;
+ return child(v, c, char_pos);
+ }
+
+ //! Returns the d-th character (1-based indexing) of the edge-label pointing to v.
+ /*!\param v The node at which the edge path ends.
+ * \param d The position (1-based indexing) on the edge path from the
+ * root to v. \f$ d > 0 \wedge d <= depth(v) \f$
+ * \return The character at position d on the edge path from the root to v.
+ * \par Time complexity
+ * \f$ \Order{ \log\sigma + (\saaccess+\isaaccess) } \f$
+ * \pre \f$ 1 \leq d \leq depth(v) \f$
+ */
+ char_type edge(const node_type& v, size_type d)const {
+ assert(1 <= d);
+ assert(d <= depth(v));
+ size_type order = get_char_pos(v.i, d-1, m_csa);
+ size_type c_begin = 1, c_end = ((size_type)m_csa.sigma)+1, mid;
+ while (c_begin < c_end) {
+ mid = (c_begin+c_end)>>1;
+ if (m_csa.C[mid] <= order) {
+ c_begin = mid+1;
+ } else {
+ c_end = mid;
+ }
+ }
+ return m_csa.comp2char[c_begin-1];
+ }
+
+ //! Calculate the LCA of two nodes `v` and `w`
+ /*!
+ * \param v The first node.
+ * \param w The second node.
+ * \return The lowest common ancestor of v and w.
+ * \par Time complexity
+ * \f$ \Order{\rrenclose}\ \f$
+ */
+
+ node_type lca(node_type v, node_type w)const {
+ if (v.i > w.i or(v.i == w.i and v.j < w.j)) {
+ std::swap(v, w);
+ }
+ if (v.j >= w.j) { // v encloses w or v==w
+ return v;
+ } else { // v.i < v.j < w.i < w.j
+ size_type min_index = rmq(v.i+1, w.j);
+ size_type min_index_pos = m_bp_support.select(min_index+1);
+ size_type min_index_cpos = m_bp_support.find_close(min_index_pos);
+
+ if (min_index_cpos >= (m_bp.size() - m_csa.sigma)) { // if lcp[min_index]==0 => return root
+ return root();
+ }
+ size_type new_j = nsv(min_index, min_index_pos)-1;
+ size_type new_ipos, new_icpos;
+ size_type new_i = psv(min_index, min_index_pos, min_index_cpos, new_ipos, new_icpos);
+ size_type jp1pos = m_bp.size();
+ if (new_j < size()-1) {
+ jp1pos = m_bp_support.select(new_j+2);
+ }
+ return node_type(new_i, new_j, new_ipos, new_icpos, jp1pos);
+ }
+ }
+
+ //! Returns the string depth of node v.
+ /*!
+ * \param v A valid node of a cst_sct3.
+ * \return The string depth of node v.
+ * \par Time complexity
+ * \f$ \Order{1} \f$ for non-leaves and \f$\Order{t_{SA}}\f$ for leaves
+ */
+ size_type depth(const node_type& v)const {
+ if (v.i == v.j) {
+ return size()-m_csa[v.i];
+ } else if (v == root()) {
+ return 0;
+ } else {
+ size_type kpos, ckpos;
+ size_type l = select_l_index(v, 1, kpos, ckpos);
+ return m_lcp[l];
+ }
+ }
+
+ //! Returns the node depth of node v
+ /*!
+ * \param v A valid node of a cst_sct3.
+ * \return The node depth of node v.
+ * \par Time complexity
+ * \f$ \Order{z} \f$, where \f$z\f$ is the resulting node depth.
+ * \par Note
+ * Can be implemented in O(1) with o(n) space. See
+ * Jansson, Sadakane, Sung:
+ * Ultra-succinct Representation of Ordered Trees
+ * SODA 2007
+ */
+ size_type node_depth(node_type v)const {
+ size_type d = 0;
+ while (v != root()) {
+ ++d;
+ v = parent(v);
+ }
+ return d;
+ }
+
+ //! Compute the suffix link of node v.
+ /*!
+ * \param v A valid node of a cst_sct3.
+ * \return The suffix link of node v.
+ * \par Time complexity
+ * \f$ \Order{ \rrenclose } \f$
+ */
+ node_type sl(const node_type& v)const {
+ if (v == root())
+ return root();
+ // get interval with first char deleted
+ size_type i = m_csa.psi[v.i];
+ if (is_leaf(v)) {
+ if (v.i==0 and v.j==0) // if( v.l==1 )
+ return root();
+ else
+ return select_leaf(i+1);
+ }
+ size_type j = m_csa.psi[v.j];
+ assert(i < j);
+ size_type min_index = rmq(i+1, j); // rmq
+ size_type min_index_pos = m_bp_support.select(min_index+1);
+ size_type min_index_cpos = m_bp_support.find_close(min_index_pos);
+ if (min_index_cpos >= (m_bp.size() - m_csa.sigma)) { // if lcp[min_index]==0 => return root
+ return root();
+ }
+ size_type new_j = nsv(min_index, min_index_pos)-1;
+ size_type new_ipos, new_icpos;
+ size_type new_i = psv(min_index, min_index_pos, min_index_cpos, new_ipos, new_icpos);
+ size_type jp1pos = m_bp.size();
+ if (new_j < size()-1) {
+ jp1pos = m_bp_support.select(new_j+2);
+ }
+ return node_type(new_i, new_j, new_ipos, new_icpos, jp1pos);
+ }
+
+
+ //! Compute the Weiner link of node v and character c.
+ /*!
+ * \param v A valid not of a cst_sct3.
+ * \param c The character which should be prepended to the string of the current node.
+ * \return root() if the Weiner link of (v, c) does not exist,
+ * otherwise the Weiner link is returned.
+ * \par Time complexity
+ * \f$ \Order{ t_{rank\_bwt} } \f$
+ */
+ node_type wl(const node_type& v, const char_type c) const {
+ size_type c_left = m_csa.bwt.rank(v.i, c);
+ size_type c_right = m_csa.bwt.rank(v.j+1, c);
+ if (c_left == c_right) // there exists no Weiner link
+ return root();
+ if (c_left+1 == c_right)
+ return select_leaf(m_csa.C[m_csa.char2comp[c]] + c_left + 1);
+ else {
+ size_type left = m_csa.C[m_csa.char2comp[c]] + c_left;
+ size_type right = m_csa.C[m_csa.char2comp[c]] + c_right - 1;
+ assert(left < right);
+
+ size_type ipos = m_bp_support.select(left+1);
+ size_type jp1pos = m_bp.size();
+ if (right < size()-1) {
+ jp1pos = m_bp_support.select(right+2);
+ }
+ return node_type(left, right, ipos,
+ m_bp_support.find_close(ipos), jp1pos);
+ }
+ }
+
+ //! Computes the suffix number of a leaf node v.
+ /*!\param v A valid leaf node of a cst_sct3.
+ * \return The suffix array value corresponding to the leaf node v.
+ * \par Time complexity
+ * \f$ \Order{ \saaccess } \f$
+ */
+ size_type sn(const node_type& v)const {
+ assert(is_leaf(v));
+ return m_csa[v.i];
+ }
+
+ //! Computes a unique identification number for a node of the suffx tree in the range [0..nodes()-1]
+ /*!
+ * \param v A valid node of a cst_sct3.
+ * \return A unique identification number for the node v in the range [0..nodes()-1]
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type id(const node_type& v)const {
+ if (is_leaf(v)) { // return id in the range from 0..csa.size()-1
+ return v.i;
+ }
+ size_type ckpos; // closing parentheses of the l-index
+ if (v.cipos > v.jp1pos) { // corresponds to m_lcp[i] <= m_lcp[j+1]
+ ckpos = v.jp1pos-1;
+ } else { // corresponds to m_lcp[i] > m_lcp[j+1]
+ ckpos = v.cipos-1;
+ }
+ assert(m_bp[ckpos]==0);
+ size_type r0ckpos = ckpos-m_bp_support.rank(ckpos); // determine the rank of the closing parenthesis
+ return size()+m_first_child_rank(r0ckpos);
+ }
+
+ //! Computes the node for such that id(v)=id.
+ /*!
+ * \param id An id in the range [0..nodes()-1].
+ * \return A node v of the CST such that id(v)=id.
+ * \par Time complexity
+ * \f$ \Order{1} \f$ for leaves and \f$ \Order{\log size()} \f$ for inner nodes
+ * \sa id(node_type v)
+ */
+ node_type inv_id(size_type id) {
+ if (id < size()) { // the corresponding node is a leaf
+ return select_leaf(id+1);
+ } else { // the corresponding node is a inner node
+ // (1) get index of the closing parenthesis in m_first_child
+ size_type r0ckpos = 0;
+ {
+ //binary search for the position of the (id-size()+1)-th set bit in
+ id = id-size()+1;
+ size_type lb = 0, rb = m_bp.size(); // lb inclusive, rb exclusive
+ // invariant: arg(lb) < id, arg(rb) >= id
+ while (rb-lb > 1) {
+ size_type mid = lb + (rb-lb)/2;
+ size_type arg = m_first_child_rank(mid); // ones in the prefix [0..mid-1]
+ if (arg < id) {
+ lb = mid;
+ } else { // arg >= id
+ rb = mid;
+ }
+ }
+ r0ckpos = lb;
+ }
+ // (2) determine position clpos of the r0clpos-th closing parentheses in the parentheses sequence
+ size_type ckpos = 0;
+ {
+ // binary search for the position of the (r0ckpos+1)-th closing parenthesis
+ size_type lb = 0, rb = m_bp.size(); // lb inclusive, rb exclusive
+ // invariant: arg(lb) < r0ckpos+1, arg(rb) >= r0ckpos+1
+ while (rb-lb > 1) {
+ size_type mid = lb + (rb-lb)/2;
+ size_type arg = mid - m_bp_support.rank(mid-1); // zeros in the prefix [0..mid-1]
+ if (arg < r0ckpos+1) {
+ lb = mid;
+ } else { // arg >= x
+ rb = mid;
+ }
+ }
+ ckpos = lb;
+ }
+ if (ckpos == m_bp.size()-1) {
+ return root();
+ }
+ if (m_bp[ckpos+1]) { // jp1pos < cipos
+ size_type jp1pos= ckpos+1;
+ size_type j = m_bp_support.rank(jp1pos-1)-1;
+ size_type kpos = m_bp_support.find_open(ckpos);
+ size_type ipos = m_bp_support.enclose(kpos);
+ size_type cipos = m_bp_support.find_close(ipos);
+ size_type i = m_bp_support.rank(ipos-1);
+ return node_type(i, j, ipos, cipos, jp1pos);
+ } else { //
+ size_type cipos = ckpos+1;
+ size_type ipos = m_bp_support.find_open(cipos);
+ size_type i = m_bp_support.rank(ipos-1);
+ size_type j = nsv(i, ipos)-1;
+ size_type jp1pos= m_bp.size();
+ if (j != size()-1) {
+ jp1pos = m_bp_support.select(j+2);
+ }
+ return node_type(i, j, ipos, cipos, jp1pos);
+ }
+ }
+ }
+
+ //! Get the number of nodes of the suffix tree.
+ size_type nodes()const {
+ return m_nodes;
+ }
+
+ //! Get the node in the suffix tree which corresponds to the lcp-interval [lb..rb]
+ /* \param lb Left bound of the lcp-interval [lb..rb] (inclusive).
+ * \param rb Right bound of the lcp-interval [lb..rb] (inclusive).
+ * \return The node in the suffix tree corresponding lcp-interval [lb..rb]
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ node_type node(size_type lb, size_type rb) const {
+ size_type ipos = m_bp_support.select(lb+1);
+ size_type jp1pos;
+ if (rb == size()-1) {
+ jp1pos = m_bp.size();
+ } else {
+ jp1pos = m_bp_support.select(rb+2);
+ }
+ return node_type(lb, rb, ipos, m_bp_support.find_close(ipos), jp1pos);
+ }
+
+ //! Maps an index i to the position in TLCP where LCP[i] can be found
+ /*!
+ * \param i The index in the LCP array
+ * \return The corresponding position in the TLCP array
+ */
+ size_type tlcp_idx(size_type i) const {
+ size_type ipos = m_bp_support.select(i+1);
+ size_type cipos = m_bp_support.find_close(ipos);
+ return m_first_child_rank.rank(((ipos+cipos-1)>>1)-i);
+ }
+ /* @} */
+};
+
+// == template functions ==
+
+
+template<class t_csa, class t_lcp, class t_bp_support, class t_bv, class t_rank, class t_sel>
+cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>::cst_sct3(cache_config& config, bool build_only_bps)
+{
+ {
+ auto event = memory_monitor::event("bps-sct");
+ int_vector_buffer<> lcp_buf(cache_file_name(conf::KEY_LCP, config));
+ m_nodes = construct_supercartesian_tree_bp_succinct_and_first_child(lcp_buf, m_bp, m_first_child) + m_bp.size()/2;
+ if (m_bp.size() == 2) { // handle special case, when the tree consists only of the root node
+ m_nodes = 1;
+ }
+ }
+ {
+ auto event = memory_monitor::event("bpss-sct");
+ util::init_support(m_bp_support, &m_bp);
+ util::init_support(m_first_child_rank, &m_first_child);
+ util::init_support(m_first_child_select, &m_first_child);
+ }
+ if (!build_only_bps) {
+ auto event = memory_monitor::event("clcp");
+ cache_config tmp_config(false, config.dir, config.id, config.file_map);
+ construct_lcp(m_lcp, *this, tmp_config);
+ config.file_map = tmp_config.file_map;
+ }
+ if (!build_only_bps) {
+ auto event = memory_monitor::event("load csa");
+ load_from_cache(m_csa,std::string(conf::KEY_CSA)+"_"+util::class_to_hash(m_csa), config);
+ }
+}
+
+template<class t_csa, class t_lcp, class t_bp_support, class t_bv, class t_rank, class t_sel>
+auto cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>::serialize(std::ostream& out, structure_tree_node* v, std::string name) const -> size_type
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_csa.serialize(out, child, "csa");
+ written_bytes += m_lcp.serialize(out, child, "lcp");
+ written_bytes += m_bp.serialize(out, child, "bp");
+ written_bytes += m_bp_support.serialize(out, child, "bp_support");
+ written_bytes += m_first_child.serialize(out, child, "mark_child");
+ written_bytes += m_first_child_rank.serialize(out, child, "mark_child_rank");
+ written_bytes += m_first_child_select.serialize(out, child, "mark_child_select");
+ written_bytes += write_member(m_nodes, out, child, "node_cnt");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<class t_csa, class t_lcp, class t_bp_support, class t_bv, class t_rank, class t_sel>
+void cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>::load(std::istream& in)
+{
+ m_csa.load(in);
+ load_lcp(m_lcp, in, *this);
+ m_bp.load(in);
+ m_bp_support.load(in, &m_bp);
+ m_first_child.load(in);
+ m_first_child_rank.load(in);
+ m_first_child_rank.set_vector(&m_first_child);
+ m_first_child_select.load(in);
+ m_first_child_select.set_vector(&m_first_child);
+ read_member(m_nodes, in);
+}
+
+template<class t_csa, class t_lcp, class t_bp_support, class t_bv, class t_rank, class t_sel>
+cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>& cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>::operator=(const cst_sct3& cst)
+{
+ if (this != &cst) {
+ copy(cst);
+ }
+ return *this;
+}
+
+template<class t_csa, class t_lcp, class t_bp_support, class t_bv, class t_rank, class t_sel>
+cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>& cst_sct3<t_csa, t_lcp, t_bp_support, t_bv, t_rank, t_sel>::operator=(cst_sct3&& cst)
+{
+ if (this != &cst) {
+ m_csa = std::move(cst.m_csa);
+ move_lcp(m_lcp, cst.m_lcp, *this);
+ m_bp = std::move(cst.m_bp);
+ m_bp_support = std::move(cst.m_bp_support);
+ m_bp_support.set_vector(&m_bp);
+ m_first_child = std::move(cst.m_first_child);
+ m_first_child_rank = std::move(cst.m_first_child_rank);
+ m_first_child_rank.set_vector(&m_first_child);
+ m_first_child_select = std::move(cst.m_first_child_select);
+ m_first_child_select.set_vector(&m_first_child);
+ m_nodes = std::move(cst.m_nodes);
+ }
+ return *this;
+}
+
+template<class t_int>
+struct bp_interval {
+ t_int i; //!< The left border of the lcp-interval \f$\ell-[left..right]\f$.
+ t_int j; //!< The right border of the lcp-interval \f$\ell-[left..right]\f$.
+ t_int ipos; // position of the i+1th opening parenthesis in the balanced parentheses sequence
+ t_int cipos; // position of the matching closing parenthesis of the i+1th opening parenthesis in the balanced parentheses sequence
+ t_int jp1pos;// position of the j+2th opening parenthesis in the balanced parentheses sequence
+
+ //! Constructor
+ bp_interval(t_int i=0, t_int j=0, t_int ipos=0, t_int cipos=0, t_int jp1pos=0):i(i),j(j),ipos(ipos),cipos(cipos),jp1pos(jp1pos) {};
+
+ //! Copy constructor
+ bp_interval(const bp_interval& iv) = default;
+ //! Move copy constructor
+ bp_interval(bp_interval&& iv) = default;
+
+ bool operator<(const bp_interval& interval)const {
+ if (i!=interval.i)
+ return i<interval.i;
+ return j<interval.j;
+ }
+
+ //! Equality operator.
+ /*! Two lcp-intervals are equal if and only if all their corresponding member variables have the same values.
+ */
+ bool operator==(const bp_interval& interval)const {
+ return i==interval.i and j==interval.j;
+ }
+
+ //! Inequality operator.
+ /*! Two lcp-intervals are not equal if and only if not all their corresponding member variables have the same values.
+ */
+ bool operator!=(const bp_interval& interval)const {
+ return !(*this==interval);
+ }
+
+ //! Assignment operator.
+ bp_interval& operator=(const bp_interval& interval) = default;
+ //! Move assignment
+ bp_interval& operator=(bp_interval&& interval) = default;
+};
+
+
+template<class t_int>
+inline std::ostream& operator<<(std::ostream& os, const bp_interval<t_int>& interval)
+{
+ os<<"-["<<interval.i<<","<<interval.j<<"]("<<interval.ipos<<","<<interval.cipos<<","<<interval.jp1pos<<")";
+ return os;
+}
+
+
+
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/dac_vector.hpp b/include/sdsl/dac_vector.hpp
new file mode 100644
index 0000000..2f5744f
--- /dev/null
+++ b/include/sdsl/dac_vector.hpp
@@ -0,0 +1,382 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file dac_vector.hpp
+ \brief dac_vector.hpp contains a vector which stores the values with variable length codes.
+ \author Simon Gog
+*/
+#ifndef SDSL_DAC_VECTOR
+#define SDSL_DAC_VECTOR
+
+#include "int_vector.hpp"
+#include "rank_support_v5.hpp"
+#include "iterators.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A generic immutable space-saving vector class for unsigned integers.
+/*! The values of a dac_vector are immutable after the constructor call.
+ * The ,,escaping'' technique is used to encode values.
+ * This is defined as follows (see [1]):
+ * A k-bit integer is split into \f$K=\lceil k/(b-1)\rceil\f$ bits each and
+ * encoded into \f$K\f$ blocks of \f$ b \f$ bits each. All but the last block
+ * are marked with by a 1 in the most significant bit. Escaping with b=8 is
+ * also known as vbyte-coding (see [2]). A experimental study of using escaping
+ * for the LCP array is given in [3].
+ * \par Time complexity
+ * - \f$\Order{\log n/b}\f$ worst case, where b is the number of bits
+ in a block
+ * \par References
+ * [1] F. Transier and P. Sanders: ,,Engineering Basic Search Algorithms
+ * of an In-Memory Text Search Engine'', ACM Transactions on
+ * Information Systems, Vol. 29, No.1, Article 2, 2010
+ * [2] H.E. Williams and J. Zobel: ,,Compressing integers for fast file
+ * access'', Computing Journal Vol 43, No.3, 1999
+ * [3] N. Brisboa, S. Ladra, G. Navarro: ,,Directly addressable variable-
+ * length codes'', Proceedings of SPIRE 2009.
+ *
+ * \tparam t_b Split block size.
+ * \tparam t_rank Rank structure to navigate between the different levels.
+
+ */
+template<uint8_t t_b = 4,
+ typename t_rank = rank_support_v5<>
+ >
+class dac_vector
+{
+ private:
+ static_assert(t_b > 0 , "dac_vector: t_b has to be larger than 0");
+ static_assert(t_b < 64, "dac_vector: t_b has to be smaller than 64");
+ public:
+ typedef typename int_vector<>::value_type value_type;
+ typedef random_access_const_iterator<dac_vector> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef ptrdiff_t difference_type;
+ typedef t_rank rank_support_type;
+ typedef iv_tag index_category;
+ private:
+ int_vector<t_b> m_data; // block data for every level
+ bit_vector m_overflow; // mark non-end bytes
+ rank_support_type m_overflow_rank; // rank for m_overflow
+ int_vector<64> m_level_pointer_and_rank = int_vector<64>(4,0);
+ uint8_t m_max_level; // maximum level < (log n)/b+1
+
+ void copy(const dac_vector& v)
+ {
+ m_data = v.m_data;
+ m_overflow = v.m_overflow;
+ m_overflow_rank = v.m_overflow_rank;
+ m_overflow_rank.set_vector(&m_overflow);
+ m_level_pointer_and_rank = v.m_level_pointer_and_rank;
+ m_max_level = v.m_max_level;
+ }
+
+ public:
+ dac_vector() = default;
+
+ dac_vector(const dac_vector& v)
+ {
+ copy(v);
+ }
+
+ dac_vector(dac_vector&& v)
+ {
+ *this = std::move(v);
+ }
+ dac_vector& operator=(const dac_vector& v)
+ {
+ if (this != &v) {
+ copy(v);
+ }
+ return *this;
+ }
+
+ dac_vector& operator=(dac_vector&& v)
+ {
+ if (this != &v) {
+ m_data = std::move(v.m_data);
+ m_overflow = std::move(v.m_overflow);
+ m_overflow_rank = std::move(v.m_overflow_rank);
+ m_overflow_rank.set_vector(&m_overflow);
+ m_level_pointer_and_rank = std::move(v.m_level_pointer_and_rank);
+ m_max_level = std::move(v.m_max_level);
+ }
+ return *this;
+ }
+
+ //! Constructor for a Container of unsigned integers.
+ /*! \param c A container of unsigned integers.
+ \pre No two adjacent values should be equal.
+ */
+ template<class Container>
+ dac_vector(const Container& c);
+
+ //! Constructor for an int_vector_buffer of unsigned integers.
+ template<uint8_t int_width>
+ dac_vector(int_vector_buffer<int_width>& v_buf);
+
+ //! The number of elements in the dac_vector.
+ size_type size()const
+ {
+ return m_level_pointer_and_rank[2];
+ }
+ //! Return the largest size that this container can ever have.
+ static size_type max_size()
+ {
+ return int_vector<>::max_size()/2;
+ }
+
+ //! Returns if the dac_vector is empty.
+ bool empty() const
+ {
+ return 0 == m_level_pointer_and_rank[2];
+ }
+
+ //! Swap method for dac_vector
+ void swap(dac_vector& v)
+ {
+ m_data.swap(v.m_data);
+ m_overflow.swap(v.m_overflow);
+ util::swap_support(m_overflow_rank, v.m_overflow_rank,
+ &m_overflow, &(v.m_overflow));
+
+ m_level_pointer_and_rank.swap(v.m_level_pointer_and_rank);
+ std::swap(m_max_level, v.m_max_level);
+ }
+
+ //! Iterator that points to the first element of the dac_vector.
+ const const_iterator begin()const
+ {
+ return const_iterator(this, 0);
+ }
+
+
+ //! Iterator that points to the position after the last element of the dac_vector.
+ const const_iterator end()const
+ {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ value_type operator[](size_type i)const
+ {
+ uint8_t level = 1;
+ uint8_t offset = t_b;
+ size_type result = m_data[i];
+ const uint64_t* p = m_level_pointer_and_rank.data();
+ uint64_t ppi = (*p)+i;
+ while (level < m_max_level and m_overflow[ppi]) {
+ p += 2;
+ ppi = *p + (m_overflow_rank(ppi) - *(p-1));
+ result |= (m_data[ppi] << (offset));
+ ++level;
+ offset += t_b;
+ }
+ return result;
+ }
+
+ //! Serializes the dac_vector to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ //! Load from a stream.
+ void load(std::istream& in)
+ {
+ m_data.load(in);
+ m_overflow.load(in);
+ m_overflow_rank.load(in, &m_overflow);
+ m_level_pointer_and_rank.load(in);
+ read_member(m_max_level, in);
+ }
+};
+
+template<uint8_t t_b, typename t_rank>
+template<class Container>
+dac_vector<t_b, t_rank>::dac_vector(const Container& c)
+{
+// (1) Count for each level, how many blocks are needed for the representation
+// Running time: \f$ O(n \times \frac{\log n}{b} \f$
+// Result is sorted in m_level_pointer_and_rank
+ size_type n = c.size(), val=0;
+ if (n == 0)
+ return;
+// initialize counter
+ m_level_pointer_and_rank = int_vector<64>(128, 0);
+ m_level_pointer_and_rank[0] = n; // level 0 has n entries
+
+ uint8_t level_x_2 = 0;
+ uint8_t max_level_x_2 = 4;
+ for (size_type i=0; i < n; ++i) {
+ val=c[i];
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 = 2;
+ while (val) {
+ // increase counter for current level by 1
+ ++m_level_pointer_and_rank[level_x_2];
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 += 2; // increase level by 1
+ max_level_x_2 = std::max(max_level_x_2, level_x_2);
+ }
+ }
+ m_level_pointer_and_rank.resize(max_level_x_2);
+// (2) Determine maximum level and prefix sums of level counters
+ m_max_level = 0;
+ size_type sum_blocks = 0, last_block_size=0;
+ for (size_type i=0, t=0; i < m_level_pointer_and_rank.size(); i+=2) {
+ t = sum_blocks;
+ sum_blocks += m_level_pointer_and_rank[i];
+ m_level_pointer_and_rank[i] = t;
+ if (sum_blocks > t) {
+ ++m_max_level;
+ last_block_size = sum_blocks - t;
+ }
+ }
+ m_overflow = bit_vector(sum_blocks - last_block_size, 0);
+ m_data.resize(sum_blocks);
+
+ assert(last_block_size > 0);
+
+// (3) Enter block and overflow data
+ int_vector<64> cnt = m_level_pointer_and_rank;
+ const uint64_t mask = bits::lo_set[t_b];
+
+ for (size_type i=0, j=0; i < n; ++i) {
+ val=c[i];
+ j = cnt[0]++;
+ m_data[ j ] = val & mask;
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 = 2;
+ while (val) {
+ m_overflow[j] = 1;
+ // increase counter for current level by 1
+ j = cnt[level_x_2]++;
+ m_data[ j ] = val & mask;
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 += 2; // increase level by 1
+ }
+ }
+
+// (4) Initialize rank data structure for m_overflow and precalc rank for
+// pointers
+ util::init_support(m_overflow_rank, &m_overflow);
+ for (size_type i=0; 2*i < m_level_pointer_and_rank.size() and
+ m_level_pointer_and_rank[2*i] < m_overflow.size(); ++i) {
+ m_level_pointer_and_rank[2*i+1] = m_overflow_rank(
+ m_level_pointer_and_rank[2*i]);
+ }
+
+}
+
+template<uint8_t t_b, typename t_rank>
+template<uint8_t int_width>
+dac_vector<t_b, t_rank>::dac_vector(int_vector_buffer<int_width>& v_buf)
+{
+// (1) Count for each level, how many blocks are needed for the representation
+// Running time: \f$ O(n \times \frac{\log n}{b} \f$
+// Result is sorted in m_level_pointer_and_rank
+ size_type n = v_buf.size(), val=0;
+ if (n == 0)
+ return;
+// initialize counter
+ m_level_pointer_and_rank = int_vector<64>(128, 0);
+ m_level_pointer_and_rank[0] = n; // level 0 has n entries
+
+ uint8_t level_x_2 = 0;
+ uint8_t max_level_x_2 = 4;
+ for (size_type i=0; i < n; ++i) {
+ val=v_buf[i];
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 = 2;
+ while (val) {
+ // increase counter for current level by 1
+ ++m_level_pointer_and_rank[level_x_2];
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 += 2; // increase level by 1
+ max_level_x_2 = std::max(max_level_x_2, level_x_2);
+ }
+ }
+ m_level_pointer_and_rank.resize(max_level_x_2);
+// (2) Determine maximum level and prefix sums of level counters
+ m_max_level = 0;
+ size_type sum_blocks = 0, last_block_size=0;
+ for (size_type i=0, t=0; i < m_level_pointer_and_rank.size(); i+=2) {
+ t = sum_blocks;
+ sum_blocks += m_level_pointer_and_rank[i];
+ m_level_pointer_and_rank[i] = t;
+ if (sum_blocks > t) {
+ ++m_max_level;
+ last_block_size = sum_blocks - t;
+ }
+ }
+ m_overflow = bit_vector(sum_blocks - last_block_size, 0);
+ m_data.resize(sum_blocks);
+
+ assert(last_block_size > 0);
+
+// (3) Enter block and overflow data
+ int_vector<64> cnt = m_level_pointer_and_rank;
+ const uint64_t mask = bits::lo_set[t_b];
+
+ for (size_type i=0, j=0; i < n; ++i) {
+ val=v_buf[i];
+ j = cnt[0]++;
+ m_data[ j ] = val & mask;
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 = 2;
+ while (val) {
+ m_overflow[j] = 1;
+ // increase counter for current level by 1
+ j = cnt[level_x_2]++;
+ m_data[ j ] = val & mask;
+ val >>= t_b; // shift value b bits to the right
+ level_x_2 += 2; // increase level by 1
+ }
+ }
+
+// (4) Initialize rank data structure for m_overflow and precalc rank for
+// pointers
+ util::init_support(m_overflow_rank, &m_overflow);
+ for (size_type i=0; 2*i < m_level_pointer_and_rank.size() and
+ m_level_pointer_and_rank[2*i] < m_overflow.size(); ++i) {
+ m_level_pointer_and_rank[2*i+1] = m_overflow_rank(
+ m_level_pointer_and_rank[2*i]);
+ }
+}
+
+template<uint8_t t_b, typename t_rank>
+dac_vector<>::size_type dac_vector<t_b, t_rank>::serialize(std::ostream& out, structure_tree_node* v, std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_data.serialize(out, child, "data");
+ written_bytes += m_overflow.serialize(out, child, "overflow");
+ written_bytes += m_overflow_rank.serialize(out, child, "overflow_rank");
+ written_bytes += m_level_pointer_and_rank.serialize(out,
+ child, "level_pointer_and_rank");
+ written_bytes += write_member(m_max_level, out, child, "max_level");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/enc_vector.hpp b/include/sdsl/enc_vector.hpp
new file mode 100644
index 0000000..a4731c3
--- /dev/null
+++ b/include/sdsl/enc_vector.hpp
@@ -0,0 +1,352 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file enc_vector.hpp
+ \brief enc_vector.hpp contains the sdsl::enc_vector class.
+ \author Simon Gog
+*/
+#ifndef SDSL_ENC_VECTOR
+#define SDSL_ENC_VECTOR
+
+#include "int_vector.hpp"
+#include "coder.hpp"
+#include "iterators.hpp"
+
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+template<uint8_t t_width>
+struct enc_vector_trait {
+ typedef int_vector<0> int_vector_type;
+};
+
+template<>
+struct enc_vector_trait<32> {
+ typedef int_vector<32> int_vector_type;
+};
+
+template<>
+struct enc_vector_trait<64> {
+ typedef int_vector<64> int_vector_type;
+};
+
+//! A generic immutable space-saving vector class for unsigned integers.
+/*! A vector v is stored more space-efficiently by self-delimiting coding
+ * the deltas v[i+1]-v[i] (v[-1]:=0). Space of the structure and random
+ * access time to it can be controlled by a sampling parameter t_dens.
+ *
+ * \tparam t_coder Self-delimiting coder.
+ * \tparam t_dens Every t_dens-th element of v is sampled.
+ * \tparam t_width Width of the int_vector used to store the samples and pointers.
+ * This class is a parameter of csa_sada.
+ * @ingroup int_vector
+ */
+template<class t_coder=coder::elias_delta,
+ uint32_t t_dens = 128, uint8_t t_width=0>
+class enc_vector
+{
+ private:
+ static_assert(t_dens > 1 , "enc_vector: sample density must be larger than `1`");
+ public:
+ typedef uint64_t value_type;
+ typedef random_access_const_iterator<enc_vector> iterator;
+ typedef iterator const_iterator;
+ typedef const value_type reference;
+ typedef const value_type const_reference;
+ typedef const value_type* const_pointer;
+ typedef ptrdiff_t difference_type;
+ typedef int_vector<>::size_type size_type;
+ typedef t_coder coder;
+ typedef typename enc_vector_trait<t_width>::int_vector_type int_vector_type;
+ typedef iv_tag index_category;
+ static const uint32_t sample_dens = t_dens;
+
+ int_vector<0> m_z; // storage for encoded deltas
+ private:
+ int_vector_type m_sample_vals_and_pointer; // samples and pointers
+ size_type m_size = 0; // number of vector elements
+
+ void clear() {
+ m_z.resize(0);
+ m_size = 0;
+ m_sample_vals_and_pointer.resize(0);
+ }
+
+ public:
+ enc_vector() = default;
+ enc_vector(const enc_vector&) = default;
+ enc_vector(enc_vector&&) = default;
+ enc_vector& operator=(const enc_vector&) = default;
+ enc_vector& operator=(enc_vector&&) = default;
+
+ //! Constructor for a Container of unsigned integers.
+ /*! \param c A container of unsigned integers.
+ */
+ template<class Container>
+ enc_vector(const Container& c);
+
+ //! Constructor for an int_vector_buffer of unsigned integers.
+ /*
+ \param v_buf A int_vector_buf.
+ */
+ template<uint8_t int_width>
+ enc_vector(int_vector_buffer<int_width>& v_buf);
+
+ //! Default Destructor
+ ~enc_vector() { }
+
+ //! The number of elements in the enc_vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Return the largest size that this container can ever have.
+ static size_type max_size() {
+ return int_vector<>::max_size()/2;
+ }
+
+ //! Returns if the enc_vector is empty.
+ bool empty() const {
+ return 0==m_size;
+ }
+
+ //! Swap method for enc_vector
+ void swap(enc_vector& v);
+
+ //! Iterator that points to the first element of the enc_vector.
+ const const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Iterator that points to the position after the last element of the enc_vector.
+ const const_iterator end()const {
+ return const_iterator(this, this->m_size);
+ }
+
+ //! operator[]
+ /*! \param i Index. \f$ i \in [0..size()-1]\f$.
+ */
+ value_type operator[](size_type i)const;
+
+ //! Serialize the enc_vector to a stream.
+ /*! \param out Out stream to write the data structure.
+ \return The number of written bytes.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ //! Load the enc_vector from a stream.
+ void load(std::istream& in);
+
+ //! Returns the i-th sample of enc_vector
+ /*! \param i The index of the sample. 0 <= i < size()/get_sample_dens()
+ * \return The value of the i-th sample.
+ */
+ value_type sample(const size_type i) const;
+
+ uint32_t get_sample_dens() const {
+ return t_dens;
+ }
+
+ /*!
+ * \param i The index of the sample for which all values till the next sample should be decoded. 0 <= i < size()/get_sample_dens()
+ * \param it A pointer to a uint64_t vector, whereto the values should be written
+ */
+ void get_inter_sampled_values(const size_type i, uint64_t* it)const {
+ *(it++) = 0;
+ if (i*t_dens + t_dens - 1 < size()) {
+ t_coder::template decode<true, true>(m_z.data(), m_sample_vals_and_pointer[(i<<1)+1], t_dens - 1, it);
+ } else {
+ assert(i*t_dens < size());
+ t_coder::template decode<true, true>(m_z.data(), m_sample_vals_and_pointer[(i<<1)+1], size()-i*t_dens - 1, it);
+ }
+ };
+};
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+inline typename enc_vector<t_coder, t_dens,t_width>::value_type enc_vector<t_coder, t_dens,t_width>::operator[](const size_type i)const
+{
+ assert(i+1 != 0);
+ assert(i < m_size);
+ size_type idx = i/get_sample_dens();
+ return m_sample_vals_and_pointer[idx<<1] + t_coder::decode_prefix_sum(m_z.data(), m_sample_vals_and_pointer[(idx<<1)+1], i-t_dens*idx);
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+inline typename enc_vector<t_coder, t_dens,t_width>::value_type enc_vector<t_coder, t_dens,t_width>::sample(const size_type i)const
+{
+ assert(i*get_sample_dens()+1 != 0);
+ assert(i*get_sample_dens() < m_size);
+ return m_sample_vals_and_pointer[i<<1];
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+void enc_vector<t_coder, t_dens,t_width>::swap(enc_vector<t_coder, t_dens,t_width>& v)
+{
+ if (this != &v) { // if v and _this_ are not the same object
+ m_z.swap(v.m_z);
+ m_sample_vals_and_pointer.swap(v.m_sample_vals_and_pointer);
+ std::swap(m_size, v.m_size);
+ }
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+template<class Container>
+enc_vector<t_coder, t_dens,t_width>::enc_vector(const Container& c)
+{
+ // clear bit_vectors
+ clear();
+
+ if (c.empty()) // if c is empty there is nothing to do...
+ return;
+ typename Container::const_iterator it = c.begin(), end = c.end();
+ typename Container::value_type v1 = *it, v2, max_sample_value=0, x;
+ size_type samples=0;
+ size_type z_size = 0;
+// (1) Calculate maximal value of samples and of deltas
+ for (size_type i=0, no_sample=0; it != end; ++it,++i, --no_sample) {
+ v2 = *it;
+ if (!no_sample) { // add a sample
+ no_sample = get_sample_dens();
+ if (max_sample_value < v2) max_sample_value = v2;
+ ++samples;
+ } else {
+ z_size += t_coder::encoding_length(v2-v1);
+ }
+ v1=v2;
+ }
+// (2) Write sample values and deltas
+ {
+ if (max_sample_value > z_size+1)
+ m_sample_vals_and_pointer.width(bits::hi(max_sample_value) + 1);
+ else
+ m_sample_vals_and_pointer.width(bits::hi(z_size+1) + 1);
+ m_sample_vals_and_pointer.resize(2*samples+2); // add 2 for last entry
+ util::set_to_value(m_sample_vals_and_pointer, 0);
+ typename int_vector_type::iterator sv_it = m_sample_vals_and_pointer.begin();
+ z_size = 0;
+ size_type no_sample=0;
+ for (it = c.begin(); it != end; ++it, --no_sample) {
+ v2 = *it;
+ if (!no_sample) { // add a sample
+ no_sample = get_sample_dens();
+ *sv_it = v2; ++sv_it;
+ *sv_it = z_size; ++sv_it;
+ } else {
+ x = v2-v1;
+ z_size += t_coder::encoding_length(x);
+ }
+ v1=v2;
+ }
+ *sv_it = 0; ++sv_it; // initialize
+ *sv_it = z_size+1; ++sv_it; // last entry
+
+ m_z = int_vector<>(z_size, 0, 1);
+ uint64_t* z_data = t_coder::raw_data(m_z);
+ uint8_t offset = 0;
+ no_sample = 0;
+ for (it = c.begin(); it != end; ++it, --no_sample) {
+ v2 = *it;
+ if (!no_sample) { // add a sample
+ no_sample = get_sample_dens();
+ } else {
+ t_coder::encode(v2-v1, z_data, offset);
+ }
+ v1=v2;
+ }
+ }
+ m_size = c.size();
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+template<uint8_t int_width>
+enc_vector<t_coder, t_dens,t_width>::enc_vector(int_vector_buffer<int_width>& v_buf)
+{
+ // clear bit_vectors
+ clear();
+ size_type n = v_buf.size();
+ if (n == 0) // if c is empty there is nothing to do...
+ return;
+ value_type v1=0, v2=0, max_sample_value=0;
+ size_type samples=0, z_size=0;
+ const size_type sd = get_sample_dens();
+// (1) Calculate maximal value of samples and of deltas
+ for (size_type i=0, no_sample = 0; i < n; ++i, --no_sample) {
+ v2 = v_buf[i];
+ if (!no_sample) { // is sample
+ no_sample = sd;
+ if (max_sample_value < v2) max_sample_value = v2;
+ ++samples;
+ } else {
+ z_size += t_coder::encoding_length(v2-v1);
+ }
+ v1 = v2;
+ }
+
+// (2) Write sample values and deltas
+// (a) Initialize array for sample values and pointers
+ if (max_sample_value > z_size+1)
+ m_sample_vals_and_pointer.width(bits::hi(max_sample_value) + 1);
+ else
+ m_sample_vals_and_pointer.width(bits::hi(z_size+1) + 1);
+ m_sample_vals_and_pointer.resize(2*samples+2); // add 2 for last entry
+ util::set_to_value(m_sample_vals_and_pointer, 0);
+
+// (b) Initilize bit_vector for encoded data
+ m_z = int_vector<>(z_size, 0, 1);
+ uint64_t* z_data = t_coder::raw_data(m_z);
+ uint8_t offset = 0;
+
+// (c) Write sample values and deltas
+ z_size = 0;
+ for (size_type i=0, j=0, no_sample = 0; i < n; ++i, --no_sample) {
+ v2 = v_buf[i];
+ if (!no_sample) { // is sample
+ no_sample = sd;
+ m_sample_vals_and_pointer[j++] = v2; // write samples
+ m_sample_vals_and_pointer[j++] = z_size;// write pointers
+ } else {
+ z_size += t_coder::encoding_length(v2-v1);
+ t_coder::encode(v2-v1, z_data, offset); // write encoded values
+ }
+ v1 = v2;
+ }
+ m_size = n;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+enc_vector<>::size_type enc_vector<t_coder, t_dens,t_width>::serialize(std::ostream& out, structure_tree_node* v, std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += m_z.serialize(out, child, "encoded deltas");
+ written_bytes += m_sample_vals_and_pointer.serialize(out, child, "samples_and_pointers");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+void enc_vector<t_coder, t_dens,t_width>::load(std::istream& in)
+{
+ read_member(m_size, in);
+ m_z.load(in);
+ m_sample_vals_and_pointer.load(in);
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/fast_cache.hpp b/include/sdsl/fast_cache.hpp
new file mode 100644
index 0000000..09c4c35
--- /dev/null
+++ b/include/sdsl/fast_cache.hpp
@@ -0,0 +1,39 @@
+
+#ifndef INCLUDED_SDSL_FAST_CACHE
+#define INCLUDED_SDSL_FAST_CACHE
+
+#include "int_vector.hpp"
+
+namespace sdsl
+{
+
+#define CACHE_SIZE 0x3FFULL
+
+struct fast_cache {
+ typedef int_vector<>::size_type size_type;
+ size_type m_table[2*(CACHE_SIZE+1)];
+ // Constructor
+ fast_cache() {
+ for (size_type i=0; i < (CACHE_SIZE+1); ++i) {
+ m_table[i<<1] = (size_type)-1;
+ }
+ }
+ // Returns true if the request i is cached and
+ // x is set to the answer of request i
+ bool exists(size_type i, size_type& x) {
+ if (m_table[(i&CACHE_SIZE)<<1 ] == i) {
+ x = m_table[((i&CACHE_SIZE)<<1) + 1 ];
+ return true;
+ } else
+ return false;
+ }
+ // Writes the answer for request i to the cache
+ void write(size_type i, size_type x) {
+ m_table[(i&CACHE_SIZE)<<1 ] = i;
+ m_table[((i&CACHE_SIZE)<<1) + 1 ] = x;
+ }
+};
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/int_vector.hpp b/include/sdsl/int_vector.hpp
new file mode 100644
index 0000000..b61795c
--- /dev/null
+++ b/include/sdsl/int_vector.hpp
@@ -0,0 +1,1446 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file int_vector.hpp
+ \brief int_vector.hpp contains the sdsl::int_vector class.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_INT_VECTOR
+#define INCLUDED_SDSL_INT_VECTOR
+
+#include "bits.hpp"
+#include "structure_tree.hpp"
+#include "util.hpp"
+#include "io.hpp"
+#include "config.hpp"
+#include "uintx_t.hpp"
+
+#include "memory_management.hpp"
+#include "ram_fs.hpp"
+#include "sfstream.hpp"
+
+#include <iosfwd> // forward declaration of ostream
+#include <stdexcept> // for exceptions
+#include <iostream> // for cerr
+#include <typeinfo>
+#include <cassert>
+#include <iterator>
+#include <cstdlib>
+#include <cstddef>
+#include <ctime> // for rand initialization
+#include <cstring> // for memcpy
+#include <ostream>
+#include <istream>
+#include <string>
+#include <initializer_list>
+#include <type_traits>
+#include <vector>
+
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+typedef uint64_t std_size_type_for_int_vector;
+
+template<uint8_t t_width=0>
+class int_vector;
+
+template<class int_vector_type>
+class mm_item;
+
+namespace algorithm
+{
+template<uint8_t t_width>
+static void calculate_sa(const unsigned char* c,
+ typename int_vector<t_width>::size_type len,
+ int_vector<t_width>& sa);
+}
+
+
+//! bit_vector is a specialization of the int_vector.
+typedef int_vector<1> bit_vector;
+
+template<class t_int_vector>
+class int_vector_reference;
+
+template<class t_int_vector>
+class int_vector_iterator_base;
+
+template<class t_int_vector>
+class int_vector_iterator;
+
+template<class t_int_vector>
+class int_vector_const_iterator;
+
+template<uint8_t t_width>
+class int_vector_mapper;
+
+template<uint8_t b, uint8_t t_patter_len> // forward declaration
+class rank_support_v;
+
+class rank_support;
+
+class select_support;
+
+template<uint8_t t_bit_pattern, uint8_t t_pattern_len>
+class select_support_mcl;
+
+namespace coder
+{
+class fibonacci;
+class elias_delta;
+class elias_gamma;
+template<uint8_t t_width> class comma;
+}
+
+template<uint8_t t_width>
+struct int_vec_category_trait {
+ typedef iv_tag type;
+};
+
+template<>
+struct int_vec_category_trait<1> {
+ typedef bv_tag type;
+};
+
+template<uint8_t t_width>
+struct int_vector_trait {
+ typedef uint64_t value_type;
+ typedef int_vector<t_width> int_vector_type;
+ typedef int_vector_reference<int_vector_type> reference;
+ typedef const uint64_t const_reference;
+ typedef uint8_t int_width_type;
+ typedef int_vector_iterator<int_vector_type> iterator;
+ typedef int_vector_const_iterator<int_vector_type> const_iterator;
+
+ static iterator begin(int_vector_type* v, uint64_t*) {
+ return iterator(v, 0);
+ }
+ static iterator end(int_vector_type* v, uint64_t*, int_vector_size_type) {
+ return iterator(v, v->size()*v->width()) ;
+ }
+ static const_iterator begin(const int_vector_type* v, const uint64_t*) {
+ return const_iterator(v, 0);
+ }
+ static const_iterator end(const int_vector_type* v, const uint64_t*, int_vector_size_type) {
+ return const_iterator(v, v->size()*v->width());
+ }
+};
+
+template<>
+struct int_vector_trait<64> {
+ typedef uint64_t value_type;
+ typedef int_vector<64> int_vector_type;
+ typedef uint64_t& reference;
+ typedef const uint64_t const_reference;
+ typedef const uint8_t int_width_type;
+ typedef uint64_t* iterator;
+ typedef const uint64_t* const_iterator;
+
+ static iterator begin(int_vector_type*, uint64_t* begin) {
+ return begin;
+ }
+ static iterator end(int_vector_type*, uint64_t* begin, int_vector_size_type size) {
+ return begin+size;
+ }
+ static const_iterator begin(const int_vector_type*, const uint64_t* begin) {
+ return begin;
+ }
+ static const_iterator end(const int_vector_type*, const uint64_t* begin, int_vector_size_type size) {
+ return begin+size;
+ }
+};
+
+template<>
+struct int_vector_trait<32> {
+ typedef uint32_t value_type;
+ typedef int_vector<32> int_vector_type;
+ typedef uint32_t& reference;
+ typedef const uint32_t const_reference;
+ typedef const uint8_t int_width_type;
+ typedef uint32_t* iterator;
+ typedef const uint32_t* const_iterator;
+
+ static iterator begin(int_vector_type*, uint64_t* begin) {
+ return (uint32_t*)begin;
+ }
+ static iterator end(int_vector_type*, uint64_t* begin, int_vector_size_type size) {
+ return ((uint32_t*)begin)+size;
+ }
+ static const_iterator begin(const int_vector_type*, const uint64_t* begin) {
+ return (uint32_t*)begin;
+ }
+ static const_iterator end(const int_vector_type*, const uint64_t* begin, int_vector_size_type size) {
+ return ((uint32_t*)begin)+size;
+ }
+};
+
+template<>
+struct int_vector_trait<16> {
+ typedef uint16_t value_type;
+ typedef int_vector<16> int_vector_type;
+ typedef uint16_t& reference;
+ typedef const uint16_t const_reference;
+ typedef const uint8_t int_width_type;
+ typedef uint16_t* iterator;
+ typedef const uint16_t* const_iterator;
+
+ static iterator begin(int_vector_type*, uint64_t* begin) {
+ return (uint16_t*)begin;
+ }
+ static iterator end(int_vector_type*, uint64_t* begin, int_vector_size_type size) {
+ return ((uint16_t*)begin)+size;
+ }
+ static const_iterator begin(const int_vector_type*, const uint64_t* begin) {
+ return (uint16_t*)begin;
+ }
+ static const_iterator end(const int_vector_type*, const uint64_t* begin, int_vector_size_type size) {
+ return ((uint16_t*)begin)+size;
+ }
+};
+
+template<>
+struct int_vector_trait<8> {
+ typedef uint8_t value_type;
+ typedef int_vector<8> int_vector_type;
+ typedef uint8_t& reference;
+ typedef const uint8_t const_reference;
+ typedef const uint8_t int_width_type;
+ typedef uint8_t* iterator;
+ typedef const uint8_t* const_iterator;
+
+ static iterator begin(int_vector_type*, uint64_t* begin) {
+ return (uint8_t*)begin;
+ }
+ static iterator end(int_vector_type*, uint64_t* begin, int_vector_size_type size) {
+ return ((uint8_t*)begin)+size;
+ }
+ static const_iterator begin(const int_vector_type*, const uint64_t* begin) {
+ return (uint8_t*)begin;
+ }
+ static const_iterator end(const int_vector_type*, const uint64_t* begin, int_vector_size_type size) {
+ return ((uint8_t*)begin)+size;
+ }
+};
+
+//! A generic vector class for integers of width \f$w\in [1..64]\f$.
+/*! \author Simon Gog
+ *
+ * This generic vector class could be used to generate a vector
+ * that contains integers of fixed width \f$w\in [1..64]\f$.
+ *
+ * \tparam t_width Width of the integer. If set to `0` it is variable
+ * during runtime, otherwise fixed at compile time.
+ * @ingroup int_vector
+ */
+template<uint8_t t_width>
+class int_vector
+{
+ private:
+ static_assert(t_width <= 64 , "int_vector: width of must be at most 64bits.");
+ public:
+ typedef typename int_vector_trait<t_width>::value_type value_type;
+ typedef typename int_vector_trait<t_width>::iterator iterator;
+ typedef typename int_vector_trait<t_width>::const_iterator const_iterator;
+ typedef typename int_vector_trait<t_width>::reference reference;
+ typedef typename int_vector_trait<t_width>::const_reference const_reference;
+ typedef int_vector_reference<int_vector>* pointer;
+ typedef const value_type* const_pointer;
+ typedef ptrdiff_t difference_type;
+ typedef int_vector_size_type size_type;
+ typedef typename int_vector_trait<t_width>::int_width_type int_width_type;
+ typedef rank_support_v<1,1> rank_1_type;
+ typedef rank_support_v<0,1> rank_0_type;
+ typedef select_support_mcl<1,1> select_1_type;
+ typedef select_support_mcl<0,1> select_0_type;
+ typedef typename int_vec_category_trait<t_width>::type index_category;
+
+ friend struct int_vector_trait<t_width>;
+ friend class int_vector_iterator_base<int_vector>;
+ friend class int_vector_iterator<int_vector>;
+ friend class int_vector_const_iterator<int_vector>;
+ friend class int_vector_mapper<t_width>;
+ friend class coder::elias_delta;
+ friend class coder::elias_gamma;
+ friend class coder::fibonacci;
+ template<uint8_t> friend class coder::comma;
+ friend class memory_manager;
+
+ enum { fixed_int_width = t_width }; // make template parameter accessible
+
+ private:
+
+ size_type m_size; //!< Number of bits needed to store int_vector.
+ uint64_t* m_data; //!< Pointer to the memory for the bits.
+ int_width_type m_width; //!< Width of the integers.
+
+ public:
+
+ //! Constructor for int_vector.
+ /*! \param size Number of elements. Default value is 0.
+ \param default_value Initialize all value to `default value`.
+ \param int_width The width of each integer.
+ \sa resize, width
+ */
+ int_vector(size_type size = 0, value_type default_value = 0,
+ uint8_t int_width = t_width);
+
+ //! Constructor for initializer_list.
+ template<class t_T>
+ int_vector(std::initializer_list<t_T> il) : int_vector() {
+ resize(il.size());
+ size_type idx = 0;
+for (auto x : il) {
+ (*this)[idx++] = x;
+ }
+ }
+
+ //! Move constructor.
+ int_vector(int_vector&& v);
+
+ //! Copy constructor.
+ int_vector(const int_vector& v);
+
+ //! Destructor.
+ ~int_vector();
+
+ //! Equivalent to size() == 0.
+ bool empty() const {
+ return 0==m_size;
+ }
+
+ //! Swap method for int_vector.
+ void swap(int_vector& v);
+
+ //! Resize the int_vector in terms of elements.
+ /*! \param size The size to resize the int_vector in terms of elements.
+ */
+ void resize(const size_type size) {
+ bit_resize(size * width());
+ }
+
+ //! Resize the int_vector in terms of bits.
+ /*! \param size The size to resize the int_vector in terms of bits.
+ */
+ void bit_resize(const size_type size);
+
+ //! The number of elements in the int_vector.
+ /*! \sa max_size, bit_size, capacity
+ */
+ size_type size() const {
+ return m_size/m_width;
+ }
+
+ //! Maximum size of the int_vector.
+ /*! \sa size, bit_size, capacity
+ */
+ static size_type max_size() {
+ return ((size_type)1)<<(sizeof(size_type)*8-6);
+ }
+
+ //! The number of bits in the int_vector.
+ /*! \sa size, max_size, bit_size, capacity
+ */
+ size_type bit_size() const {
+ return m_size;
+ }
+
+ //! Returns the size of the occupied bits of the int_vector.
+ /*! The capacity of a int_vector is greater or equal to the
+ bit_size of the vector: capacity() >= bit_size().
+ \sa size, bit_size, max_size, capacity
+ */
+ size_type capacity() const {
+ return ((m_size+63)>>6)<<6;
+ }
+
+ //! Pointer to the raw data of the int_vector
+ /*! \returns Const pointer to the raw data of the int_vector
+ */
+ const uint64_t* data() const {
+ return m_data;
+ }
+
+ //! Pointer to the raw data of the int_vector
+ /*! \returns pointer to the raw data of the int_vector
+ */
+ uint64_t* data() {
+ return m_data;
+ }
+
+ //! Get the integer value of the binary string of length len starting at position idx in the int_vector.
+ /*! \param idx Starting index of the binary representation of the integer.
+ \param len Length of the binary representation of the integer. Default value is 64.
+ \returns The integer value of the binary string of length len starting at position idx.
+ \sa setInt, getBit, setBit
+ */
+ value_type get_int(size_type idx, const uint8_t len=64) const;
+
+ //! Set the bits from position idx to idx+len-1 to the binary representation of integer x.
+ /*! The bit at position idx represents the least significant bit(lsb), and the bit at
+ position idx+len-1 the most significant bit (msb) of x.
+ \param idx Starting index of the binary representation of x.
+ \param x The integer to store in the int_vector.
+ \param len The length used to store x in the int_vector. Default value is 64.
+ \sa getInt, getBit, setBit
+ */
+ void set_int(size_type idx, value_type x, const uint8_t len=64);
+
+ //! Returns the width of the integers which are accessed via the [] operator.
+ /*! \returns The width of the integers which are accessed via the [] operator.
+ \sa width
+ */
+ uint8_t width() const {
+ return m_width;
+ }
+
+ //! Sets the width of the integers which are accessed via the [] operator, if t_width equals 0.
+ /*! \param intWidth New width of the integers accessed via the [] operator.
+ \note This method has no effect if t_width is in the range [1..64].
+ \sa width
+ */
+ void width(uint8_t) { }
+
+ // Write data (without header) to a stream.
+ size_type write_data(std::ostream& out) const;
+
+ //! Serializes the int_vector to a stream.
+ /*! \return The number of bytes written to out.
+ * \sa load
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name = "", bool write_fixed_as_variable=false) const;
+
+ //! Load the int_vector for a stream.
+ void load(std::istream& in);
+
+ //! non const version of [] operator
+ /*! \param i Index the i-th integer of length width().
+ * \return A reference to the i-th integer of length width().
+ */
+ inline reference operator[](const size_type& i);
+
+ //! const version of [] operator
+ /*! \param i Index the i-th integer of length width().
+ * \return The value of the i-th integer of length width().
+ */
+ inline const_reference operator[](const size_type& i) const;
+
+ //! Assignment operator.
+ /*! \param v The vector v which should be assigned
+ */
+ int_vector& operator=(const int_vector& v);
+
+ //! Move assignment operator.
+ int_vector& operator=(int_vector&& v);
+
+ //! Equality operator for two int_vectors.
+ /*! Two int_vectors are equal if
+ * - capacities and sizes are equal and
+ * - width are equal and
+ * - the bits in the range [0..bit_size()-1] are equal.
+ */
+ bool operator==(const int_vector& v) const;
+
+ //! Inequality operator for two int_vectors.
+ /*! Two int_vectors are not equal if
+ * - capacities and sizes are not equal or
+ * - int widths are not equal or
+ * - the bits in the range [0..bit_size()-1] are not equal.
+ */
+ bool operator!=(const int_vector& v) const;
+
+ //! Less operator for two int_vectors
+ /*! int_vector w is less than v if
+ * - w[i]==v[i] for i<j and w[j]<v[j] with j in [0, min(w.size(), v.size()) )
+ * - or w[i]==v[i] for all i < min(w.size(), v.size()) and w.size()<v.size().
+ * \sa operator>
+ */
+ bool operator<(const int_vector& v) const;
+
+ //! Greater operator for two int_vectors
+ /*! int_vector w is greater than v if
+ * - w[i]==v[i] for i<j and w[j]>v[j] with j in [0, min(w.size(), v.size()) )
+ * - or w[i]==v[i] for all i < min(w.size(), v.size()) and w.size()>v.size().
+ */
+ bool operator>(const int_vector& v) const;
+
+ //! Less or equal operator
+ bool operator<=(const int_vector& v) const;
+
+ //! Greater of equal operator
+ bool operator>=(const int_vector& v) const;
+
+ //! Iterator that points to the first element of the int_vector.
+ /*! Time complexity guaranty is O(1).
+ */
+ const iterator begin() {
+ return int_vector_trait<t_width>::begin(this, m_data);
+ }
+
+ //! Iterator that points to the element after the last element of int_vector.
+ /*! Time complexity guaranty is O(1).
+ */
+ const iterator end() {
+ return int_vector_trait<t_width>::end(this, m_data, (m_size/m_width));
+ }
+
+ //! Const iterator that points to the first element of the int_vector.
+ const const_iterator begin() const {
+ return int_vector_trait<t_width>::begin(this, m_data);
+ }
+
+ //! Const iterator that points to the element after the last element of int_vector.
+ const const_iterator end() const {
+ return int_vector_trait<t_width>::end(this, m_data, (m_size/m_width));
+ }
+
+ //! Flip all bits of bit_vector
+ void flip() {
+ static_assert(1 == t_width, "int_vector: flip() is available only for bit_vector.");
+ }
+
+ //! Read the size and int_width of a int_vector
+ static void read_header(int_vector_size_type& size, int_width_type& int_width, std::istream& in) {
+ read_member(size, in);
+ if (0 == t_width) {
+ read_member(int_width, in);
+ }
+ }
+
+ //! Write the size and int_width of a int_vector
+ static uint64_t write_header(uint64_t size, uint8_t int_width, std::ostream& out) {
+ uint64_t written_bytes = write_member(size, out);
+ if (0 == t_width) {
+ written_bytes += write_member(int_width, out);
+ }
+ return written_bytes;
+ }
+
+
+ struct raw_wrapper {
+ const int_vector& vec;
+ raw_wrapper() = delete;
+ raw_wrapper(const int_vector& _vec) : vec(_vec) {}
+
+ size_type
+ serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ auto written_bytes = vec.write_data(out);
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+ };
+
+ const raw_wrapper raw = raw_wrapper(*this);
+};
+
+template<>
+void int_vector<0>::width(const uint8_t);
+
+template<>
+void bit_vector::flip();
+
+//! A proxy class that acts as a reference to an integer of length \p len bits in a int_vector.
+/*! \tparam t_int_vector The specific int_vector class.
+ */
+template<class t_int_vector>
+class int_vector_reference
+{
+ public:
+ typedef typename t_int_vector::value_type value_type;
+ private:
+ typename t_int_vector::value_type* const m_word;
+ const uint8_t m_offset;
+ const uint8_t m_len; //!< Length of the integer referred to in bits.
+ public:
+ //! Constructor for the reference class
+ /*! \param word Pointer to the corresponding 64bit word in the int_vector.
+ \param offset Offset to the starting bit (offset in [0..63])
+ \param len length of the integer, should be v->width()!!!
+ */
+ int_vector_reference(value_type* word, uint8_t offset, uint8_t len):
+ m_word(word),m_offset(offset),m_len(len) {};
+
+ //! Assignment operator for the proxy class
+ /*!
+ The integer x is assign to the referenced
+ position in the t_int_vector with the specified width
+ of the int_vector
+ \param x 64bit integer to assign
+ \return A const_reference to the assigned reference
+ */
+ int_vector_reference& operator=(value_type x) {
+ bits::write_int(m_word, x, m_offset, m_len);
+ return *this;
+ };
+
+ int_vector_reference& operator=(const int_vector_reference& x) {
+ return *this = value_type(x);
+ };
+
+ //! Cast the reference to a int_vector<>::value_type
+ operator value_type()const {
+ return bits::read_int(m_word, m_offset, m_len);
+ }
+
+ //! Prefix increment of the proxy object
+ int_vector_reference& operator++() {
+ value_type x = bits::read_int(m_word, m_offset, m_len);
+ bits::write_int(m_word, x+1, m_offset, m_len);
+ return *this;
+ }
+
+ //! Postfix increment of the proxy object
+ value_type operator++(int) {
+ value_type val = (typename t_int_vector::value_type)*this;
+ ++(*this);
+ return val;
+ }
+
+ //! Prefix decrement of the proxy object
+ int_vector_reference& operator--() {
+ value_type x = bits::read_int(m_word, m_offset, m_len);
+ bits::write_int(m_word, x-1, m_offset, m_len);
+ return *this;
+ }
+
+ //! Postfix decrement of the proxy object
+ value_type operator--(int) {
+ value_type val = (value_type)*this;
+ --(*this);
+ return val;
+ }
+
+ //! Add assign from the proxy object
+ int_vector_reference& operator+=(const value_type x) {
+ value_type w = bits::read_int(m_word, m_offset, m_len);
+ bits::write_int(m_word, w+x, m_offset, m_len);
+ return *this;
+ }
+
+ //! Subtract assign from the proxy object
+ int_vector_reference& operator-=(const value_type x) {
+ value_type w = bits::read_int(m_word, m_offset, m_len);
+ bits::write_int(m_word, w-x, m_offset, m_len);
+ return *this;
+ }
+
+ bool operator==(const int_vector_reference& x)const {
+ return value_type(*this) == value_type(x);
+ }
+
+ bool operator<(const int_vector_reference& x)const {
+ return value_type(*this) < value_type(x);
+ }
+};
+
+// For C++11
+template<class t_int_vector>
+inline void swap(int_vector_reference<t_int_vector> x,
+ int_vector_reference<t_int_vector> y)
+{
+ // TODO: more efficient solution?
+ typename int_vector_reference<t_int_vector>::value_type tmp = x;
+ x = y;
+ y = tmp;
+}
+
+// For C++11
+template<class t_int_vector>
+inline void swap(typename int_vector_reference<t_int_vector>::value_type& x,
+ int_vector_reference<t_int_vector> y)
+{
+ // TODO: more efficient solution?
+ typename int_vector_reference<t_int_vector>::value_type tmp = x;
+ x = y;
+ y = tmp;
+}
+
+// For C++11
+template<class t_int_vector>
+inline void swap(int_vector_reference<t_int_vector> x,
+ typename int_vector_reference<t_int_vector>::value_type& y)
+{
+ // TODO: more efficient solution?
+ typename int_vector_reference<t_int_vector>::value_type tmp = x;
+ x = y;
+ y = tmp;
+}
+
+// specialization for int_vector_reference for int_vector == bit_vector
+// special thanks to Timo Beller, who pointed out that the specialization is missing
+// Same implementation as in stl_bvector.h.
+template<>
+class int_vector_reference<bit_vector>
+{
+ public:
+ typedef bool value_type;
+ private:
+ uint64_t* const m_word;
+ uint64_t m_mask;
+ public:
+ //! Constructor for the reference class
+ /*! \param word Pointer to the corresponding 64bit word in the int_vector.
+ \param offset Offset to the starting bit (offset in [0..63])
+ */
+ int_vector_reference(uint64_t* word, uint8_t offset, uint8_t):
+ m_word(word),m_mask(1ULL<<offset) {};
+
+ //! Assignment operator for the proxy class
+ int_vector_reference& operator=(bool x) {
+ if (x)
+ *m_word |= m_mask;
+ else
+ *m_word &= ~m_mask;
+ return *this;
+ };
+
+ int_vector_reference& operator=(const int_vector_reference& x) {
+ return *this = bool(x);
+ };
+
+ //! Cast the reference to a bool
+ operator bool()const {
+ return !!(*m_word & m_mask);
+ }
+
+ bool operator==(const int_vector_reference& x)const {
+ return bool(*this) == bool(x);
+ }
+
+ bool operator<(const int_vector_reference& x)const {
+ return !bool(*this) && bool(x);
+ }
+};
+
+// For C++11
+template<>
+inline void swap(int_vector_reference<bit_vector> x,
+ int_vector_reference<bit_vector> y)
+{
+ // TODO: more efficient solution?
+ bool tmp = x;
+ x = y;
+ y = tmp;
+}
+
+// For C++11
+template<>
+inline void swap(bool& x,
+ int_vector_reference<bit_vector> y)
+{
+ // TODO: more efficient solution?
+ bool tmp = x;
+ x = y;
+ y = tmp;
+}
+
+// For C++11
+template<>
+inline void swap(int_vector_reference<bit_vector> x,
+ bool& y)
+{
+ // TODO: more efficient solution?
+ bool tmp = x;
+ x = y;
+ y = tmp;
+}
+
+
+
+template<class t_int_vector>
+class int_vector_iterator_base: public std::iterator<std::random_access_iterator_tag, typename t_int_vector::value_type, typename t_int_vector::difference_type>
+{
+ public:
+ typedef uint64_t size_type;
+ protected:
+ uint8_t m_offset;
+ uint8_t m_len;
+
+ public:
+ int_vector_iterator_base(uint8_t offset, uint8_t len):
+ m_offset(offset),m_len(len) {}
+
+ int_vector_iterator_base(const t_int_vector* v=nullptr, size_type idx=0):
+ m_offset(idx&0x3F), m_len(v==nullptr ? 0 : v->m_width) {}
+};
+
+template<class t_int_vector>
+class int_vector_iterator : public int_vector_iterator_base<t_int_vector>
+{
+ public:
+
+ typedef int_vector_reference<t_int_vector> reference;
+ typedef uint64_t value_type;
+ typedef int_vector_iterator iterator;
+ typedef reference* pointer;
+ typedef typename t_int_vector::size_type size_type;
+ typedef typename t_int_vector::difference_type difference_type;
+
+ friend class int_vector_const_iterator<t_int_vector>;
+ private:
+
+ using int_vector_iterator_base<t_int_vector>::m_offset; // make m_offset easy usable
+ using int_vector_iterator_base<t_int_vector>::m_len; // make m_len easy usable
+
+ typename t_int_vector::value_type* m_word;
+
+ public:
+
+ int_vector_iterator(t_int_vector* v=nullptr, size_type idx=0):
+ int_vector_iterator_base<t_int_vector>(v, idx),
+ m_word((v != nullptr) ? v->m_data + (idx>>6) : nullptr) {}
+
+
+ int_vector_iterator(const int_vector_iterator<t_int_vector>& it) :
+ int_vector_iterator_base<t_int_vector>(it), m_word(it.m_word) {
+ m_offset = it.m_offset;
+ m_len = it.m_len;
+ }
+
+ reference operator*() const {
+ return reference(m_word, m_offset, m_len);
+ }
+
+ //! Prefix increment of the Iterator
+ iterator& operator++() {
+ m_offset+=m_len;
+ if (m_offset >= 64) {
+ m_offset &= 0x3F;
+ ++m_word;
+ }
+ return *this;
+ }
+
+ //! Postfix increment of the Iterator
+ iterator operator++(int) {
+ int_vector_iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ //! Prefix decrement of the Iterator
+ iterator& operator--() {
+ m_offset-=m_len;
+ if (m_offset >= 64) {
+ m_offset &= 0x3F;
+ --m_word;
+ }
+ return *this;
+ }
+
+ //! Postfix decrement of the Iterator
+ iterator operator--(int) {
+ int_vector_iterator it = *this;
+ --(*this);
+ return it;
+ }
+
+ iterator& operator+=(difference_type i) {
+ if (i<0)
+ return *this -= (-i);
+ difference_type t = i*m_len;
+ m_word += (t>>6);
+ if ((m_offset+=(t&0x3F))&~0x3F) { // if new offset is >= 64
+ ++m_word; // add one to the word
+ m_offset&=0x3F; // offset = offset mod 64
+ }
+ return *this;
+ }
+
+ iterator& operator-=(difference_type i) {
+ if (i<0)
+ return *this += (-i);
+ difference_type t = i*m_len;
+ m_word -= (t>>6);
+ if ((m_offset-=(t&0x3F))&~0x3F) { // if new offset is < 0
+ --m_word;
+ m_offset&=0x3F;
+ }
+ return *this;
+ }
+
+ iterator& operator=(const int_vector_iterator<t_int_vector>& it) {
+ if (this != &it) {
+ m_word = it.m_word;
+ m_offset = it.m_offset;
+ m_len = it.m_len;
+ }
+ return *this;
+ }
+
+ iterator operator+(difference_type i) const {
+ iterator it = *this;
+ return it += i;
+ }
+
+ iterator operator-(difference_type i) const {
+ iterator it = *this;
+ return it -= i;
+ }
+
+ reference operator[](difference_type i) const {
+ return *(*this + i);
+ }
+
+ bool operator==(const int_vector_iterator& it)const {
+ return it.m_word == m_word && it.m_offset == m_offset;
+ }
+
+ bool operator!=(const int_vector_iterator& it)const {
+ return !(*this==it);
+ }
+
+ bool operator<(const int_vector_iterator& it)const {
+ if (m_word == it.m_word)
+ return m_offset < it.m_offset;
+ return m_word < it.m_word;
+ }
+
+ bool operator>(const int_vector_iterator& it)const {
+ if (m_word == it.m_word)
+ return m_offset > it.m_offset;
+ return m_word > it.m_word;
+ }
+
+ bool operator>=(const int_vector_iterator& it)const {
+ return !(*this < it);
+ }
+
+ bool operator<=(const int_vector_iterator& it)const {
+ return !(*this > it);
+ }
+ inline difference_type operator-(const int_vector_iterator& it) {
+ return (((m_word - it.m_word)<<6) + m_offset - it.m_offset) / m_len;
+ }
+};
+
+//template<class t_int_vector>
+//void swap(const int_vector_iterator<t_int_vector> &x, const int_vector_iterator<t_int_vector> &y){
+// x->swap(*y);
+//}
+
+template<class t_int_vector>
+inline int_vector_iterator<t_int_vector> operator+(typename int_vector_iterator<t_int_vector>::difference_type n, const int_vector_iterator<t_int_vector>& it)
+{
+ return it+n;
+}
+
+template<class t_int_vector>
+class int_vector_const_iterator : public int_vector_iterator_base<t_int_vector>
+{
+ public:
+
+ typedef typename t_int_vector::value_type const_reference;
+ typedef const typename t_int_vector::value_type* pointer;
+ typedef int_vector_const_iterator const_iterator;
+ typedef typename t_int_vector::size_type size_type;
+ typedef typename t_int_vector::difference_type difference_type;
+
+ template<class X>
+ friend typename int_vector_const_iterator<X>::difference_type
+ operator-(const int_vector_const_iterator<X>& x, const int_vector_const_iterator<X>& y);
+ friend class int_vector_iterator<t_int_vector>;
+ friend class int_vector_iterator_base<t_int_vector>;
+
+ private:
+
+ using int_vector_iterator_base<t_int_vector>::m_offset; // make m_offset easy usable
+ using int_vector_iterator_base<t_int_vector>::m_len; // make m_len easy usable
+
+ const typename t_int_vector::value_type* m_word;
+
+ public:
+
+ int_vector_const_iterator(const t_int_vector* v=nullptr, size_type idx=0):
+ int_vector_iterator_base<t_int_vector>(v, idx),
+ m_word((v != nullptr) ? v->m_data + (idx>>6) : nullptr) {}
+
+ int_vector_const_iterator(const int_vector_const_iterator& it):
+ int_vector_iterator_base<t_int_vector>(it), m_word(it.m_word) {
+ m_offset = it.m_offset;
+ m_len = it.m_len;
+ }
+
+ int_vector_const_iterator(const int_vector_iterator<t_int_vector>& it):
+ m_word(it.m_word) {
+ m_offset = it.m_offset;
+ m_len = it.m_len;
+ }
+
+ const_reference operator*() const {
+ if (m_offset+m_len <= 64) {
+ return ((*m_word)>>m_offset)&bits::lo_set[m_len];
+ }
+ return ((*m_word)>>m_offset) |
+ ((*(m_word+1) & bits::lo_set[(m_offset+m_len)&0x3F])<<(64-m_offset));
+ }
+
+ //! Prefix increment of the Iterator
+ const_iterator& operator++() {
+ m_offset+=m_len;
+ if (m_offset >= 64) {
+ m_offset &= 0x3F;
+ ++m_word;
+ }
+ return *this;
+ }
+
+ //! Postfix increment of the Iterator
+ const_iterator operator++(int) {
+ int_vector_const_iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ //! Prefix decrement of the Iterator
+ const_iterator& operator--() {
+ m_offset-=m_len;
+ if (m_offset >= 64) {
+ m_offset &= 0x3F;
+ --m_word;
+ }
+ return *this;
+ }
+
+ //! Postfix decrement of the Iterator
+ const_iterator operator--(int) {
+ int_vector_const_iterator it = *this;
+ --(*this);
+ return it;
+ }
+
+ const_iterator& operator+=(difference_type i) {
+ if (i<0)
+ return *this -= (-i);
+ difference_type t = i*m_len;
+ m_word += (t>>6);
+ if ((m_offset+=(t&0x3F))&~0x3F) {// if new offset >= 64
+ ++m_word; // add one to the word
+ m_offset&=0x3F; // offset = offset mod 64
+ }
+ return *this;
+ }
+
+ const_iterator& operator-=(difference_type i) {
+ if (i<0)
+ return *this += (-i);
+ difference_type t = i*m_len;
+ m_word -= (t>>6);
+ if ((m_offset-=(t&0x3F))&~0x3F) {// if new offset is < 0
+ --m_word;
+ m_offset&=0x3F;
+ }
+ return *this;
+ }
+
+ const_iterator operator+(difference_type i) const {
+ const_iterator it = *this;
+ return it += i;
+ }
+
+ const_iterator operator-(difference_type i) const {
+ const_iterator it = *this;
+ return it -= i;
+ }
+
+ const_reference operator[](difference_type i) const {
+ return *(*this + i);
+ }
+
+ bool operator==(const int_vector_const_iterator& it)const {
+ return it.m_word == m_word && it.m_offset == m_offset;
+ }
+
+ bool operator!=(const int_vector_const_iterator& it)const {
+ return !(*this==it);
+ }
+
+ bool operator<(const int_vector_const_iterator& it)const {
+ if (m_word == it.m_word)
+ return m_offset < it.m_offset;
+ return m_word < it.m_word;
+ }
+
+ bool operator>(const int_vector_const_iterator& it)const {
+ if (m_word == it.m_word)
+ return m_offset > it.m_offset;
+ return m_word > it.m_word;
+ }
+
+ bool operator>=(const int_vector_const_iterator& it)const {
+ return !(*this < it);
+ }
+
+ bool operator<=(const int_vector_const_iterator& it)const {
+ return !(*this > it);
+ }
+
+};
+
+template<class t_int_vector>
+inline typename int_vector_const_iterator<t_int_vector>::difference_type
+operator-(const int_vector_const_iterator<t_int_vector>& x,
+ const int_vector_const_iterator<t_int_vector>& y)
+{
+ return (((x.m_word - y.m_word)<<6) + x.m_offset - y.m_offset) / x.m_len;
+}
+
+template<class t_int_vector>
+inline int_vector_const_iterator<t_int_vector>
+operator+(typename int_vector_const_iterator<t_int_vector>::difference_type n,
+ const int_vector_const_iterator<t_int_vector>& it)
+{
+ return it + n;
+}
+
+template<class t_bv>
+inline typename std::enable_if<std::is_same<typename t_bv::index_category ,bv_tag>::value, std::ostream&>::type
+operator<<(std::ostream& os, const t_bv& bv)
+{
+for (auto b : bv) {
+ os << b;
+ }
+ return os;
+}
+
+// ==== int_vector implementation ====
+
+template<uint8_t t_width>
+inline int_vector<t_width>::int_vector(size_type size, value_type default_value, uint8_t intWidth):
+ m_size(0), m_data(nullptr), m_width(t_width)
+{
+ width(intWidth);
+ resize(size);
+ util::set_to_value(*this, default_value); // new initialization
+}
+
+template<uint8_t t_width>
+inline int_vector<t_width>::int_vector(int_vector&& v) :
+ m_size(v.m_size), m_data(v.m_data), m_width(v.m_width)
+{
+ v.m_data = nullptr; // ownership of v.m_data now transfered
+ v.m_size = 0;
+}
+
+template<uint8_t t_width>
+inline int_vector<t_width>::int_vector(const int_vector& v):
+ m_size(0), m_data(nullptr), m_width(v.m_width)
+{
+ bit_resize(v.bit_size());
+ if (v.capacity() > 0) {
+ if (memcpy(m_data, v.data() ,v.capacity()/8)==nullptr) {
+ throw std::bad_alloc(); // LCOV_EXCL_LINE
+ }
+ }
+ width(v.m_width);
+}
+
+template<uint8_t t_width>
+int_vector<t_width>& int_vector<t_width>::operator=(const int_vector& v)
+{
+ if (this != &v) {// if v is not the same object
+ bit_resize(v.bit_size());
+ if (v.bit_size()>0) {
+ if (memcpy(m_data, v.data() ,v.capacity()/8)==nullptr) {
+ throw std::bad_alloc(); // LCOV_EXCL_LINE
+ }
+ }
+ width(v.width());
+ }
+ return *this;
+}
+
+template<uint8_t t_width>
+int_vector<t_width>& int_vector<t_width>::operator=(int_vector&& v)
+{
+ swap(v);
+ return *this;
+}
+
+// Destructor
+template<uint8_t t_width>
+int_vector<t_width>::~int_vector()
+{
+ memory_manager::clear(*this);
+}
+
+template<uint8_t t_width>
+void int_vector<t_width>::swap(int_vector& v)
+{
+ if (this != &v) { // if v and _this_ are not the same object
+ size_type size = m_size;
+ uint64_t* data = m_data;
+ uint8_t int_width = m_width;
+ m_size = v.m_size;
+ m_data = v.m_data;
+ width(v.m_width);
+ v.m_size = size;
+ v.m_data = data;
+ v.width(int_width);
+ }
+}
+
+template<uint8_t t_width>
+void int_vector<t_width>::bit_resize(const size_type size)
+{
+ memory_manager::resize(*this, size);
+}
+
+template<uint8_t t_width>
+auto int_vector<t_width>::get_int(size_type idx, const uint8_t len)const -> value_type
+{
+#ifdef SDSL_DEBUG
+if (idx+len > m_size) {
+throw std::out_of_range("OUT_OF_RANGE_ERROR: int_vector::get_int(size_type, uint8_t); idx+len > size()!");
+}
+if (len > 64) {
+throw std::out_of_range("OUT_OF_RANGE_ERROR: int_vector::get_int(size_type, uint8_t); len>64!");
+}
+#endif
+return bits::read_int(m_data+(idx>>6), idx&0x3F, len);
+}
+
+template<uint8_t t_width>
+inline void int_vector<t_width>::set_int(size_type idx, value_type x, const uint8_t len)
+{
+#ifdef SDSL_DEBUG
+ if (idx+len > m_size) {
+ throw std::out_of_range("OUT_OF_RANGE_ERROR: int_vector::set_int(size_type, uint8_t); idx+len > size()!");
+ }
+ if (len > 64) {
+ throw std::out_of_range("OUT_OF_RANGE_ERROR: int_vector::set_int(size_type, uint8_t); len>64!");
+ }
+#endif
+ bits::write_int(m_data+(idx>>6), x, idx&0x3F, len);
+}
+
+template<uint8_t t_width>
+inline auto int_vector<t_width>::operator[](const size_type& idx) -> reference {
+ assert(idx < this->size());
+ size_type i = idx * m_width;
+ return reference(this->m_data + (i>>6), i&0x3F, m_width);
+}
+
+// specialized [] operator for 64 bit access.
+template<>
+inline auto int_vector<64>::operator[](const size_type& idx) -> reference {
+ assert(idx < this->size());
+ return *(this->m_data+idx);
+}
+
+// specialized [] operator for 32 bit access.
+template<>
+inline auto int_vector<32>::operator[](const size_type& idx) -> reference {
+ assert(idx < this->size());
+ return *(((uint32_t*)(this->m_data))+idx);
+}
+
+// specialized [] operator for 16 bit access.
+template<>
+inline auto int_vector<16>::operator[](const size_type& idx) -> reference {
+ assert(idx < this->size());
+ return *(((uint16_t*)(this->m_data))+idx);
+}
+
+// specialized [] operator for 8 bit access.
+template<>
+inline auto int_vector<8>::operator[](const size_type& idx) -> reference {
+ assert(idx < this->size());
+ return *(((uint8_t*)(this->m_data))+idx);
+}
+
+template<uint8_t t_width>
+inline auto
+int_vector<t_width>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return get_int(idx * t_width, t_width);
+}
+
+template<>
+inline auto
+int_vector<0>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return get_int(idx * m_width, m_width);
+}
+
+template<>
+inline auto
+int_vector<64>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return *(this->m_data+idx);
+}
+
+template<>
+inline auto
+int_vector<32>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return *(((uint32_t*)this->m_data)+idx);
+}
+
+template<>
+inline auto
+int_vector<16>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return *(((uint16_t*)this->m_data)+idx);
+}
+
+template<>
+inline auto
+int_vector<8>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return *(((uint8_t*)this->m_data)+idx);
+}
+
+template<>
+inline auto
+int_vector<1>::operator[](const size_type& idx)const -> const_reference
+{
+ assert(idx < this->size());
+ return ((*(m_data+(idx>>6)))>>(idx&0x3F))&1;
+}
+template<uint8_t t_width>
+bool int_vector<t_width>::operator==(const int_vector& v)const
+{
+ if (capacity() != v.capacity())
+ return false;
+ if (bit_size() != v.bit_size())
+ return false;
+ if (empty())
+ return true;
+ const uint64_t* data1 = v.data();
+ const uint64_t* data2 = data();
+ for (size_type i=0; i < (capacity()>>6)-1; ++i) {
+ if (*(data1++) != *(data2++))
+ return false;
+ }
+ int8_t l = 64-(capacity()-bit_size());
+ return ((*data1)&bits::lo_set[l])==((*data2)&bits::lo_set[l]);
+}
+
+template<uint8_t t_width>
+bool int_vector<t_width>::operator<(const int_vector& v)const
+{
+ size_type min_size = size();
+ if (min_size > v.size())
+ min_size = v.size();
+ for (auto it = begin(), end = begin()+min_size, it_v = v.begin(); it!=end; ++it, ++it_v) {
+ if (*it == *it_v)
+ continue;
+ else
+ return *it < *it_v;
+ }
+ return size() < v.size();
+}
+
+template<uint8_t t_width>
+bool int_vector<t_width>::operator>(const int_vector& v)const
+{
+ size_type min_size = size();
+ if (min_size > v.size())
+ min_size = v.size();
+ for (auto it = begin(), end = begin()+min_size, it_v = v.begin(); it!=end; ++it, ++it_v) {
+ if (*it == *it_v)
+ continue;
+ else
+ return *it > *it_v;
+ }
+ return size() > v.size();
+}
+
+template<uint8_t t_width>
+bool int_vector<t_width>::operator<=(const int_vector& v)const
+{
+ return *this==v or *this<v;
+}
+
+template<uint8_t t_width>
+bool int_vector<t_width>::operator>=(const int_vector& v)const
+{
+ return *this==v or *this>v;
+}
+
+template<uint8_t t_width>
+bool int_vector<t_width>::operator!=(const int_vector& v)const
+{
+ return !(*this==v);
+}
+
+template<uint8_t t_width>
+typename int_vector<t_width>::size_type int_vector<t_width>::write_data(std::ostream& out) const
+{
+ size_type written_bytes = 0;
+ uint64_t* p = m_data;
+ size_type idx = 0;
+ while (idx+conf::SDSL_BLOCK_SIZE < (capacity()>>6)) {
+ out.write((char*) p, conf::SDSL_BLOCK_SIZE*sizeof(uint64_t));
+ written_bytes += conf::SDSL_BLOCK_SIZE*sizeof(uint64_t);
+ p += conf::SDSL_BLOCK_SIZE;
+ idx += conf::SDSL_BLOCK_SIZE;
+ }
+ out.write((char*) p, ((capacity()>>6)-idx)*sizeof(uint64_t));
+ written_bytes += ((capacity()>>6)-idx)*sizeof(uint64_t);
+ return written_bytes;
+}
+
+template<uint8_t t_width>
+typename int_vector<t_width>::size_type int_vector<t_width>::serialize(std::ostream& out,
+ structure_tree_node* v,
+ std::string name,
+ bool write_fixed_as_variable) const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ if (t_width > 0 and write_fixed_as_variable) {
+ written_bytes += int_vector<0>::write_header(m_size, t_width, out);
+ } else {
+ written_bytes += int_vector<t_width>::write_header(m_size, m_width, out);
+ }
+ written_bytes += write_data(out);
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<uint8_t t_width>
+void int_vector<t_width>::load(std::istream& in)
+{
+ size_type size;
+ int_vector<t_width>::read_header(size, m_width, in);
+
+ bit_resize(size);
+ uint64_t* p = m_data;
+ size_type idx = 0;
+ while (idx+conf::SDSL_BLOCK_SIZE < (capacity()>>6)) {
+ in.read((char*) p, conf::SDSL_BLOCK_SIZE*sizeof(uint64_t));
+ p += conf::SDSL_BLOCK_SIZE;
+ idx += conf::SDSL_BLOCK_SIZE;
+ }
+ in.read((char*) p, ((capacity()>>6)-idx)*sizeof(uint64_t));
+}
+
+}// end namespace sdsl
+
+#include "int_vector_buffer.hpp"
+
+#endif
diff --git a/include/sdsl/int_vector_buffer.hpp b/include/sdsl/int_vector_buffer.hpp
new file mode 100644
index 0000000..f7d15eb
--- /dev/null
+++ b/include/sdsl/int_vector_buffer.hpp
@@ -0,0 +1,530 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file int_vector_buffer.hpp
+ \brief int_vector_buffer.hpp contains the sdsl::int_vector_buffer class.
+ \author Maike Zwerger, Timo Beller and Simon Gog
+*/
+#ifndef INCLUDED_INT_VECTOR_BUFFER
+#define INCLUDED_INT_VECTOR_BUFFER
+
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <string>
+
+namespace sdsl
+{
+
+template<uint8_t t_width=0>
+class int_vector_buffer
+{
+ public:
+ class iterator;
+ typedef typename int_vector<t_width>::difference_type difference_type;
+ typedef typename int_vector<t_width>::value_type value_type;
+
+ private:
+ static_assert(t_width <= 64 , "int_vector_buffer: width must be at most 64 bits.");
+ sdsl::isfstream m_ifile;
+ sdsl::osfstream m_ofile;
+ std::string m_filename;
+ int_vector<t_width> m_buffer;
+ bool m_need_to_write = false;
+ // length of int_vector header in bytes: 0 for plain, 8 for int_vector<t_width> (0 < t_width), 9 for int_vector<0>
+ uint64_t m_offset = 0;
+ uint64_t m_buffersize = 8; // in elements! m_buffersize*width() must be a multiple of 8!
+ uint64_t m_size = 0; // size of int_vector_buffer
+ uint64_t m_begin = 0; // number in elements
+
+ //! Read block containing element at index idx.
+ void read_block(const uint64_t idx) {
+ m_begin = (idx/m_buffersize)*m_buffersize;
+ if (m_begin >= m_size) {
+ util::set_to_value(m_buffer, 0);
+ } else {
+ m_ifile.seekg(m_offset+(m_begin*width())/8);
+ assert(m_ifile.good());
+ m_ifile.read((char*) m_buffer.data(), (m_buffersize*width())/8);
+ if ((uint64_t)m_ifile.gcount() < (m_buffersize*width())/8) {
+ m_ifile.clear();
+ }
+ assert(m_ifile.good());
+ for (uint64_t i=m_size-m_begin; i<m_buffersize; ++i) {
+ m_buffer[i] = 0;
+ }
+ }
+ }
+
+ //! Write current block to file.
+ void write_block() {
+ if (m_need_to_write) {
+ m_ofile.seekp(m_offset+(m_begin*width())/8);
+ assert(m_ofile.good());
+ if (m_begin+m_buffersize >= m_size) {
+ //last block in file
+ uint64_t wb = ((m_size-m_begin)*width()+7)/8;
+ m_ofile.write((char*) m_buffer.data(), wb);
+ } else {
+ m_ofile.write((char*) m_buffer.data(), (m_buffersize*width())/8);
+ }
+ m_ofile.flush();
+ assert(m_ofile.good());
+ m_need_to_write = false;
+ }
+ }
+
+ //! Read value from idx.
+ uint64_t read(const uint64_t idx) {
+ assert(is_open());
+ assert(idx < m_size);
+ if (idx < m_begin or m_begin+m_buffersize <= idx) {
+ write_block();
+ read_block(idx);
+ }
+ return m_buffer[idx-m_begin];
+ }
+
+ //! Write value to idx.
+ void write(const uint64_t idx, const uint64_t value) {
+ assert(is_open());
+ // If idx is not in current block, write current block and load needed block
+ if (idx < m_begin or m_begin+m_buffersize <= idx) {
+ write_block();
+ read_block(idx);
+ }
+ if (m_size <= idx) {
+ m_size = idx+1;
+ }
+ m_need_to_write = true;
+ m_buffer[idx-m_begin] = value;
+ }
+
+ public:
+
+ //! Constructor.
+ int_vector_buffer() {
+ m_buffer = int_vector<t_width>();
+ }
+
+ //! Constructor for int_vector_buffer.
+ /*! \param filename File that contains the data read from / written to.
+ * \param mode Openmode:
+ * std::ios::in opens an existing file (that must exist already),
+ * std::ios::out creates a new file (that may exist already).
+ * \param buffersize Buffersize in bytes. This has to be a multiple of 8, if not the next multiple of 8 will be taken
+ * \param int_width The width of each integer.
+ * \param is_plain If false (default) the file will be interpreted as int_vector.
+ * If true the file will be interpreted as plain array with t_width bits per integer.
+ * In second case (is_plain==true), t_width must be 8, 16, 32 or 64.
+ */
+ int_vector_buffer(const std::string filename, std::ios::openmode mode=std::ios::in, const uint64_t buffer_size=1024*1024, const uint8_t int_width=t_width, const bool is_plain=false) {
+ m_filename = filename;
+ assert(!(mode&std::ios::app));
+ mode &= ~std::ios::app;
+ m_buffer.width(int_width);
+ if (is_plain) {
+ // is_plain is only allowed with width() in {8, 16, 32, 64}
+ assert(8==width() or 16==width() or 32==width() or 64==width());
+ } else {
+ m_offset = t_width ? 8 : 9;
+ }
+
+ // Open file for IO
+ m_ofile.open(m_filename, mode|std::ios::out|std::ios::binary);
+ assert(m_ofile.good());
+ m_ifile.open(m_filename, std::ios::in|std::ios::binary);
+ assert(m_ifile.good());
+ if (mode & std::ios::in) {
+ uint64_t size = 0;
+ if (is_plain) {
+ m_ifile.seekg(0, std::ios_base::end);
+ size = m_ifile.tellg()*8;
+ } else {
+ uint8_t width = 0;
+ int_vector<t_width>::read_header(size, width, m_ifile);
+ m_buffer.width(width);
+ }
+ assert(m_ifile.good());
+ m_size = size/width();
+ }
+ buffersize(buffer_size);
+ }
+
+ //! Move constructor.
+ int_vector_buffer(int_vector_buffer&& ivb) :
+ m_filename(std::move(ivb.m_filename)),
+ m_buffer(std::move(ivb.m_buffer)),
+ m_need_to_write(ivb.m_need_to_write),
+ m_offset(ivb.m_offset),
+ m_buffersize(ivb.m_buffersize),
+ m_size(ivb.m_size),
+ m_begin(ivb.m_begin) {
+ ivb.m_ifile.close();
+ ivb.m_ofile.close();
+ m_ifile.open(m_filename, std::ios::in|std::ios::binary);
+ m_ofile.open(m_filename, std::ios::in|std::ios::out|std::ios::binary);
+ assert(m_ifile.good());
+ assert(m_ofile.good());
+ // set ivb to default-constructor state
+ ivb.m_filename = "";
+ ivb.m_buffer = int_vector<t_width>();
+ ivb.m_need_to_write = false;
+ ivb.m_offset = 0;
+ ivb.m_buffersize = 8;
+ ivb.m_size = 0;
+ ivb.m_begin = 0;
+ }
+
+ //! Destructor.
+ ~int_vector_buffer() {
+ close();
+ }
+
+ //! Move assignment operator.
+ int_vector_buffer<t_width>& operator=(int_vector_buffer&& ivb) {
+ close();
+ ivb.m_ifile.close();
+ ivb.m_ofile.close();
+ m_filename = ivb.m_filename;
+ m_ifile.open(m_filename, std::ios::in|std::ios::binary);
+ m_ofile.open(m_filename, std::ios::in|std::ios::out|std::ios::binary);
+ assert(m_ifile.good());
+ assert(m_ofile.good());
+ // assign the values of ivb to this
+ m_buffer = (int_vector<t_width>&&)ivb.m_buffer;
+ m_need_to_write = ivb.m_need_to_write;
+ m_offset = ivb.m_offset;
+ m_buffersize = ivb.m_buffersize;
+ m_size = ivb.m_size;
+ m_begin = ivb.m_begin;
+ // set ivb to default-constructor state
+ ivb.m_filename = "";
+ ivb.m_buffer = int_vector<t_width>();
+ ivb.m_need_to_write = false;
+ ivb.m_offset = 0;
+ ivb.m_buffersize = 8;
+ ivb.m_size = 0;
+ ivb.m_begin = 0;
+ return *this;
+ }
+
+ //! Returns the width of the integers which are accessed via the [] operator.
+ uint8_t width() const {
+ return m_buffer.width();
+ }
+
+ //! Returns the number of elements currently stored.
+ uint64_t size() const {
+ return m_size;
+ }
+
+ //! Returns the filename.
+ std::string filename() const {
+ return m_filename;
+ }
+
+ //! Returns the buffersize in bytes
+ uint64_t buffersize() const {
+ assert(m_buffersize*width()%8==0);
+ return (m_buffersize*width())/8;
+ }
+
+ //! Set the buffersize in bytes
+ void buffersize(uint64_t buffersize) {
+ if (0ULL == buffersize)
+ buffersize = 8;
+ write_block();
+ if (0==(buffersize*8)%width()) {
+ m_buffersize = buffersize*8/width(); // m_buffersize might not be multiple of 8, but m_buffersize*width() is.
+ } else {
+ uint64_t element_buffersize = (buffersize*8)/width()+1; // one more element than fits into given buffersize in byte
+ m_buffersize = element_buffersize+7 - (element_buffersize+7)%8; // take next multiple of 8
+ }
+ m_buffer = int_vector<t_width>(m_buffersize, 0, width());
+ if (0!=m_buffersize) read_block(0);
+ }
+
+ //! Returns whether state of underlying streams are good
+ bool good() {
+ return m_ifile.good() and m_ofile.good();
+ }
+
+ //! Returns whether underlying streams are currently associated to a file
+ bool is_open() {
+ return m_ifile.is_open() and m_ofile.is_open();;
+ }
+
+ //! Delete all content and set size to 0
+ void reset() {
+ // reset file
+ assert(m_ifile.good());
+ assert(m_ofile.good());
+ m_ifile.close();
+ m_ofile.close();
+ m_ofile.open(m_filename, std::ios::out|std::ios::binary);
+ assert(m_ofile.good());
+ m_ifile.open(m_filename, std::ios::in|std::ios::binary);
+ assert(m_ifile.good());
+ assert(m_ofile.good());
+ // reset member variables
+ m_need_to_write = false;
+ m_size = 0;
+ // reset buffer
+ read_block(0);
+ }
+
+ // Forward declaration
+ class reference;
+
+ //! [] operator
+ /*! \param i Index the i-th integer of length width().
+ * \return A reference to the i-th integer of length width().
+ */
+ reference operator[](uint64_t idx) {
+ return reference(this, idx);
+ }
+
+ //! Appends the given element value to the end of the int_vector_buffer
+ void push_back(const uint64_t value) {
+ write(m_size, value);
+ }
+
+ //! Close the int_vector_buffer.
+ /*! It is not possible to read from / write into the int_vector_buffer after calling this method
+ * \param remove_file If true, the underlying file will be removed on closing.
+ */
+ void close(bool remove_file=false) {
+ if (is_open()) {
+ if (!remove_file) {
+ write_block();
+ if (0 < m_offset) { // in case of int_vector, write header and trailing zeros
+ uint64_t size = m_size*width();
+ m_ofile.seekp(0, std::ios::beg);
+ int_vector<t_width>::write_header(size, width(), m_ofile);
+ assert(m_ofile.good());
+ uint64_t wb = (size+7)/8;
+ if (wb%8) {
+ m_ofile.seekp(m_offset+wb);
+ assert(m_ofile.good());
+ m_ofile.write("\0\0\0\0\0\0\0\0", 8-wb%8);
+ assert(m_ofile.good());
+ }
+ }
+ }
+ m_ifile.close();
+ assert(m_ifile.good());
+ m_ofile.close();
+ assert(m_ofile.good());
+ if (remove_file) {
+ sdsl::remove(m_filename);
+ }
+ }
+ }
+
+ iterator begin() {
+ return iterator(*this, 0);
+ }
+
+ iterator end() {
+ return iterator(*this, size());
+ }
+
+ //! Swap method for int_vector_buffer.
+ void swap(int_vector_buffer<t_width>& ivb) {
+ if (this != &ivb) {
+ m_ifile.close();
+ ivb.m_ifile.close();
+ m_ofile.close();
+ ivb.m_ofile.close();
+ std::swap(m_filename, ivb.m_filename);
+ m_ifile.open(m_filename, std::ios::in|std::ios::binary);
+ assert(m_ifile.good());
+ m_ofile.open(m_filename, std::ios::in|std::ios::out|std::ios::binary);
+ assert(m_ofile.good());
+ ivb.m_ifile.open(ivb.m_filename, std::ios::in|std::ios::binary);
+ assert(ivb.m_ifile.good());
+ ivb.m_ofile.open(ivb.m_filename, std::ios::in|std::ios::out|std::ios::binary);
+ assert(ivb.m_ofile.good());
+ std::swap(m_buffer, ivb.m_buffer);
+ std::swap(m_need_to_write, ivb.m_need_to_write);
+ std::swap(m_offset, ivb.m_offset);
+ std::swap(m_buffersize, ivb.m_buffersize);
+ std::swap(m_size, ivb.m_size);
+ std::swap(m_begin, ivb.m_begin);
+ }
+ }
+
+ class reference
+ {
+ friend class int_vector_buffer<t_width>;
+ private:
+ int_vector_buffer<t_width>* const m_int_vector_buffer = nullptr;
+ uint64_t m_idx = 0;
+
+ reference() {}
+
+ reference(int_vector_buffer<t_width>* _int_vector_buffer, uint64_t _idx) :
+ m_int_vector_buffer(_int_vector_buffer), m_idx(_idx) {}
+
+ public:
+
+ //! Conversion to int for read operations
+ operator uint64_t ()const {
+ return m_int_vector_buffer->read(m_idx);
+ }
+
+ //! Assignment operator for write operations
+ reference& operator=(const uint64_t& val) {
+ m_int_vector_buffer->write(m_idx, val);
+ return *this;
+ }
+
+ //! Assignment operator
+ reference& operator=(reference& x) {
+ return *this = (uint64_t)(x);
+ };
+
+ //! Prefix increment of the proxy object
+ reference& operator++() {
+ uint64_t x = m_int_vector_buffer->read(m_idx);
+ m_int_vector_buffer->write(m_idx, x+1);
+ return *this;
+ }
+
+ //! Postfix increment of the proxy object
+ uint64_t operator++(int) {
+ uint64_t val = (uint64_t)*this;
+ ++(*this);
+ return val;
+ }
+
+ //! Prefix decrement of the proxy object
+ reference& operator--() {
+ uint64_t x = m_int_vector_buffer->read(m_idx);
+ m_int_vector_buffer->write(m_idx, x-1);
+ return *this;
+ }
+
+ //! Postfix decrement of the proxy object
+ uint64_t operator--(int) {
+ uint64_t val = (uint64_t)*this;
+ --(*this);
+ return val;
+ }
+
+ //! Add assign from the proxy object
+ reference& operator+=(const uint64_t x) {
+ uint64_t w = m_int_vector_buffer->read(m_idx);
+ m_int_vector_buffer->write(m_idx, w+x);
+ return *this;
+ }
+
+ //! Subtract assign from the proxy object
+ reference& operator-=(const uint64_t x) {
+ uint64_t w = m_int_vector_buffer->read(m_idx);
+ m_int_vector_buffer->write(m_idx, w-x);
+ return *this;
+ }
+
+ bool operator==(const reference& x)const {
+ return (uint64_t)*this == (uint64_t)x;
+ }
+
+ bool operator<(const reference& x)const {
+ return (uint64_t)*this < (uint64_t)x;
+ }
+ };
+
+ class iterator: public std::iterator<std::random_access_iterator_tag, value_type, difference_type>
+ {
+ private:
+ int_vector_buffer<t_width>& m_ivb;
+ uint64_t m_idx = 0;
+ public:
+
+ iterator() = delete;
+ iterator(int_vector_buffer<t_width>& ivb, uint64_t idx=0) : m_ivb(ivb), m_idx(idx) {}
+
+ iterator& operator++() {
+ ++m_idx;
+ return *this;
+ }
+
+ iterator operator++(int) {
+ iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ iterator& operator--() {
+ --m_idx;
+ return *this;
+ }
+
+ iterator operator--(int) {
+ iterator it = *this;
+ --(*this);
+ return it;
+ }
+
+ reference operator*()const {
+ return m_ivb[m_idx];
+ }
+
+ iterator& operator+=(difference_type i) {
+ if (i<0)
+ return *this -= (-i);
+ m_idx += i;
+ return *this;
+ }
+
+ iterator& operator-=(difference_type i) {
+ if (i<0)
+ return *this += (-i);
+ m_idx -= i;
+ return *this;
+ }
+
+ iterator operator+(difference_type i) const {
+ iterator it = *this;
+ return it += i;
+ }
+
+ iterator& operator-(difference_type i) const {
+ iterator it = *this;
+ return it -= i;
+ }
+
+ bool operator==(const iterator& it) const {
+ return &m_ivb == &(it.m_ivb) and m_idx == it.m_idx;
+ }
+
+ bool operator!=(const iterator& it) const {
+ return !(*this == it);
+ }
+ inline difference_type operator-(const iterator& it) {
+ return (m_idx - it.m_idx);
+ }
+ };
+};
+
+} // end of namespace
+
+#endif // include guard
diff --git a/include/sdsl/int_vector_io_wrappers.hpp b/include/sdsl/int_vector_io_wrappers.hpp
new file mode 100644
index 0000000..7638a91
--- /dev/null
+++ b/include/sdsl/int_vector_io_wrappers.hpp
@@ -0,0 +1,190 @@
+/*! \author Simon Gog (simon.gog at unimelb.edu.au)
+ * \file int_vector_io_wrappers.hpp
+ * \brief This file contains classes which could be used to encode and decode integer vectors when they are written
+ * to disk.
+ *
+ * So far we two coders:
+ * int_vector_(load/serialize)_wrapper is just a dummy class which does not change the writing and reading process
+ * int_vector_(load/serialize)_vbyte_wrapper encodes and decodes each element using vbyte (aka escaping) coding.
+ * int_vector_(load/serialize)_vlen_wrapper encodes and decodes each element using a variable length code (e.g. Delta/Gamma/Fibonacci code)
+ *
+ * TODO: more sophisticated coders which have in contrast to the implemented version an internal state
+ * after the initialization. Like a Huffman coder which calculates the Huffman tree at initialization.
+ */
+#ifndef INCLUDE_SDSL_INT_VECTOR_IO_WRAPPERS
+#define INCLUDE_SDSL_INT_VECTOR_IO_WRAPPERS
+
+#include <sdsl/int_vector.hpp>
+#include <sdsl/util.hpp>
+#include <sdsl/coder.hpp>
+
+#include <iostream>
+
+namespace sdsl
+{
+
+template<uint8_t fixedIntWidth=0>
+class int_vector_serialize_vbyte_wrapper
+{
+ public:
+ typedef int_vector<fixedIntWidth> int_vector_type;
+ typedef typename int_vector_type::size_type size_type;
+ typedef typename int_vector_type::value_type value_type;
+
+ private:
+ const int_vector_type& m_vec;
+
+ public:
+ int_vector_serialize_vbyte_wrapper(const int_vector_type& vec):m_vec(vec) {}
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ // (1) write size and int_width
+ written_bytes += _sdsl_serialize_size_and_int_width(out, fixedIntWidth, m_vec.width(), m_vec.bit_size());
+ // (2) write entries in vbyte coding
+ for (size_type i=0; i < m_vec.size(); ++i) {
+ value_type ww = m_vec[i];
+ uint8_t w = ww & 0x7F;
+ ww >>= 7;
+ while (ww > 0) {
+ w |= 0x80; // mark overflow bit
+ out.write((const char*)&w, sizeof(uint8_t)); // write byte
+ w = ww & 0x7F;
+ ww >>= 7;
+ ++written_bytes;
+ }
+ out.write((const char*)&w, sizeof(uint8_t)); // write without overflow bit
+ ++written_bytes;
+ }
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+};
+
+template<uint8_t fixedIntWidth=0>
+class int_vector_load_vbyte_wrapper
+{
+ public:
+ typedef int_vector<fixedIntWidth> int_vector_type;
+ typedef typename int_vector_type::size_type size_type;
+ typedef typename int_vector_type::value_type value_type;
+
+ private:
+ int_vector_type& m_vec;
+
+ public:
+ int_vector_load_vbyte_wrapper(int_vector_type& vec):m_vec(vec) {}
+
+ void load(std::istream& in) {
+ size_type size;
+ typename int_vector_type::int_width_type int_width;
+ // (1) read size and int_width
+ int_vector_trait<fixedIntWidth>::read_header(size, int_width, in);
+ // (2) resize the vector
+ m_vec.width(int_width);
+ m_vec.bit_resize(size);
+ // (3) read vbyte encoded entries an put them into the vector
+ size_type i = 0;
+ while (i < m_vec.size()) {
+ value_type ww=0;
+ uint8_t w=0;
+ value_type shift=0;
+ do {
+ in.read((char*)&w, sizeof(uint8_t));
+ ww |= (((value_type)(w&0x7F))<<shift);
+ shift += 7;
+ } while ((w&0x80) > 0);
+ m_vec[ i++ ] = ww;
+ }
+ }
+};
+
+template<class coder_type=coder::elias_delta>
+class int_vector_serialize_vlen_wrapper
+{
+ public:
+ typedef int_vector<> int_vector_type;
+ typedef typename int_vector_type::size_type size_type;
+ typedef typename int_vector_type::value_type value_type;
+
+ private:
+ const int_vector_type& m_vec;
+
+ public:
+ int_vector_serialize_vlen_wrapper(const int_vector_type& vec):m_vec(vec) {}
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ int_vector_type enc_vec;
+ coder_type::encode(m_vec, enc_vec);
+ written_bytes += enc_vec.serialize(out, child, "enc_vector");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+};
+
+template<class coder_type=coder::elias_delta>
+class int_vector_load_vlen_wrapper
+{
+ public:
+ typedef int_vector<> int_vector_type;
+ typedef typename int_vector_type::size_type size_type;
+ typedef typename int_vector_type::value_type value_type;
+
+ private:
+ int_vector_type& m_vec;
+
+ public:
+ int_vector_load_vlen_wrapper(int_vector_type& vec):m_vec(vec) {}
+
+ void load(std::istream& in) {
+ int_vector_type enc_vec;
+ enc_vec.load(in);
+ coder_type::decode(enc_vec, m_vec);
+ }
+};
+
+
+template<class int_vector_type=int_vector<> >
+class int_vector_serialize_wrapper
+{
+ public:
+ typedef typename int_vector_type::size_type size_type;
+
+ private:
+ const int_vector_type& m_vec;
+
+ public:
+ int_vector_serialize_wrapper(const int_vector_type& vec):m_vec(vec) {}
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return m_vec.serialize(out, v, name);
+ }
+};
+
+template<class int_vector_type=int_vector<> >
+class int_vector_load_wrapper
+{
+ public:
+ typedef typename int_vector_type::size_type size_type;
+ private:
+ int_vector_type& m_vec;
+
+ public:
+ int_vector_load_wrapper(int_vector_type& vec):m_vec(vec) {}
+ void load(std::istream& in) {
+ m_vec.load(in);
+ }
+};
+
+template<class int_vector_serialize_wrapper_type=int_vector_serialize_wrapper<> >
+class int_vector_serialize_min_overhead
+{
+
+};
+
+} // end namespace
+
+#endif // end include guard
diff --git a/include/sdsl/int_vector_mapper.hpp b/include/sdsl/int_vector_mapper.hpp
new file mode 100644
index 0000000..d4e06a9
--- /dev/null
+++ b/include/sdsl/int_vector_mapper.hpp
@@ -0,0 +1,288 @@
+#ifndef SDSL_INT_VECTOR_MAPPER
+#define SDSL_INT_VECTOR_MAPPER
+
+#include "int_vector.hpp"
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <cstdio>
+
+namespace sdsl {
+
+template <uint8_t t_width = 0>
+class int_vector_mapper {
+ static_assert(t_width <= 64,
+ "int_vector_mapper: width must be at most 64 bits.");
+public:
+ typedef typename int_vector<t_width>::difference_type difference_type;
+ typedef typename int_vector<t_width>::value_type value_type;
+ typedef typename int_vector<t_width>::size_type size_type;
+ typedef typename int_vector<t_width>::int_width_type width_type;
+public:
+ const size_type append_block_size = 1000000;
+private:
+ uint8_t* m_mapped_data = nullptr;
+ uint64_t m_file_size_bytes = 0;
+ off_t m_data_offset = 0;
+ int m_fd = -1;
+ int_vector<t_width> m_wrapper;
+ std::string m_file_name;
+ bool m_delete_on_close;
+public:
+ int_vector_mapper() = delete;
+ int_vector_mapper(const int_vector_mapper&) = delete;
+ int_vector_mapper& operator=(const int_vector_mapper&) = delete;
+public:
+ ~int_vector_mapper() {
+ if (m_mapped_data) {
+ if (m_data_offset) {
+ // update size in the on disk representation and
+ // truncate if necessary
+ uint64_t* size_in_file = (uint64_t*)m_mapped_data;
+ if (*size_in_file != m_wrapper.m_size) {
+ *size_in_file = m_wrapper.m_size;
+ }
+ if(t_width==0) {
+ // if size is variable and we map a sdsl vector
+ // we might have to update the stored width
+ uint8_t stored_width = m_mapped_data[8];
+ if (stored_width != m_wrapper.m_width) {
+ m_mapped_data[8] = m_wrapper.m_width;
+ }
+ }
+ }
+ // do we have to truncate?
+ size_type current_bit_size = m_wrapper.m_size;
+ size_type data_size_in_bytes = ((current_bit_size + 63) >> 6) << 3;
+ munmap(m_mapped_data, m_file_size_bytes);
+ if (m_file_size_bytes != data_size_in_bytes + m_data_offset) {
+ int tret = ftruncate(m_fd, data_size_in_bytes + m_data_offset);
+ if (tret == -1) {
+ std::string truncate_error
+ = std::string("int_vector_mapper: truncate error. ")
+ + std::string(strerror(errno));
+ throw std::runtime_error(truncate_error);
+ }
+ }
+ }
+ if (m_fd != -1) {
+ close(m_fd);
+ if(m_delete_on_close) {
+ sdsl::remove(m_file_name);
+ }
+ }
+ m_wrapper.m_data = nullptr;
+ m_wrapper.m_size = 0;
+ }
+ int_vector_mapper(int_vector_mapper&& ivm) {
+ m_wrapper.m_data = ivm.m_wrapper.m_data;
+ m_wrapper.m_size = ivm.m_wrapper.m_size;
+ m_wrapper.width(ivm.m_wrapper.width());
+ m_file_name = ivm.m_file_name;
+ m_delete_on_close = ivm.m_delete_on_close;
+ ivm.m_wrapper.m_data = nullptr;
+ ivm.m_wrapper.m_size = 0;
+ ivm.m_mapped_data = nullptr;
+ ivm.m_fd = -1;
+ }
+ int_vector_mapper& operator=(int_vector_mapper&& ivm) {
+ m_wrapper.m_data = ivm.m_wrapper.m_data;
+ m_wrapper.m_size = ivm.m_wrapper.m_size;
+ m_wrapper.width(ivm.m_wrapper.width());
+ m_file_name = ivm.m_file_name;
+ m_delete_on_close = ivm.m_delete_on_close;
+ ivm.m_wrapper.m_data = nullptr;
+ ivm.m_wrapper.m_size = 0;
+ ivm.m_mapped_data = nullptr;
+ ivm.m_fd = -1;
+ return (*this);
+ }
+ int_vector_mapper(const std::string& key,const cache_config& config)
+ : int_vector_mapper(cache_file_name(key, config)) {}
+ int_vector_mapper(const std::string filename,
+ bool is_plain = false,
+ bool delete_on_close = false) :
+ m_file_name(filename), m_delete_on_close(delete_on_close)
+ {
+ size_type size_in_bits = 0;
+ uint8_t int_width = t_width;
+ {
+ std::ifstream f(filename);
+ if (!f.is_open()) {
+ throw std::runtime_error(
+ "int_vector_mapper: file does not exist.");
+ }
+ if (!is_plain) {
+ int_vector<t_width>::read_header(size_in_bits, int_width, f);
+ }
+ }
+ m_file_size_bytes = util::file_size(filename);
+
+ if (!is_plain) {
+ m_data_offset = t_width ? 8 : 9;
+ } else {
+ if (8 != t_width and 16 != t_width and 32 != t_width and 64
+ != t_width) {
+ throw std::runtime_error("int_vector_mapper: plain vector can "
+ "only be of width 8, 16, 32, 64.");
+ }
+ size_in_bits = m_file_size_bytes * 8;
+ }
+
+ // open backend file
+ m_fd = open(filename.c_str(), O_RDWR);
+ if (m_fd == -1) {
+ std::string open_error
+ = std::string("int_vector_mapper: open file error. ")
+ + std::string(strerror(errno));
+ throw std::runtime_error(open_error);
+ }
+
+ // prepare wrapper and mmap
+ width(int_width);
+ bit_resize(size_in_bits);
+ }
+ std::string file_name() const { return m_file_name; }
+ width_type width() const { return m_wrapper.width(); }
+ void width(const uint8_t new_int_width) {
+ m_wrapper.width(new_int_width);
+ }
+ size_type size() const { return m_wrapper.size(); }
+ void bit_resize(const size_type bit_size) {
+ size_type new_size_in_bytes = ((bit_size + 63) >> 6) << 3;
+ if (m_file_size_bytes != new_size_in_bytes + m_data_offset) {
+ if (m_mapped_data) munmap(m_mapped_data, m_file_size_bytes);
+ int tret = ftruncate(m_fd, new_size_in_bytes + m_data_offset);
+ if (tret == -1) {
+ std::string truncate_error
+ = std::string("int_vector_mapper: truncate error. ")
+ + std::string(strerror(errno));
+ throw std::runtime_error(truncate_error);
+ }
+ m_file_size_bytes = new_size_in_bytes + m_data_offset;
+ }
+ m_mapped_data
+ = (uint8_t*)mmap(NULL, m_file_size_bytes, PROT_READ | PROT_WRITE,
+ MAP_SHARED, m_fd, 0);
+ if (m_mapped_data == MAP_FAILED) {
+ std::string mmap_error
+ = std::string("int_vector_mapper: mmap error. ")
+ + std::string(strerror(errno));
+ throw std::runtime_error(mmap_error);
+ }
+ auto ret = madvise(m_mapped_data, m_file_size_bytes, MADV_SEQUENTIAL);
+ if (ret == -1) {
+ perror("Error trying to hint sequential access");
+ }
+ // update wrapper
+ m_wrapper.m_data = (uint64_t*)(m_mapped_data + m_data_offset);
+ m_wrapper.m_size = bit_size;
+ }
+ void resize(const size_type size) {
+ size_type size_in_bits = size * width();
+ bit_resize(size_in_bits);
+ }
+ auto begin() -> typename int_vector<t_width>::iterator {
+ return m_wrapper.begin();
+ }
+ auto end() -> typename int_vector<t_width>::iterator {
+ return m_wrapper.end();
+ }
+ auto begin() const -> typename int_vector<t_width>::const_iterator {
+ return m_wrapper.begin();
+ }
+ auto end() const -> typename int_vector<t_width>::const_iterator {
+ return m_wrapper.end();
+ }
+ auto operator[](const size_type& idx) const
+ -> typename int_vector<t_width>::const_reference
+ {
+ return m_wrapper[idx];
+ }
+ auto operator[](const size_type& idx)
+ -> typename int_vector<t_width>::reference
+ {
+ return m_wrapper[idx];
+ }
+ const uint64_t* data() const { return m_wrapper.data(); }
+ uint64_t* data() { return m_wrapper.data(); }
+ value_type get_int(size_type idx, const uint8_t len = 64) const {
+ return m_wrapper.get_int(idx, len);
+ }
+ void set_int(size_type idx, value_type x, const uint8_t len = 64) {
+ m_wrapper.set_int(idx, x, len);
+ }
+ void push_back(value_type x) {
+ if (capacity() < size() + 1) {
+ size_type old_size = m_wrapper.m_size;
+ size_type size_in_bits = (size() + append_block_size) * width();
+ bit_resize(size_in_bits);
+ m_wrapper.m_size = old_size;
+ }
+ m_wrapper[size()] = x;
+ // update size in wrapper only
+ m_wrapper.m_size += width();
+ }
+ size_type capacity() const {
+ size_t data_size_in_bits = 8 * (m_file_size_bytes - m_data_offset);
+ return data_size_in_bits / width();
+ }
+ size_type bit_size() const {
+ return m_wrapper.bit_size();
+ }
+ template<class container>
+ bool operator==(const container& v) const {
+ return std::equal( begin(), end(), v.begin());
+ }
+ bool operator==(const int_vector<t_width>& v) const {
+ return m_wrapper == v;
+ }
+ bool operator==(const int_vector_mapper& v) const {
+ return m_wrapper == v.m_wrapper;
+ }
+ template<class container>
+ bool operator!=(const container& v) const {
+ return !(*this==v);
+ }
+ void flip() {
+ m_wrapper.flip();
+ }
+ bool empty() const {
+ return m_wrapper.empty();
+ }
+};
+
+template <uint8_t t_width = 0>
+class temp_file_buffer {
+private:
+ static std::string tmp_file(const std::string& dir) {
+ char tmp_file_name[1024] = {0};
+ sprintf (tmp_file_name, "%s/tmp_mapper_file_XXXXXX.sdsl",dir.c_str());
+ int fd = mkstemps(tmp_file_name,5);
+ if(fd == -1) {
+ throw std::runtime_error("could not create temporary file.");
+ }
+ close(fd);
+ return std::string(tmp_file_name,strlen(tmp_file_name));
+ }
+public:
+ static int_vector_mapper<t_width> create() {
+ auto file_name = tmp_file("/tmp");
+ return create(file_name);
+ }
+ static int_vector_mapper<t_width> create(const cache_config& config) {
+ auto file_name = tmp_file(config.dir);
+ return create(file_name);
+ }
+ static int_vector_mapper<t_width> create(const std::string& file_name) {
+ //write empty int_vector to init the file
+ int_vector<t_width> tmp_vector;
+ store_to_file(tmp_vector,file_name);
+ return int_vector_mapper<t_width>(file_name,false,true);
+ }
+};
+
+typedef int_vector_mapper<1> bit_vector_mapper;
+
+} // end of namespace
+
+#endif
diff --git a/include/sdsl/inv_perm_support.hpp b/include/sdsl/inv_perm_support.hpp
new file mode 100644
index 0000000..8ff5935
--- /dev/null
+++ b/include/sdsl/inv_perm_support.hpp
@@ -0,0 +1,219 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file inv_perm_support.hpp
+ \brief inv_perm_support.hpp contains a class which adds access to the
+ inverse of a permutation.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_INV_PERM_SUPPORT
+#define INCLUDED_SDSL_INV_PERM_SUPPORT
+
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include "bit_vectors.hpp"
+#include "rank_support.hpp"
+
+namespace sdsl
+{
+
+//! Class inv_perm_support adds access to the inverse of a permutation.
+/*!
+ * \tparam t_s Sampling parameter of the inverse permutation.
+ * \tparam t_bv Type of the bitvector used to indicate back-pointers.
+ * \tparam t_rank Type of rank_support to rank the indicator bitvector.
+ *
+ * This support class adds access to the inverse of a permutation in at
+ * most \(t_s\) steps. It takes about \(1/t_s \log n\) space, where \(n\)
+ * is the size of the supported permutation.
+ *
+ * \par References
+ * [1] J. Munro, R. Raman, V. Raman, S. Rao: ,,Succinct representation
+ * of permutations'', Proceedings of ICALP 2003
+ */
+template<uint64_t t_s=32, class t_bv=bit_vector, class t_rank=typename bit_vector::rank_1_type>
+class inv_perm_support
+{
+ public:
+ typedef int_vector<> iv_type;
+ typedef iv_type::size_type size_type;
+ typedef iv_type::value_type value_type;
+ typedef iv_type::difference_type difference_type;
+ typedef random_access_const_iterator<inv_perm_support> const_iterator;
+ typedef t_bv bit_vector_type;
+ typedef t_rank rank_type;
+ private:
+ const iv_type* m_v = nullptr; // pointer to supported permutation
+ iv_type m_back_pointer; // back pointers
+ bit_vector_type m_marked; // back pointer marking
+ rank_type m_rank_marked; // rank support for back pointer marking
+ public:
+
+ inv_perm_support() {};
+
+ inv_perm_support(const inv_perm_support& p) : m_v(p.m_v),
+ m_back_pointer(p.m_back_pointer), m_marked(p.m_marked),
+ m_rank_marked(p.m_rank_marked) {
+ m_rank_marked.set_vector(&m_marked);
+ }
+
+ inv_perm_support(inv_perm_support&& p) {
+ *this = std::move(p);
+ }
+
+ //! Constructor
+ inv_perm_support(const iv_type* v) : m_v(v) {
+ bit_vector marked = bit_vector(m_v->size(), 0);
+ bit_vector done = bit_vector(m_v->size(), 0);
+
+ size_type max_back_pointer = 0;
+ for (size_type i = 0; i < m_v->size(); ++i) {
+ if (!done[i]) {
+ done[i] = 1;
+ size_type back_pointer=i, j = i, j_new=0;
+ uint64_t steps = 0, all_steps = 0;
+ while ((j_new=(*m_v)[j]) != i) {
+ j = j_new;
+ done[j] = 1;
+ ++steps; ++all_steps;
+ if (t_s == steps) {
+ max_back_pointer = std::max(max_back_pointer, back_pointer);
+ marked[j] = 1;
+ steps = 0;
+ back_pointer = j;
+ }
+ }
+ if (all_steps > t_s) {
+ marked[i] = 1;
+ max_back_pointer = std::max(max_back_pointer, back_pointer);
+ }
+ }
+ }
+
+ m_marked = t_bv(std::move(marked));
+ util::init_support(m_rank_marked, &m_marked);
+
+ done = bit_vector(m_v->size(), 0);
+ size_type n_bp = m_rank_marked(m_v->size());
+ m_back_pointer = int_vector<>(n_bp, 0, bits::hi(max_back_pointer)+1);
+
+ for (size_type i = 0; i < m_v->size(); ++i) {
+ if (!done[i]) {
+ done[i] = 1;
+ size_type back_pointer = i, j = i, j_new=0;
+ uint64_t steps = 0, all_steps = 0;
+ while ((j_new=(*m_v)[j]) != i) {
+ j = j_new;
+ done[j] = 1;
+ ++steps; ++all_steps;
+ if (t_s == steps) {
+ m_back_pointer[m_rank_marked(j)] = back_pointer;
+ steps = 0;
+ back_pointer = j;
+ }
+ }
+ if (all_steps > t_s) {
+ m_back_pointer[m_rank_marked(i)] = back_pointer;
+ }
+ }
+ }
+ }
+
+ //! Access operator
+ value_type operator[](size_type i) const {
+ size_type j = i, j_new=0;
+ while ((j_new=(*m_v)[j]) != i) {
+ if (m_marked[j]) {
+ j = m_back_pointer[m_rank_marked(j)];
+ while ((j_new=(*m_v)[j]) != i) j = j_new;
+ } else {
+ j = j_new;
+ }
+ }
+ return j;
+ }
+
+ size_type size() const {
+ return nullptr == m_v ? 0 : m_v->size();
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ void set_vector(const iv_type* v) { m_v = v; }
+
+ //! Assignment operation
+ inv_perm_support& operator=(const inv_perm_support& p) {
+ if (this != &p) {
+ m_v = p.m_v;
+ m_back_pointer = p.m_back_pointer;
+ m_marked = p.m_marked;
+ m_rank_marked = p.m_rank_marked;
+ m_rank_marked.set_vector(&m_marked);
+ }
+ return *this;
+ }
+
+ //! Assignment move operation
+ inv_perm_support& operator=(inv_perm_support&& p) {
+ if (this != &p) {
+ m_v = std::move(p.m_v);
+ m_back_pointer = std::move(p.m_back_pointer);
+ m_marked = std::move(p.m_marked);
+ m_rank_marked = std::move(p.m_rank_marked);
+ m_rank_marked.set_vector(&m_marked);
+ }
+ return *this;
+ }
+
+ //! Swap operation
+ void swap(inv_perm_support& p) {
+ if (this != &p) {
+ m_back_pointer.swap(p.m_back_pointer);
+ m_marked.swap(p.m_marked);
+ util::swap_support(m_rank_marked, p.m_rank_marked, &m_marked, &(p.m_marked));
+ }
+ }
+
+ //! Serialize into stream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_back_pointer.serialize(out, child, "back_pointer");
+ written_bytes += m_marked.serialize(out, child, "marked");
+ written_bytes += m_rank_marked.serialize(out, child, "rank_marked");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load sampling from disk
+ void load(std::istream& in) {
+ m_back_pointer.load(in);
+ m_marked.load(in);
+ m_rank_marked.load(in, &m_marked);
+ }
+};
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/io.hpp b/include/sdsl/io.hpp
new file mode 100644
index 0000000..64e1731
--- /dev/null
+++ b/include/sdsl/io.hpp
@@ -0,0 +1,801 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file io.hpp
+ \brief io.hpp contains some methods for reading/writing sdsl structures.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_IO
+#define INCLUDED_SDSL_IO
+
+#include "util.hpp"
+#include "sdsl_concepts.hpp"
+#include "structure_tree.hpp"
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <cctype>
+
+namespace sdsl
+{
+
+template<typename T>
+void load_vector(std::vector<T>&, std::istream&);
+
+template<class T>
+uint64_t
+serialize_vector(const std::vector<T>&, std::ostream&,
+ sdsl::structure_tree_node* v=nullptr, std::string="");
+
+// has_serialize<X>::value is true if class X has
+// implement method serialize
+// Adapted solution from jrok's proposal:
+// http://stackoverflow.com/questions/87372/check-if-a-class-has-a-member-function-of-a-given-signature
+template<typename X>
+struct has_serialize {
+ template<typename T>
+ static constexpr auto check(T*)
+ -> typename
+ std::is_same<
+ decltype(std::declval<T>().serialize(
+ std::declval<std::ostream&>(),
+ std::declval<structure_tree_node*>(),
+ std::declval<std::string>()
+ )),
+ typename T::size_type>::type {return std::true_type();}
+ template<typename>
+ static constexpr std::false_type check(...) {return std::false_type();}
+ typedef decltype(check<X>(nullptr)) type;
+ static constexpr bool value = type::value;
+};
+
+// has_load<X>::value is true if class X has
+// implement method load
+template<typename X>
+struct has_load {
+ template<typename T>
+ static constexpr auto check(T*)
+ -> typename
+ std::is_same<
+ decltype(std::declval<T>().load(
+ std::declval<std::istream&>()
+ )),
+ void>::type {return std::true_type();}
+ template<typename>
+ static constexpr std::false_type check(...) {return std::false_type();}
+ typedef decltype(check<X>(nullptr)) type;
+ static constexpr bool value = type::value;
+};
+
+// Writes primitive-typed variable t to stream out
+template<class T>
+size_t write_member(const T& t, std::ostream& out, sdsl::structure_tree_node* v=nullptr, std::string name="")
+{
+ sdsl::structure_tree_node* child = sdsl::structure_tree::add_child(v, name, util::class_name(t));
+ out.write((char*)&t, sizeof(t));
+ size_t written_bytes = sizeof(t);
+ sdsl::structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+// Specialization for std::string
+template<>
+size_t write_member<std::string>(const std::string& t, std::ostream& out, sdsl::structure_tree_node* v, std::string name);
+
+// Writes primitive-typed variable t to stream out
+template<class T>
+void read_member(T& t, std::istream& in)
+{
+ in.read((char*)&t, sizeof(t));
+}
+
+// Specialization for std::string
+template<>
+void read_member<std::string>(std::string& t, std::istream& in);
+
+
+
+
+template<typename X>
+typename std::enable_if<has_serialize<X>::value,typename X::size_type>::type
+serialize(const X& x,
+ std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")
+{
+ return x.serialize(out, v, name);
+}
+
+template<typename X>
+typename std::enable_if<std::is_pod<X>::value,uint64_t>::type
+serialize(const X& x,
+ std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")
+{
+ return write_member(x, out, v, name);
+}
+
+template<typename X>
+uint64_t
+serialize(const std::vector<X>& x,
+ std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")
+{
+
+ return serialize(x.size(), out, v, name)
+ + serialize_vector(x, out, v, name);
+}
+
+
+template<typename X>
+typename std::enable_if<has_load<X>::value,void>::type
+load(X& x, std::istream& in)
+{
+ x.load(in);
+}
+
+template<typename X>
+typename std::enable_if<std::is_pod<X>::value,void>::type
+load(X& x, std::istream& in)
+{
+ read_member(x, in);
+}
+
+template<typename X>
+void load(std::vector<X>& x, std::istream& in)
+{
+ typename std::vector<X>::size_type size;
+ load(size, in);
+ x.resize(size);
+ load_vector(x, in);
+}
+
+//! Load sdsl-object v from a file.
+/*!
+ * \param v sdsl-
+ * \param file Name of the serialized file.
+ */
+template<class T>
+bool load_from_file(T& v, const std::string& file);
+
+//! Load an int_vector from a plain array of `num_bytes`-byte integers with X in \{0, 1,2,4,8\} from disk.
+// TODO: Remove ENDIAN dependency.
+template<class t_int_vec>
+bool load_vector_from_file(t_int_vec& v, const std::string& file, uint8_t num_bytes=1, uint8_t max_int_width=64)
+{
+ if ((uint8_t)0 == num_bytes) { // if byte size is variable read int_vector<0> from file
+ return load_from_file(v, file);
+ } else if (num_bytes == 'd') {
+ uint64_t x = 0, max_x = 0;
+ isfstream in(file);
+ if (!in) {
+ return false;
+ } else {
+ std::vector<uint64_t> tmp;
+ while (in >> x) {
+ tmp.push_back(x);
+ max_x = std::max(x, max_x);
+ }
+ v.width(bits::hi(max_x)+1); v.resize(tmp.size());
+ for (size_t i=0; i < tmp.size(); ++i) {
+ v[i] = tmp[i];
+ }
+ return true;
+ }
+ } else {
+ off_t file_size = util::file_size(file);
+ if (file_size == 0) {
+ v.resize(0);
+ return true;
+ }
+ if (file_size % num_bytes != 0) {
+ throw std::logic_error("file size "+util::to_string(file_size)+" of \""+ file
+ +"\" is not a multiple of "+util::to_string(num_bytes));
+ return false;
+ }
+ isfstream in(file);
+ if (in) {
+ v.width(std::min((int)8*num_bytes, (int)max_int_width));
+ v.resize(file_size / num_bytes);
+ if (8 == t_int_vec::fixed_int_width and 1 == num_bytes) { // if int_vector<8> is created from byte alphabet file
+ in.read((char*)v.data(), file_size);
+ } else {
+ size_t idx=0;
+ const size_t block_size = conf::SDSL_BLOCK_SIZE*num_bytes;
+ std::vector<uint8_t> buf(block_size);
+ // TODO: check for larger alphabets with num_bytes*8 = v::fixed_int_width
+
+ uint64_t x = 0; // value
+ uint8_t cur_byte = 0;
+ do {
+ in.read((char*)buf.data(), block_size);
+ size_t read = in.gcount();
+ uint8_t* begin = buf.data();
+ uint8_t* end = begin+read;
+ while (begin < end) {
+ x |= ((uint64_t)(*begin)) << (cur_byte*8);
+ ++cur_byte;
+ if (cur_byte == num_bytes) {
+ v[idx++] = x;
+ cur_byte = 0;
+ x = 0ULL;
+ }
+ ++begin;
+ }
+ } while (idx < v.size());
+ in.close();
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+//! Store a data structure to a file.
+/*! The data structure has to provide a serialize function.
+ * \param v Data structure to store.
+ * \param file Name of the file where to store the data structure.
+ * \param Return if the data structure was stored successfully
+ */
+template<class T>
+bool store_to_file(const T& v, const std::string& file);
+
+//! Specialization of store_to_file for a char array
+bool store_to_file(const char* v, const std::string& file);
+
+//! Specialization of store_to_file for int_vector
+template<uint8_t t_width>
+bool store_to_file(const int_vector<t_width>& v, const std::string& file, bool write_fixed_as_variable=false);
+
+
+//! Store an int_vector as plain int_type array to disk
+template<class int_type, class t_int_vec>
+bool store_to_plain_array(t_int_vec& v, const std::string& file)
+{
+ osfstream out(file);
+ if (out) {
+ for (typename t_int_vec::size_type i=0; i<v.size(); ++i) {
+ int_type x = v[i];
+ out.write((char*)&x, sizeof(int_type));
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+template<class T>
+size_t serialize_empty_object(std::ostream&, structure_tree_node* v=nullptr, std::string name="", const T* t=nullptr)
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*t));
+ size_t written_bytes = 0;
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+
+
+//! Get the size of a data structure in bytes.
+/*!
+ * \param v A reference to the data structure for which the size in bytes should be calculated.
+ */
+template<class T>
+typename T::size_type size_in_bytes(const T& t);
+
+//! Get the size of a data structure in mega bytes (MiB).
+/*!
+ * \param t A reference to the data structure for which the size in bytes should be calculated.
+ */
+template<class T>
+double size_in_mega_bytes(const T& t);
+
+struct nullstream : std::ostream {
+ struct nullbuf: std::streambuf {
+ int overflow(int c) {
+ return traits_type::not_eof(c);
+ }
+ int xputc(int) { return 0; }
+ std::streamsize xsputn(char const*, std::streamsize n) { return n; }
+ int sync() { return 0; }
+ } m_sbuf;
+ nullstream(): std::ios(&m_sbuf), std::ostream(&m_sbuf), m_sbuf() {}
+};
+
+//! Serialize each element of an std::vector
+/*!
+ * \param vec The vector which should be serialized.
+ * \param out Output stream to which should be written.
+ * \param v Structure tree node. Note: If all elements have the same
+ * structure, then it is tried to combine all elements (i.e.
+ * make one node w with size set to the cumulative sum of all
+ * sizes of the children)
+ */
+template<class T>
+uint64_t
+serialize_vector(const std::vector<T>& vec, std::ostream& out, sdsl::structure_tree_node* v, std::string name)
+{
+ if (vec.size() > 0) {
+ sdsl::structure_tree_node* child = sdsl::structure_tree::add_child(v, name, "std::vector<"+util::class_name(vec[0])+">");
+ size_t written_bytes = 0;
+ for (const auto& x : vec) {
+ written_bytes += serialize(x, out, child, "[]");
+ }
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ } else {
+ return 0;
+ }
+}
+
+
+//! Load all elements of a vector from a input stream
+/*! \param vec Vector whose elements should be loaded.
+ * \param in Input stream.
+ * \par Note
+ * The vector has to be resized prior the loading
+ * of its elements.
+ */
+template<class T>
+void load_vector(std::vector<T>& vec, std::istream& in)
+{
+ for (typename std::vector<T>::size_type i = 0; i < vec.size(); ++i) {
+ load(vec[i], in);
+ }
+}
+
+template<format_type F, typename X>
+void write_structure(const X& x, std::ostream& out)
+{
+ std::unique_ptr<structure_tree_node> st_node(new structure_tree_node("name","type"));
+ nullstream ns;
+ serialize(x, ns, st_node.get(), "");
+ if (st_node.get()->children.size() > 0) {
+ for (const auto& child: st_node.get()->children) {
+ sdsl::write_structure_tree<F>(child.second.get(), out);
+ }
+ }
+}
+
+template<format_type F, typename... Xs>
+void write_structure(std::ostream& out, Xs... xs)
+{
+ typedef std::unique_ptr<structure_tree_node> up_stn_type;
+ up_stn_type st_node(new structure_tree_node("name","type"));
+ _write_structure(st_node, xs...);
+ sdsl::write_structure_tree<F>(st_node.get(), out);
+}
+
+template<typename X, typename... Xs>
+void _write_structure(std::unique_ptr<structure_tree_node>& st_node, X x, Xs... xs)
+{
+ nullstream ns;
+ serialize(x, ns, st_node.get(), "");
+ _write_structure(st_node, xs...);
+}
+
+inline
+void _write_structure(std::unique_ptr<structure_tree_node>&) {}
+
+//! Internal function used by csXprintf
+uint64_t _parse_number(std::string::const_iterator& c, const std::string::const_iterator& end);
+
+//! Internal function used by csXprintf
+template<class t_csa>
+const t_csa& _idx_csa(const t_csa& t, csa_tag)
+{
+ return t;
+};
+
+//! Internal function used by csXprintf
+template<class t_cst>
+const typename t_cst::csa_type& _idx_csa(const t_cst& t, cst_tag)
+{
+ return t.csa;
+};
+
+//! Internal function used by csXprintf
+template<class t_csa>
+std::string _idx_lcp_val(const t_csa&, uint64_t, uint64_t, csa_tag)
+{
+ return "";
+}
+
+//! Internal function used by csXprintf
+template<class t_cst>
+std::string _idx_lcp_val(const t_cst& t, uint64_t i, uint64_t w, cst_tag)
+{
+ return util::to_string(t.lcp[i], w);
+}
+
+template<class t_csx, class t_alph=typename t_csx::alphabet_category>
+struct default_sentinel {
+ static const char value = '$';
+};
+
+template<class t_csx>
+struct default_sentinel<t_csx, byte_alphabet_tag> {
+ static const char value = '$';
+};
+
+template<class t_csx>
+struct default_sentinel<t_csx, int_alphabet_tag> {
+ static const char value = '0';
+};
+
+//! Prints members of CSAs and CSTs
+/*! This is a printf like method to write members of CSAs and CSTs into an outstream.
+ * \tparam t_idx Type of the index. Class should be of concept csa_tag or cst_tag.
+ * \param out Output stream.
+ * \param format Format string. See explanation below.
+ * \param idx CSA or CST object.
+ * \param sentinel Character which should replace the 0-symbol in BWT/ TEXT.
+ *
+ * \par Format string
+ * Each line of the output will be formatted according to the format string.
+ * All content, except tokens which start with `%` will be copied. Tokens
+ * which start with `%` will be replaced as follows (let w be a positive
+ * number. setw(w) is used to format single numbers):
+ *
+ * Token | Replacement | Comment
+ * -----------------------------------------------------------------------
+ * %[w]I | Row index i. |
+ * %[w]S | SA[i] |
+ * %[w]s | ISA[i] |
+ * %[w]P | PSI[i] |
+ * %[w]p | LF[i] |
+ * %[w]L | LCP[i] | only for CSTs
+ * %[w]B | BWT[i] |
+ * %[w[:W]]T | Print min(idx.size(),w) chars of each |
+ * | suffix, each char formatted by setw(W).|
+ * %% | % |
+ */
+template<class t_idx>
+void
+csXprintf(std::ostream& out, const std::string& format,
+ const t_idx& idx, char sentinel=default_sentinel<t_idx>::value)
+{
+ typename t_idx::index_category cat;
+ const typename t_idx::csa_type& csa = _idx_csa(idx, cat);
+ std::vector<std::string> res(csa.size());
+ for (std::string::const_iterator c = format.begin(), s=c; c != format.end(); s=c) {
+ while (c != format.end() and* c != '%') ++c; // string before the next `%`
+ if (c > s) { // copy format string part
+ std::vector<std::string> to_copy(csa.size(), std::string(s, c));
+ transform(res.begin(), res.end(), to_copy.begin(), res.begin(), std::plus<std::string>());
+ }
+ if (c == format.end()) break;
+ ++c; // skip `%`
+ uint64_t w = _parse_number(c, format.end()); // element width
+ if (c == format.end()) break;
+ uint64_t W = 0; // character width
+ if (':' == *c) {
+ ++c;
+ W = _parse_number(c, format.end());
+ }
+ if (c == format.end()) break;
+ for (uint64_t i=0; i<csa.size(); ++i) {
+ switch (*c) {
+ case 'I': res[i] += util::to_string(i,w); break;
+ case 'S': res[i] += util::to_string(csa[i],w); break;
+ case 's': res[i] += util::to_string(csa.isa[i],w); break;
+ case 'P': res[i] += util::to_string(csa.psi[i],w); break;
+ case 'p': res[i] += util::to_string(csa.lf[i],w); break;
+ case 'L': res[i] += _idx_lcp_val(idx,i,w, cat); break;
+ case 'B': if (0 == csa.bwt[i]) {
+ res[i] += util::to_string(sentinel,w);
+ } else {
+ res[i] += util::to_string(csa.bwt[i],w);
+ }
+ break;
+ case 'T': for (uint64_t k=0; (w>0 and k < w) or(0==w and k < csa.size()); ++k) {
+ if (0 == csa.text[(csa[i]+k)%csa.size()]) {
+ res[i] += util::to_string(sentinel, W);
+ } else {
+ res[i] += util::to_string(csa.text[(csa[i]+k)%csa.size()], W);
+ }
+ }
+ break;
+ case '%': res[i] += "%"; break;
+ }
+ }
+ ++c;
+ }
+ for (size_t i=0; i<res.size(); ++i) out << res[i] << std::endl;
+}
+
+
+
+//! Returns the file name of the resource.
+/*!
+ * \param key Resource key.
+ * \param config Cache configuration.
+ * \return The file name of the resource.
+ */
+std::string cache_file_name(const std::string& key,const cache_config& config);
+
+//! Returns the file name of the resource.
+/*!
+ * \param key Resource key.
+ * \param config Cache configuration.
+ * \return The file name of the resource.
+ */
+template<typename T>
+std::string cache_file_name(const std::string& key,const cache_config& config)
+{
+ return cache_file_name(key+"_"+util::class_to_hash(T()), config);
+}
+
+
+
+//! Register the existing resource specified by the key to the cache
+/*!
+ * \param key Resource key.
+ * \param config Cache configuration.
+ *
+ * Note: If the resource does not exist under the given key,
+ * it will be not added to the cache configuration.
+ */
+void register_cache_file(const std::string& key, cache_config& config);
+
+//! Checks if the resource specified by the key exists in the cache.
+/*!
+ \param key Resource key.
+ \param config Cache configuration.
+ \return True, if the file exists, false otherwise.
+*/
+bool cache_file_exists(const std::string& key, const cache_config& config);
+
+//! Checks if the resource specified by the key and type exists in the cache.
+/*!
+ \tparam T Type.
+ \param key Resource key.
+ \param config Cache configuration.
+ \return True, if the file exists, false otherwise.
+*/
+template<typename T>
+bool cache_file_exists(const std::string& key, const cache_config& config)
+{
+ return cache_file_exists(key+"_"+util::class_to_hash(T()), config);
+}
+
+//! Returns a name for a temporary file. I.e. the name was not used before.
+std::string tmp_file(const cache_config& config, std::string name_part="");
+
+//! Returns a name for a temporary file. I.e. the name was not used before.
+std::string tmp_file(const std::string& filename, std::string name_part="");
+
+template<class T>
+bool load_from_cache(T& v, const std::string& key, const cache_config& config, bool add_type_hash=false)
+{
+ std::string file;
+ if (add_type_hash) {
+ file = cache_file_name<T>(key, config);
+ } else {
+ file = cache_file_name(key, config);
+ }
+ if (load_from_file(v, file)) {
+ if (util::verbose) {
+ std::cerr << "Load `" << file << std::endl;
+ }
+ return true;
+ } else {
+ std::cerr << "WARNING: Could not load file '";
+ std::cerr << file << "'" << std::endl;
+ return false;
+ }
+}
+
+//! Stores the object v as a resource in the cache.
+/*!
+ * \param
+ */
+template<class T>
+bool store_to_cache(const T& v, const std::string& key, cache_config& config, bool add_type_hash=false)
+{
+ std::string file;
+ if (add_type_hash) {
+ file = cache_file_name<T>(key, config);
+ } else {
+ file = cache_file_name(key, config);
+ }
+ if (store_to_file(v, file)) {
+ config.file_map[std::string(key)] = file;
+ return true;
+ } else {
+ std::cerr<<"WARNING: store_to_cache: could not store file `"<< file <<"`" << std::endl;
+ return false;
+ }
+}
+
+//==================== Template functions ====================
+
+template<class T>
+typename T::size_type size_in_bytes(const T& t)
+{
+ if ((&t) == nullptr)
+ return 0;
+ nullstream ns;
+ return serialize(t, ns);
+}
+
+template<class T>
+double size_in_mega_bytes(const T& t)
+{
+ return size_in_bytes(t)/(1024.0*1024.0);
+}
+
+template<class T>
+void add_hash(const T& t, std::ostream& out)
+{
+ uint64_t hash_value = util::hashvalue_of_classname(t);
+ write_member(hash_value, out);
+}
+
+template<class T>
+bool store_to_file(const T& t, const std::string& file)
+{
+ osfstream out(file, std::ios::binary | std::ios::trunc | std::ios::out);
+ if (!out) {
+ if (util::verbose) {
+ std::cerr<<"ERROR: store_to_file not successful for: `"<<file<<"`"<<std::endl;
+ }
+ return false;
+ }
+ serialize(t,out);
+ out.close();
+ if (util::verbose) {
+ std::cerr<<"INFO: store_to_file: `"<<file<<"`"<<std::endl;
+ }
+ return true;
+}
+
+template<class T>
+bool store_to_checked_file(const T& t, const std::string& file)
+{
+ std::string checkfile = file+"_check";
+ osfstream out(checkfile, std::ios::binary | std::ios::trunc | std::ios::out);
+ if (!out) {
+ if (util::verbose) {
+ std::cerr<<"ERROR: store_to_checked_file not successful for: `"<<checkfile<<"`"<<std::endl;
+ }
+ return false;
+ }
+ add_hash(t, out);
+ out.close();
+ return store_to_file(t, file);
+}
+
+bool store_to_file(const char* v, const std::string& file);
+
+template<uint8_t t_width>
+bool store_to_file(const int_vector<t_width>& v, const std::string& file, bool write_fixed_as_variable)
+{
+ osfstream out(file, std::ios::binary | std::ios::trunc | std::ios::out);
+ if (!out) {
+ std::cerr<<"ERROR: util::store_to_file:: Could not open file `"<<file<<"`"<<std::endl;
+ return false;
+ } else {
+ if (util::verbose) {
+ std::cerr<<"INFO: store_to_file: `"<<file<<"`"<<std::endl;
+ }
+ }
+ v.serialize(out, nullptr, "", write_fixed_as_variable);
+ out.close();
+ return true;
+}
+
+template<uint8_t t_width>
+bool store_to_checked_file(const int_vector<t_width>& v, const std::string& file, bool write_fixed_as_variable)
+{
+ std::string checkfile = file+"_check";
+ osfstream out(checkfile, std::ios::binary | std::ios::trunc | std::ios::out);
+ if (!out) {
+ std::cerr<<"ERROR: util::store_to_checked_file: Could not open check file `"<<checkfile<<"`"<<std::endl;
+ return false;
+ } else {
+ if (util::verbose) {
+ std::cerr<<"INFO: store_to_checked_file: `"<<checkfile<<"`"<<std::endl;
+ }
+ }
+ add_hash(v, out);
+ out.close();
+ return store_to_file(v, file, write_fixed_as_variable);
+}
+
+template<class T>
+bool load_from_file(T& v, const std::string& file)
+{
+ isfstream in(file, std::ios::binary | std::ios::in);
+ if (!in) {
+ if (util::verbose) {
+ std::cerr << "Could not load file `" << file << "`" << std::endl;
+ }
+ return false;
+ }
+ load(v, in);
+ in.close();
+ if (util::verbose) {
+ std::cerr << "Load file `" << file << "`" << std::endl;
+ }
+ return true;
+}
+
+template<class T>
+bool load_from_checked_file(T& v, const std::string& file)
+{
+ isfstream in(file+"_check", std::ios::binary | std::ios::in);
+ if (!in) {
+ if (util::verbose) {
+ std::cerr << "Could not load check file `" << file << "_check`" << std::endl;
+ }
+ return false;
+ }
+ uint64_t hash_value;
+ read_member(hash_value, in);
+ if (hash_value != util::hashvalue_of_classname(v)) {
+ if (util::verbose) {
+ std::cerr << "File `" << file << "` is not an instance of the class `" << sdsl::util::demangle2(typeid(T).name()) << "`" << std::endl;
+ }
+ return false;
+ }
+ return load_from_file(v, file);
+}
+
+
+template<class t_iv>
+inline typename std::enable_if<
+std::is_same<typename t_iv::index_category ,iv_tag>::value or
+std::is_same<typename t_iv::index_category ,csa_tag>::value
+, std::ostream&>::type
+operator<<(std::ostream& os, const t_iv& v)
+{
+ for (auto it=v.begin(), end = v.end(); it != end; ++it) {
+ os << *it;
+ if (it+1 != end) os << " ";
+ }
+ return os;
+}
+
+
+template<class t_iv>
+inline typename std::enable_if<std::is_same<typename t_iv::index_category ,wt_tag>::value, std::ostream&>::type
+operator<<(std::ostream& os, const t_iv& v)
+{
+ for (auto it=v.begin(), end = v.end(); it != end; ++it) {
+ os << *it;
+ if (it+1 != end and std::is_same<typename t_iv::alphabet_category,int_alphabet_tag>::value) os << " ";
+ }
+ return os;
+}
+
+
+template<class t_int>
+inline typename std::enable_if<std::is_integral<t_int>::value, std::ostream&>::type
+operator<<(std::ostream& os, const std::vector<t_int>& v)
+{
+ for (auto it=v.begin(), end = v.end(); it != end; ++it) {
+ os << *it;
+ if (it+1 != end) os << " ";
+ }
+ return os;
+}
+
+
+
+
+}
+#endif
diff --git a/include/sdsl/iterators.hpp b/include/sdsl/iterators.hpp
new file mode 100644
index 0000000..eb5de02
--- /dev/null
+++ b/include/sdsl/iterators.hpp
@@ -0,0 +1,153 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file iterators.hpp
+ \brief iterators.hpp contains an generic iterator for random access containers.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_ITERATORS
+#define INCLUDED_SDSL_ITERATORS
+
+#include <iterator>
+
+namespace sdsl
+{
+
+//! Generic iterator for a random access container
+/*! \tparam t_rac Type of random access container.
+ */
+template<class t_rac>
+class random_access_const_iterator: public std::iterator<std::random_access_iterator_tag, typename t_rac::value_type, typename t_rac::difference_type>
+{
+ public:
+ typedef const typename t_rac::value_type const_reference;
+ typedef typename t_rac::size_type size_type;
+ typedef random_access_const_iterator<t_rac> iterator;
+ typedef typename t_rac::difference_type difference_type;
+
+ private:
+ const t_rac* m_rac;// pointer to the random access container
+ typename t_rac::size_type m_idx;
+
+ template<class t_RAC>
+ friend typename random_access_const_iterator<t_RAC>::difference_type operator-(const random_access_const_iterator<t_RAC>& x,
+ const random_access_const_iterator<t_RAC>& y);
+
+
+ public:
+ //! Constructor
+ random_access_const_iterator(const t_rac* rac, size_type idx = 0) : m_rac(rac), m_idx(idx) { }
+
+ //! Dereference operator for the Iterator.
+ const_reference operator*()const {
+ return (*m_rac)[m_idx];
+ }
+
+ //! Prefix increment of the Iterator.
+ iterator& operator++() {
+ ++m_idx;
+ return *this;
+ }
+
+ //! Postfix increment of the Iterator.
+ iterator operator++(int) {
+ random_access_const_iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ //! Prefix decrement of the Iterator.
+ iterator& operator--() {
+ --m_idx;
+ return *this;
+ }
+
+ //! Postfix decrement of the Iterator.
+ iterator operator--(int) {
+ random_access_const_iterator it = *this;
+ --(*this);
+ return it;
+ }
+
+ iterator& operator+=(difference_type i) {
+ if (i<0)
+ return *this -= (-i);
+ m_idx += i;
+ return *this;
+ }
+
+ iterator& operator-=(difference_type i) {
+ if (i<0)
+ return *this += (-i);
+ m_idx -= i;
+ return *this;
+ }
+
+ iterator operator+(difference_type i) const {
+ iterator it = *this;
+ return it += i;
+ }
+
+ iterator operator-(difference_type i) const {
+ iterator it = *this;
+ return it -= i;
+ }
+
+ const_reference operator[](difference_type i) const {
+ return *(*this + i);
+ }
+
+ bool operator==(const iterator& it)const {
+ return it.m_rac == m_rac && it.m_idx == m_idx;
+ }
+
+ bool operator!=(const iterator& it)const {
+ return !(*this==it);
+ }
+
+ bool operator<(const iterator& it)const {
+ return m_idx < it.m_idx;
+ }
+
+ bool operator>(const iterator& it)const {
+ return m_idx > it.m_idx;
+ }
+
+ bool operator>=(const iterator& it)const {
+ return !(*this < it);
+ }
+
+ bool operator<=(const iterator& it)const {
+ return !(*this > it);
+ }
+
+};
+
+template<class t_rac>
+inline typename random_access_const_iterator<t_rac>::difference_type operator-(const random_access_const_iterator<t_rac>& x, const random_access_const_iterator<t_rac>& y)
+{
+ return (typename random_access_const_iterator<t_rac>::difference_type)x.m_idx
+ - (typename random_access_const_iterator<t_rac>::difference_type)y.m_idx;
+}
+
+template<class t_rac>
+inline random_access_const_iterator<t_rac> operator+(typename random_access_const_iterator<t_rac>::difference_type n, const random_access_const_iterator<t_rac>& it)
+{
+ return it+n;
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/k2_treap.hpp b/include/sdsl/k2_treap.hpp
new file mode 100644
index 0000000..111cefc
--- /dev/null
+++ b/include/sdsl/k2_treap.hpp
@@ -0,0 +1,447 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file k2_treap.hpp
+ \brief k2_treap.hpp contains a compact k^2-treap.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_K2_TREAP
+#define INCLUDED_SDSL_K2_TREAP
+
+#include "sdsl/vectors.hpp"
+#include "sdsl/bits.hpp"
+#include "sdsl/k2_treap_helper.hpp"
+#include "sdsl/k2_treap_algorithm.hpp"
+#include <tuple>
+#include <algorithm>
+#include <climits>
+#include <vector>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A k^2-treap.
+/*! A k^2-treap is an indexing structure for a set of weighted points. The set
+ * consists of triples (x,y,w), where the first two components x and y are
+ * the coordinates of the point and w is the point's weight.
+ *
+ * The k^2 treap supports 4-sided range count queries and 4-sided prioritized
+ * range queries in 2d. Using the latter functionality it is also possible to
+ * support 6-sided range queries in 3d. An example can be found in
+ * examples/k2_treap_in_mem.cpp .
+ *
+ * The k^2-treap constructed in-place. The construct method expects either
+ * a vector of std::array<X,3> elements (each array represent a tuple x,y,w)
+ * or a file prefix FILE. In the latter case three serialized int_vector<>
+ * have to be present at FILE.x, FILE.y, and FILE.w. One int_vector<> per
+ * component.
+ *
+ * \par References
+ * [1] N. Brisaboa, G. de Bernardo, R. Konow, and G. Navarro:
+ * ,,$K^2$-Treaps: Range Top-$k$ Queries in Compact Space,
+ * Proceedings of SPIRE 2014.
+ */
+template<uint8_t t_k,
+ typename t_bv=bit_vector,
+ typename t_rank=typename t_bv::rank_1_type,
+ typename t_max_vec=dac_vector<>>
+class k2_treap
+{
+ static_assert(t_k>1, "t_k has to be larger than 1.");
+ static_assert(t_k<=16, "t_k has to be smaller than 17.");
+
+ public:
+ typedef int_vector<>::size_type size_type;
+ using node_type = k2_treap_ns::node_type;
+ using point_type = k2_treap_ns::point_type;
+ using t_p = k2_treap_ns::t_p;
+
+ enum { k = t_k };
+
+ private:
+ uint8_t m_t = 0;
+ t_bv m_bp;
+ t_rank m_bp_rank;
+ t_max_vec m_maxval;
+ std::vector<int_vector<>> m_coord;
+ int_vector<64> m_level_idx;
+
+ template<typename t_tv>
+ uint8_t get_t(const t_tv& v)
+ {
+ using namespace k2_treap_ns;
+ if (v.size() == 0) {
+ return 0;
+ }
+ using t_e = typename t_tv::value_type;
+ auto tupmax = [](t_e a) {
+ return std::max(std::get<0>(a),std::get<1>(a));
+ };
+ auto max_it = std::max_element(std::begin(v), std::end(v), [&](t_e a, t_e b) {
+ return tupmax(a) < tupmax(b);
+ });
+ uint64_t x = tupmax(*max_it);
+ uint8_t res = 0;
+ while (precomp<t_k>::exp(res) <= x) { ++res; }
+ return res;
+ }
+
+ public:
+ uint8_t& t = m_t;
+
+ k2_treap() = default;
+
+ k2_treap(const k2_treap& tr)
+ {
+ *this = tr;
+ }
+
+ k2_treap(k2_treap&& tr)
+ {
+ *this = std::move(tr);
+ }
+
+ //! Move assignment operator
+ k2_treap& operator=(k2_treap&& tr)
+ {
+ if (this != &tr) {
+ m_t = tr.m_t;
+ m_bp = std::move(tr.m_bp);
+ m_bp_rank = std::move(tr.m_bp_rank);
+ m_bp_rank.set_vector(&m_bp);
+ m_maxval = std::move(tr.m_maxval);
+ m_coord = std::move(tr.m_coord);
+ m_level_idx = std::move(tr.m_level_idx);
+ }
+ return *this;
+ }
+
+ //! Assignment operator
+ k2_treap& operator=(k2_treap& tr)
+ {
+ if (this != &tr) {
+ m_t = tr.m_t;
+ m_bp = tr.m_bp;
+ m_bp_rank = tr.m_bp_rank;
+ m_bp_rank.set_vector(&m_bp);
+ m_maxval = tr.m_maxval;
+ m_coord = tr.m_coord;
+ m_level_idx = tr.m_level_idx;
+ }
+ return *this;
+ }
+
+ //! Number of points in the 2^k treap
+ size_type
+ size() const
+ {
+ return m_maxval.size();
+ }
+
+ //! Swap operator
+ void swap(k2_treap& tr)
+ {
+ if (this != &tr) {
+ std::swap(m_t, tr.m_t);
+ m_bp.swap(tr.m_bp);
+ util::swap_support(m_bp_rank, tr.m_bp_rank, &m_bp, &(tr.m_bp));
+ m_maxval.swap(tr.m_maxval);
+ m_coord.swap(tr.m_coord);
+ m_level_idx.swap(tr.m_level_idx);
+ }
+ }
+
+ k2_treap(int_vector_buffer<>& buf_x,
+ int_vector_buffer<>& buf_y,
+ int_vector_buffer<>& buf_w)
+ {
+ using namespace k2_treap_ns;
+ typedef int_vector_buffer<>* t_buf_p;
+ std::vector<t_buf_p> bufs = {&buf_x, &buf_y, &buf_w};
+
+ auto max_element = [](int_vector_buffer<>& buf) {
+ uint64_t max_val = 0;
+ for (auto val : buf) {
+ max_val = std::max((uint64_t)val, max_val);
+ }
+ return max_val;
+ };
+
+ auto max_buf_element = [&]() {
+ uint64_t max_v = 0;
+ for (auto buf : bufs) {
+ uint64_t _max_v = max_element(*buf);
+ max_v = std::max(max_v, _max_v);
+ }
+ return max_v;
+ };
+
+ uint64_t x = max_buf_element();
+ uint8_t res = 0;
+ while (res <= 64 and precomp<t_k>::exp(res) <= x) { ++res; }
+ if (res == 65) {
+ throw std::logic_error("Maximal element of input is too big.");
+ }
+
+ if (precomp<t_k>::exp(res) <= std::numeric_limits<uint32_t>::max()) {
+ auto v = read<uint32_t,uint32_t,uint32_t>(bufs);
+ construct(v, buf_x.filename());
+ } else {
+ auto v = read<uint64_t,uint64_t,uint64_t>(bufs);
+ construct(v, buf_x.filename());
+ }
+ }
+
+ template<typename t_x=uint64_t, typename t_y=uint64_t, typename t_w=uint64_t>
+ std::vector<std::tuple<t_x, t_y, t_w>>
+ read(std::vector<int_vector_buffer<>*>& bufs)
+ {
+ typedef std::vector<std::tuple<t_x, t_y, t_w>> t_tuple_vec;
+ t_tuple_vec v = t_tuple_vec(bufs[0]->size());
+ for (uint64_t j=0; j<v.size(); ++j) {
+ std::get<0>(v[j]) = (*(bufs[0]))[j];
+ }
+ for (uint64_t j=0; j<v.size(); ++j) {
+ std::get<1>(v[j]) = (*(bufs[1]))[j];
+ }
+ for (uint64_t j=0; j<v.size(); ++j) {
+ std::get<2>(v[j]) = (*(bufs[2]))[j];
+ }
+ return v;
+ }
+
+
+ template<typename t_x, typename t_y, typename t_w>
+ k2_treap(std::vector<std::tuple<t_x, t_y, t_w>>& v, std::string temp_file_prefix="")
+ {
+ if (v.size() > 0) {
+ construct(v, temp_file_prefix);
+ }
+ }
+
+ template<typename t_x, typename t_y, typename t_w>
+ void construct(std::vector<std::tuple<t_x, t_y, t_w>>& v, std::string temp_file_prefix="")
+ {
+ using namespace k2_treap_ns;
+ using t_e = std::tuple<t_x, t_y, t_w>;
+ m_t = get_t(v);
+ uint64_t M = precomp<t_k>::exp(t);
+ t_e MM = t_e(M,M,M);
+
+ std::string id_part = util::to_string(util::pid())
+ + "_" + util::to_string(util::id());
+
+ m_coord.resize(t);
+ m_level_idx = int_vector<64>(1+t, 0);
+
+ std::string val_file = temp_file_prefix + "_k2_treap_"
+ + id_part + ".sdsl";
+ std::string bp_file = temp_file_prefix + "_bp_" + id_part
+ + ".sdsl";
+
+ {
+ int_vector_buffer<> val_buf(val_file, std::ios::out);
+ int_vector_buffer<1> bp_buf(bp_file, std::ios::out);
+
+ auto end = std::end(v);
+ uint64_t last_level_nodes = 1;
+ uint64_t level_nodes;
+ for (uint64_t l=t, cc=0; l+1 > 0; --l) {
+ if (l > 0) {
+ m_level_idx[l-1] = m_level_idx[l] + last_level_nodes;
+ m_coord[l-1] = int_vector<>(2*last_level_nodes,0, bits::hi(precomp<t_k>::exp(l))+1);
+ }
+ level_nodes = 0;
+ cc = 0;
+ auto sp = std::begin(v);
+ for (auto ep = sp; ep != end;) {
+ ep = std::find_if(sp, end, [&sp,&l](const t_e& e) {
+ auto x1 = std::get<0>(*sp);
+ auto y1 = std::get<1>(*sp);
+ auto x2 = std::get<0>(e);
+ auto y2 = std::get<1>(e);
+ return precomp<t_k>::divexp(x1,l) != precomp<t_k>::divexp(x2,l)
+ or precomp<t_k>::divexp(y1,l) != precomp<t_k>::divexp(y2,l);
+ });
+ auto max_it = std::max_element(sp, ep, [](t_e a, t_e b) {
+ if (std::get<2>(a) != std::get<2>(b))
+ return std::get<2>(a) < std::get<2>(b);
+ else if (std::get<0>(a) != std::get<0>(b))
+ return std::get<0>(a) > std::get<0>(b);
+ return std::get<1>(a) > std::get<1>(b);
+ });
+ if (l > 0) {
+ m_coord[l-1][2*cc] = precomp<t_k>::modexp(std::get<0>(*max_it), l);
+ m_coord[l-1][2*cc+1] = precomp<t_k>::modexp(std::get<1>(*max_it), l);
+ ++cc;
+ }
+
+ val_buf.push_back(std::get<2>(*max_it));
+ *max_it = MM;
+ --ep;
+ std::swap(*max_it, *ep);
+ if (l > 0) {
+ auto _sp = sp;
+
+ for (uint8_t i=0; i < t_k; ++i) {
+ auto _ep = ep;
+ if (i+1 < t_k) {
+ _ep = std::partition(_sp, ep, [&i,&l](const t_e& e) {
+ return precomp<t_k>::divexp(std::get<0>(e),l-1)%t_k <= i;
+ });
+ }
+ auto __sp = _sp;
+ for (uint8_t j=0; j < t_k; ++j) {
+ auto __ep = _ep;
+ if (j+1 < t_k) {
+ __ep = std::partition(__sp, _ep, [&j,&l](const t_e& e) {
+ return precomp<t_k>::divexp(std::get<1>(e),l-1)%t_k <= j;
+ });
+ }
+ bool not_empty = __ep > __sp;
+ bp_buf.push_back(not_empty);
+ level_nodes += not_empty;
+ __sp = __ep;
+ }
+ _sp = _ep;
+ }
+ }
+ ++ep;
+ sp = ep;
+ }
+ end = std::remove_if(begin(v), end, [&](t_e e) {
+ return e == MM;
+ });
+ last_level_nodes = level_nodes;
+ }
+ }
+ bit_vector bp;
+ load_from_file(bp, bp_file);
+ {
+ int_vector_buffer<> val_rw(val_file, std::ios::in | std::ios::out);
+ int_vector_buffer<> val_r(val_file, std::ios::in);
+ uint64_t bp_idx = bp.size();
+ uint64_t r_idx = m_level_idx[0];
+ uint64_t rw_idx = val_rw.size();
+ while (bp_idx > 0) {
+ --r_idx;
+ for (size_t i=0; i < t_k*t_k; ++i) {
+ if (bp[--bp_idx]) {
+ --rw_idx;
+ val_rw[rw_idx] = val_r[r_idx] - val_rw[rw_idx];
+ }
+ }
+ }
+ }
+ {
+ int_vector_buffer<> val_r(val_file);
+ m_maxval = t_max_vec(val_r);
+ }
+ {
+ bit_vector _bp;
+ _bp.swap(bp);
+ m_bp = t_bv(_bp);
+ }
+ util::init_support(m_bp_rank, &m_bp);
+ sdsl::remove(bp_file);
+ sdsl::remove(val_file);
+ }
+
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const
+ {
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_t, out, child, "t");
+ written_bytes += m_bp.serialize(out, child, "bp");
+ written_bytes += m_bp_rank.serialize(out, child, "bp_rank");
+ written_bytes += serialize_vector(m_coord, out, child, "coord");
+ written_bytes += m_maxval.serialize(out, child, "maxval");
+ written_bytes += m_level_idx.serialize(out, child, "level_idx");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in)
+ {
+ read_member(m_t, in);
+ m_bp.load(in);
+ m_bp_rank.load(in);
+ m_bp_rank.set_vector(&m_bp);
+ m_coord.resize(t);
+ load_vector(m_coord, in);
+ m_maxval.load(in);
+ m_level_idx.load(in);
+ }
+
+ node_type
+ root() const
+ {
+ return node_type(t, t_p(0,0), 0, m_maxval[0],
+ t_p(m_coord[t-1][0], m_coord[t-1][1]));
+ }
+
+ bool
+ is_leaf(const node_type& v) const
+ {
+ return v.idx >= m_bp.size();
+ }
+
+ std::vector<node_type>
+ children(const node_type& v) const
+ {
+ using namespace k2_treap_ns;
+ std::vector<node_type> res;
+ if (!is_leaf(v)) {
+ uint64_t rank = m_bp_rank(v.idx);
+ auto x = std::real(v.p);
+ auto y = std::imag(v.p);
+
+ for (size_t i=0; i<t_k; ++i) {
+ for (size_t j=0; j<t_k; ++j) {
+ // get_int better for compressed bitvectors
+ // or introduce cache for bitvectors
+ if (m_bp[v.idx+t_k*i+j]) {
+ ++rank;
+
+ auto _x = x + i*precomp<t_k>::exp(v.t-1);
+ auto _y = y + j*precomp<t_k>::exp(v.t-1);
+
+ auto _max_v = v.max_v - m_maxval[rank];
+ auto _max_p = t_p(_x, _y);
+ if (v.t > 1) {
+ auto y = rank-m_level_idx[v.t-1];
+ _max_p = t_p(_x+m_coord[v.t-2][2*y],
+ _y+m_coord[v.t-2][2*y+1]);
+ }
+ res.emplace_back(v.t-1, t_p(_x,_y), rank*t_k*t_k,
+ _max_v, _max_p);
+ }
+ }
+ }
+ }
+ return res;
+ }
+
+};
+
+}
+#endif
diff --git a/include/sdsl/k2_treap_algorithm.hpp b/include/sdsl/k2_treap_algorithm.hpp
new file mode 100644
index 0000000..89a43dd
--- /dev/null
+++ b/include/sdsl/k2_treap_algorithm.hpp
@@ -0,0 +1,412 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file k2_treap_algorithm.hpp
+ \brief k2_treap_algorithm.hpp contains k^2-treap algorithms.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_K2_TREAP_ALGORITHM
+#define INCLUDED_SDSL_K2_TREAP_ALGORITHM
+
+#include "sdsl/vectors.hpp"
+#include "sdsl/bits.hpp"
+#include "sdsl/k2_treap_helper.hpp"
+#include <tuple>
+#include <algorithm>
+#include <iterator>
+#include <climits>
+#include <vector>
+#include <complex>
+#include <queue>
+#include <array>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+namespace k2_treap_ns
+{
+
+//! Check if point x is contained in the rectangle (p1,p2)
+/*! \param p Point.
+ * \param Lower left corner of the rectangle.
+ * \param Upper right corner of the rectangle.
+ */
+bool
+contained(const point_type p, const point_type& p1, const point_type& p2)
+{
+ return real(p) >= real(p1) and real(p) <= real(p2) and
+ imag(p) >= imag(p1) and imag(p) <= imag(p2);
+}
+
+//! Check if the rectangle of node v is contained in the rectangle (p1,p2)
+template<uint8_t t_k>
+bool
+contained(const point_type& p1, const point_type& p2, const node_type& v)
+{
+// uint64_t d = (1ULL << v.t)-1;
+// uint64_t d = (1ULL << v.t)-1;
+ uint64_t d = precomp<t_k>::exp(v.t)-1;
+ return real(p1) <= real(v.p) and real(p2) >= real(v.p) + d and
+ imag(p1) <= imag(v.p) and imag(p2) >= imag(v.p) + d;
+}
+
+//! Check if rectangle (p1,p2) and the area of node v overlap
+template<uint8_t t_k>
+bool
+overlap(const point_type& p1, const point_type& p2, const node_type& v)
+{
+// uint64_t d = (1ULL << v.t)-1;
+ uint64_t d = precomp<t_k>::exp(v.t)-1;
+ return real(p1) <= real(v.p) + d and real(p2) >= real(v.p) and
+ imag(p1) <= imag(v.p) + d and imag(p2) >= imag(v.p);
+}
+
+template<typename t_k2_treap>
+class top_k_iterator
+{
+ public:
+ typedef void(*t_mfptr)();
+ typedef std::pair<point_type, uint64_t> t_point_val;
+
+ private:
+ typedef k2_treap_ns::node_type node_type;
+ typedef std::pair<node_type, bool> t_nt_b;
+
+ const t_k2_treap* m_treap = nullptr;
+ std::priority_queue<t_nt_b> m_pq;
+ t_point_val m_point_val;
+ point_type m_p1;
+ point_type m_p2;
+ bool m_valid = false;
+
+ public:
+ top_k_iterator() = default;
+ top_k_iterator(const top_k_iterator&) = default;
+ top_k_iterator(top_k_iterator&&) = default;
+ top_k_iterator& operator=(const top_k_iterator&) = default;
+ top_k_iterator& operator=(top_k_iterator&&) = default;
+ top_k_iterator(const t_k2_treap& treap, point_type p1, point_type p2) :
+ m_treap(&treap), m_p1(p1), m_p2(p2), m_valid(treap.size()>0)
+ {
+ if (m_treap->size() > 0) {
+ m_pq.emplace(m_treap->root(),false);
+ ++(*this);
+ }
+ }
+
+ //! Prefix increment of the iterator
+ top_k_iterator& operator++()
+ {
+ m_valid = false;
+ while (!m_pq.empty()) {
+ auto v = std::get<0>(m_pq.top());
+ auto is_contained = std::get<1>(m_pq.top());
+ m_pq.pop();
+ if (is_contained) {
+ auto nodes = m_treap->children(v);
+ for (auto node : nodes)
+ m_pq.emplace(node, true);
+ m_point_val = t_point_val(v.max_p, v.max_v);
+ m_valid = true;
+ break;
+ } else {
+ if (contained<t_k2_treap::k>(m_p1, m_p2, v)) {
+ m_pq.emplace(v, true);
+ } else if (overlap<t_k2_treap::k>(m_p1, m_p2, v)) {
+ auto nodes = m_treap->children(v);
+ for (auto node : nodes)
+ m_pq.emplace(node, false);
+ if (contained(v.max_p, m_p1, m_p2)) {
+ m_point_val = t_point_val(v.max_p, v.max_v);
+ m_valid = true;
+ break;
+ }
+ }
+ }
+ }
+ return *this;
+ }
+
+ //! Postfix increment of the iterator
+ top_k_iterator operator++(int)
+ {
+ top_k_iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ t_point_val operator*() const
+ {
+ return m_point_val;
+ }
+
+ //! Cast to a member function pointer
+ // Test if there are more elements
+ // Can be casted to bool but not implicit in an arithmetic experession
+ // See Alexander C.'s comment on
+ // http://stackoverflow.com/questions/835590/how-would-stdostringstream-convert-to-bool
+ operator t_mfptr() const
+ {
+ return (t_mfptr)(m_valid);
+ }
+};
+
+template<typename t_k2_treap>
+class range_iterator
+{
+ public:
+ typedef void(*t_mfptr)();
+ typedef std::pair<point_type, uint64_t> t_point_val;
+
+ private:
+ typedef k2_treap_ns::node_type node_type;
+ typedef std::pair<node_type, bool> t_nt_b;
+
+ const t_k2_treap* m_treap = nullptr;
+ std::priority_queue<t_nt_b> m_pq;
+ t_point_val m_point_val;
+ point_type m_p1;
+ point_type m_p2;
+ range_type m_r;
+ bool m_valid = false;
+
+ void pq_emplace(node_type v, bool b)
+ {
+ if (v.max_v >= real(m_r)) {
+ m_pq.emplace(v, b);
+ }
+ }
+
+ public:
+ range_iterator() = default;
+ range_iterator(const range_iterator&) = default;
+ range_iterator(range_iterator&&) = default;
+ range_iterator& operator=(const range_iterator&) = default;
+ range_iterator& operator=(range_iterator&&) = default;
+ range_iterator(const t_k2_treap& treap, point_type p1, point_type p2, range_type range) :
+ m_treap(&treap), m_p1(p1), m_p2(p2), m_r(range), m_valid(treap.size()>0)
+ {
+ if (m_treap->size() >0) {
+ pq_emplace(m_treap->root(), false);
+ ++(*this);
+ }
+ }
+
+ //! Prefix increment of the iterator
+ range_iterator& operator++()
+ {
+ m_valid = false;
+ while (!m_pq.empty()) {
+ auto v = std::get<0>(m_pq.top());
+ auto is_contained = std::get<1>(m_pq.top());
+ m_pq.pop();
+ if (is_contained) {
+ auto nodes = m_treap->children(v);
+ for (auto node : nodes)
+ pq_emplace(node, true);
+ if (v.max_v <= imag(m_r)) {
+ m_point_val = t_point_val(v.max_p, v.max_v);
+ m_valid = true;
+ break;
+ }
+ } else {
+ if (contained<t_k2_treap::k>(m_p1, m_p2, v)) {
+ m_pq.emplace(v, true);
+ } else if (overlap<t_k2_treap::k>(m_p1, m_p2, v)) {
+ auto nodes = m_treap->children(v);
+ for (auto node : nodes)
+ pq_emplace(node, false);
+ if (contained(v.max_p, m_p1, m_p2) and v.max_v <= imag(m_r)) {
+ m_point_val = t_point_val(v.max_p, v.max_v);
+ m_valid = true;
+ break;
+ }
+ }
+ }
+ }
+ return *this;
+ }
+
+ //! Postfix increment of the iterator
+ range_iterator operator++(int)
+ {
+ range_iterator it = *this;
+ ++(*this);
+ return it;
+ }
+
+ t_point_val operator*() const
+ {
+ return m_point_val;
+ }
+
+ //! Cast to a member function pointer
+ // Test if there are more elements
+ operator t_mfptr() const
+ {
+ return (t_mfptr)(m_valid);
+ }
+};
+
+} // end namespace k2_treap_ns
+
+//! Get iterator for all heaviest points in rectangle (p1,p2) in decreasing order
+/*! \param treap k2-treap
+ * \param p1 Lower left corner of the rectangle
+ * \param p2 Upper right corner of the rectangle
+ * \return Iterator to result in decreasing order.
+ * \pre real(p1) <= real(p2) and imag(p1)<=imag(p2)
+ */
+template<typename t_k2_treap>
+k2_treap_ns::top_k_iterator<t_k2_treap>
+top_k(const t_k2_treap& t,
+ k2_treap_ns::point_type p1,
+ k2_treap_ns::point_type p2)
+{
+ return k2_treap_ns::top_k_iterator<t_k2_treap>(t, p1, p2);
+}
+
+
+//! Get iterator for all points in rectangle (p1,p2) with weights in range
+/*! \param treap k2-treap
+ * \param p1 Lower left corner of the rectangle
+ * \param p2 Upper right corner of the rectangle
+ * \param range Range {w1,w2}.
+ * \return Iterator to list of all points in the range.
+ * \pre real(p1) <= real(p2) and imag(p1)<=imag(p2)
+ * real(range) <= imag(range)
+ */
+template<typename t_k2_treap>
+k2_treap_ns::range_iterator<t_k2_treap>
+range_3d(const t_k2_treap& t,
+ k2_treap_ns::point_type p1,
+ k2_treap_ns::point_type p2,
+ k2_treap_ns::range_type range)
+{
+ return k2_treap_ns::range_iterator<t_k2_treap>(t, p1, p2, range);
+}
+
+
+// forward declaration
+template<typename t_k2_treap>
+uint64_t __count(const t_k2_treap&, typename t_k2_treap::node_type);
+
+// forward declaration
+template<typename t_k2_treap>
+uint64_t _count(const t_k2_treap&, k2_treap_ns::point_type,
+ k2_treap_ns::point_type, typename t_k2_treap::node_type);
+
+//! Count how many points are in the rectangle (p1,p2)
+/*! \param treap k2-treap
+ * \param p1 Lower left corner of the rectangle.
+ * \param p2 Upper right corner of the rectangle.
+ * \return The number of points in rectangle (p1,p2).
+ * \pre real(p1) <= real(p2) and imag(p1)<=imag(p2)
+ */
+template<typename t_k2_treap>
+uint64_t
+count(const t_k2_treap& treap,
+ k2_treap_ns::point_type p1,
+ k2_treap_ns::point_type p2)
+{
+ if (treap.size() > 0) {
+ return _count(treap, p1, p2, treap.root());
+ }
+ return 0;
+}
+
+
+template<typename t_k2_treap>
+uint64_t
+_count(const t_k2_treap& treap,
+ k2_treap_ns::point_type p1,
+ k2_treap_ns::point_type p2,
+ typename t_k2_treap::node_type v)
+{
+ using namespace k2_treap_ns;
+ if (contained<t_k2_treap::k>(p1, p2, v)) {
+ return __count(treap, v);
+ } else if (overlap<t_k2_treap::k>(p1, p2, v)) {
+ uint64_t res = contained(v.max_p, p1, p2);
+ auto nodes = treap.children(v);
+ for (auto node : nodes) {
+ res += _count(treap, p1, p2, node);
+ }
+ return res;
+ }
+ return 0;
+}
+
+
+template<typename t_k2_treap>
+uint64_t
+__count(const t_k2_treap& treap,
+ typename t_k2_treap::node_type v)
+{
+ uint64_t res = 1; // count the point at the node
+ auto nodes = treap.children(v);
+ for (auto node : nodes)
+ res += __count(treap, node);
+ return res;
+}
+
+
+// forward declaration
+template<uint8_t t_k,
+ typename t_bv,
+ typename t_rank,
+ typename t_max_vec>
+class k2_treap;
+
+
+//! Specialized version of method ,,construct'' for k2_treaps.
+template<uint8_t t_k,
+ typename t_bv,
+ typename t_rank,
+ typename t_max_vec>
+void
+construct(k2_treap<t_k, t_bv, t_rank, t_max_vec>& idx, std::string file)
+{
+ int_vector_buffer<> buf_x(file+".x", std::ios::in);
+ int_vector_buffer<> buf_y(file+".y", std::ios::in);
+ int_vector_buffer<> buf_w(file+".w", std::ios::in);
+ k2_treap<t_k, t_bv, t_rank, t_max_vec> tmp(buf_x, buf_y, buf_w);
+ tmp.swap(idx);
+}
+
+//! Specialized version of method ,,construct_im'' for k2_treaps.
+template<uint8_t t_k,
+ typename t_bv,
+ typename t_rank,
+ typename t_max_vec
+ >
+void
+construct_im(k2_treap<t_k, t_bv, t_rank, t_max_vec>& idx, std::vector<std::array<uint64_t, 3>> data)
+{
+ std::string tmp_prefix = ram_file_name("k2_treap_");
+ std::vector<std::tuple<uint64_t,uint64_t,uint64_t>> d;
+ for (auto x : data) {
+ d.push_back(std::make_tuple(x[0],x[1],x[2]));
+ }
+ k2_treap<t_k, t_bv, t_rank, t_max_vec> tmp(d, tmp_prefix);
+ tmp.swap(idx);
+}
+
+
+
+}
+#endif
diff --git a/include/sdsl/k2_treap_helper.hpp b/include/sdsl/k2_treap_helper.hpp
new file mode 100644
index 0000000..40ca5f3
--- /dev/null
+++ b/include/sdsl/k2_treap_helper.hpp
@@ -0,0 +1,185 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file k2_treap_helper.hpp
+ \brief k2_treap_helper.hpp contains helper functions and definitions for a k^2-treap implementation.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_K2_TREAP_HELPER
+#define INCLUDED_SDSL_K2_TREAP_HELPER
+
+#include "sdsl/vectors.hpp"
+#include "sdsl/bits.hpp"
+#include <tuple>
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include <complex>
+#include <queue>
+#include <array>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+namespace k2_treap_ns
+{
+
+// Precomputed value for fast k^2 treap operations
+template<uint8_t t_k>
+struct precomp {
+ static struct impl {
+ uint64_t exp[65];
+ impl()
+ {
+ exp[0] = 1;
+ for (uint8_t i=1; i<65; ++i) {
+ exp[i] = t_k * exp[i-1];
+ }
+ }
+ } data;
+
+ static uint64_t exp(uint8_t l)
+ {
+ return data.exp[l];
+ }
+
+ static uint64_t divexp(uint64_t x, uint8_t l)
+ {
+ return x/data.exp[l];
+ }
+
+ static uint64_t modexp(uint64_t x, uint8_t l)
+ {
+ return x%data.exp[l];
+ }
+};
+
+template<>
+struct precomp<2> {
+ static uint64_t exp(uint8_t l)
+ {
+ return 1ULL<<l;
+ }
+
+ static uint64_t divexp(uint64_t x, uint8_t l)
+ {
+ return x>>l;
+ }
+
+ static uint64_t modexp(uint64_t x, uint8_t l)
+ {
+ return x & bits::lo_set[l];
+ }
+};
+
+template<>
+struct precomp<4> {
+ static uint64_t exp(uint8_t l)
+ {
+ return 1ULL<<(2*l);
+ }
+
+ static uint64_t divexp(uint64_t x, uint8_t l)
+ {
+ return x>>(2*l);
+ }
+
+ static uint64_t modexp(uint64_t x, uint8_t l)
+ {
+ return x & bits::lo_set[2*l];
+ }
+};
+
+template<>
+struct precomp<8> {
+ static uint64_t exp(uint8_t l)
+ {
+ return 1ULL<<(3*l);
+ }
+
+ static uint64_t divexp(uint64_t x, uint8_t l)
+ {
+ return x>>(3*l);
+ }
+
+ static uint64_t modexp(uint64_t x, uint8_t l)
+ {
+ return x & bits::lo_set[3*l];
+ }
+};
+
+template<>
+struct precomp<16> {
+ static uint64_t exp(uint8_t l)
+ {
+ return 1ULL<<(4*l);
+ }
+
+ static uint64_t divexp(uint64_t x, uint8_t l)
+ {
+ return x>>(4*l);
+ }
+
+ static uint64_t modexp(uint64_t x, uint8_t l)
+ {
+ return x & bits::lo_set[4*l];
+ }
+};
+
+
+template<uint8_t t_k>
+typename precomp<t_k>::impl precomp<t_k>::data;
+
+
+
+typedef std::complex<uint64_t> t_p;
+typedef t_p point_type;
+typedef t_p range_type;
+
+struct node_type {
+ uint8_t t; // level; size of node 1<<t
+ t_p p; // lower left corner
+ uint64_t idx; // index in bp
+ uint64_t max_v; // maximal value
+ t_p max_p; // maximal point
+
+ node_type() = default;
+ node_type(uint8_t _t, t_p _p, uint64_t _idx, uint64_t _max_v,
+ t_p _max_p) : t(_t), p(_p), idx(_idx), max_v(_max_v),
+ max_p(_max_p)
+ {}
+ node_type(node_type&&) = default;
+ node_type(const node_type&) = default;
+ node_type& operator=(node_type&&) = default;
+ node_type& operator=(const node_type&) = default;
+
+ bool operator<(const node_type& v) const
+ {
+ if (max_v != v.max_v) {
+ return max_v < v.max_v;
+ }
+ if (real(max_p) != real(v.max_p)) {
+ return real(max_p) > real(v.max_p);
+ }
+ return imag(max_p) > imag(v.max_p);
+ }
+};
+
+} // end namepsace k2_treap_ns
+
+} // end nomespace sdsl
+#endif
diff --git a/include/sdsl/lcp.hpp b/include/sdsl/lcp.hpp
new file mode 100644
index 0000000..ef7b258
--- /dev/null
+++ b/include/sdsl/lcp.hpp
@@ -0,0 +1,225 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file lcp.hpp
+ \brief lcp.hpp contains classes for lcp information.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP
+#define INCLUDED_SDSL_LCP
+
+#include "sdsl_concepts.hpp"
+
+#include "int_vector.hpp"
+#include "csa_alphabet_strategy.hpp" // for key_trait
+#include "select_support_mcl.hpp"
+#include "construct_isa.hpp"
+#include <istream>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+// construct lcp arrays
+template<class t_lcp, class t_cst>
+void construct_lcp(t_lcp& lcp, const t_cst& cst, cache_config& config)
+{
+ typename t_lcp::lcp_category tag;
+ construct_lcp(lcp, cst, config, tag);
+}
+
+template<class t_lcp, class t_cst>
+void construct_lcp(t_lcp& lcp, const t_cst&, cache_config& config, lcp_plain_tag)
+{
+ t_lcp tmp_lcp(config);
+ lcp.swap(tmp_lcp);
+}
+
+template<class t_lcp, class t_cst>
+void construct_lcp(t_lcp& lcp, const t_cst& cst, cache_config& config, lcp_permuted_tag)
+{
+ t_lcp tmp_lcp(config, &(cst.csa));
+ lcp.swap(tmp_lcp);
+}
+
+template<class t_lcp, class t_cst>
+void construct_lcp(t_lcp& lcp, const t_cst& cst, cache_config& config, lcp_tree_compressed_tag)
+{
+ t_lcp tmp_lcp(config, &cst);
+ lcp.swap(tmp_lcp);
+}
+
+template<class t_lcp, class t_cst>
+void construct_lcp(t_lcp& lcp, const t_cst& cst, cache_config& config, lcp_tree_and_lf_compressed_tag)
+{
+ t_lcp tmp_lcp(config, &cst);
+ lcp.swap(tmp_lcp);
+}
+
+// copy lcp arrays
+template<class t_lcp, class t_cst>
+void copy_lcp(t_lcp& lcp, const t_lcp& lcp_c, const t_cst& cst)
+{
+ typename t_lcp::lcp_category tag;
+ copy_lcp(lcp, lcp_c, cst, tag);
+}
+
+template<class t_lcp, class t_cst>
+void copy_lcp(t_lcp& lcp, const t_lcp& lcp_c, const t_cst&, lcp_plain_tag)
+{
+ lcp = lcp_c;
+}
+
+template<class t_lcp, class t_cst>
+void copy_lcp(t_lcp& lcp, const t_lcp& lcp_c, const t_cst& cst, lcp_permuted_tag)
+{
+ lcp = lcp_c;
+ lcp.set_csa(&(cst.csa));
+}
+
+template<class t_lcp, class t_cst>
+void copy_lcp(t_lcp& lcp, const t_lcp& lcp_c, const t_cst& cst, lcp_tree_compressed_tag)
+{
+ lcp = lcp_c;
+ lcp.set_cst(&cst);
+}
+
+template<class t_lcp, class t_cst>
+void copy_lcp(t_lcp& lcp, const t_lcp& lcp_c, const t_cst& cst, lcp_tree_and_lf_compressed_tag)
+{
+ lcp = lcp_c;
+ lcp.set_cst(&cst);
+}
+
+// move lcp arrays
+template<class t_lcp, class t_cst>
+void move_lcp(t_lcp& lcp, t_lcp& lcp_c, const t_cst& cst)
+{
+ typename t_lcp::lcp_category tag;
+ move_lcp(lcp, lcp_c, cst, tag);
+}
+
+template<class t_lcp, class t_cst>
+void move_lcp(t_lcp& lcp, t_lcp& lcp_c, const t_cst&, lcp_plain_tag)
+{
+ lcp = std::move(lcp_c);
+}
+
+template<class t_lcp, class t_cst>
+void move_lcp(t_lcp& lcp, t_lcp& lcp_c, const t_cst& cst, lcp_permuted_tag)
+{
+ lcp = std::move(lcp_c);
+ lcp.set_csa(&(cst.csa));
+}
+
+template<class t_lcp, class t_cst>
+void move_lcp(t_lcp& lcp, t_lcp& lcp_c, const t_cst& cst, lcp_tree_compressed_tag)
+{
+ lcp = std::move(lcp_c);
+ lcp.set_cst(&cst);
+}
+
+template<class t_lcp, class t_cst>
+void move_lcp(t_lcp& lcp, t_lcp& lcp_c, const t_cst& cst, lcp_tree_and_lf_compressed_tag)
+{
+ lcp = std::move(lcp_c);
+ lcp.set_cst(&cst);
+}
+
+
+// swap lcp arrays
+template<class t_lcp, class t_cst>
+void swap_lcp(t_lcp& lcp1, t_lcp& lcp2, const t_cst& cst1, const t_cst& cst2)
+{
+ typename t_lcp::lcp_category tag;
+ swap_lcp(lcp1, lcp2, cst1, cst2, tag);
+}
+
+template<class t_lcp, class t_cst>
+void swap_lcp(t_lcp& lcp1, t_lcp& lcp2, const t_cst&, const t_cst&, lcp_plain_tag)
+{
+ lcp1.swap(lcp2);
+}
+
+template<class t_lcp, class t_cst>
+void swap_lcp(t_lcp& lcp1, t_lcp& lcp2, const t_cst& cst1, const t_cst& cst2, lcp_permuted_tag)
+{
+ lcp1.swap(lcp2);
+ lcp1.set_csa(&(cst1.csa));
+ lcp2.set_csa(&(cst2.csa));
+}
+
+template<class t_lcp, class t_cst>
+void swap_lcp(t_lcp& lcp1, t_lcp& lcp2, const t_cst& cst1, const t_cst& cst2, lcp_tree_compressed_tag)
+{
+ lcp1.swap(lcp2);
+ lcp1.set_cst(&cst1);
+ lcp2.set_cst(&cst2);
+}
+
+template<class t_lcp, class t_cst>
+void swap_lcp(t_lcp& lcp1, t_lcp& lcp2, const t_cst& cst1, const t_cst& cst2, lcp_tree_and_lf_compressed_tag)
+{
+ lcp1.swap(lcp2);
+ lcp1.set_cst(&cst1);
+ lcp2.set_cst(&cst2);
+}
+
+// load lcp arrays
+template<class t_lcp, class t_cst>
+void load_lcp(t_lcp& lcp, std::istream& in, const t_cst& cst)
+{
+ typename t_lcp::lcp_category tag;
+ load_lcp(lcp, in, cst, tag);
+}
+
+template<class t_lcp, class t_cst>
+void load_lcp(t_lcp& lcp, std::istream& in, const t_cst&, lcp_plain_tag)
+{
+ lcp.load(in);
+}
+
+template<class t_lcp, class t_cst>
+void load_lcp(t_lcp& lcp, std::istream& in, const t_cst& cst, lcp_permuted_tag)
+{
+ lcp.load(in, &(cst.csa));
+}
+
+template<class t_lcp, class t_cst>
+void load_lcp(t_lcp& lcp, std::istream& in, const t_cst& cst, lcp_tree_compressed_tag)
+{
+ lcp.load(in, &cst);
+}
+
+template<class t_lcp, class t_cst>
+void load_lcp(t_lcp& lcp, std::istream& in, const t_cst& cst, lcp_tree_and_lf_compressed_tag)
+{
+ lcp.load(in, &cst);
+}
+
+} // end namespace sdsl
+
+#include "lcp_support_sada.hpp" // type (b)
+#include "lcp_byte.hpp" // type (a)
+#include "lcp_wt.hpp" // type (a)
+#include "lcp_vlc.hpp" // type (a)
+#include "lcp_dac.hpp" // type (a)
+#include "lcp_bitcompressed.hpp" // type (a)
+#include "lcp_support_tree.hpp" // type (c)
+#include "lcp_support_tree2.hpp" // type (c)
+
+
+#endif
diff --git a/include/sdsl/lcp_bitcompressed.hpp b/include/sdsl/lcp_bitcompressed.hpp
new file mode 100644
index 0000000..89f2e89
--- /dev/null
+++ b/include/sdsl/lcp_bitcompressed.hpp
@@ -0,0 +1,134 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file lcp_bitcompressed.hpp
+ \brief lcp_bitcompressed.hpp contains a bitcompressed LCP array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP_BITCOMPRESSED
+#define INCLUDED_SDSL_LCP_BITCOMPRESSED
+
+#include "lcp.hpp"
+#include "int_vector.hpp"
+#include "iterators.hpp"
+
+namespace sdsl
+{
+
+template<uint8_t t_width=0>
+class lcp_bitcompressed
+{
+ public:
+
+ typedef typename int_vector<t_width>::value_type value_type;
+ typedef typename int_vector<t_width>::size_type size_type;
+ typedef random_access_const_iterator<lcp_bitcompressed> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef ptrdiff_t difference_type;
+
+ typedef lcp_plain_tag lcp_category;
+
+ enum { fast_access = 1,
+ text_order = 0,
+ sa_order = 1
+ };
+
+ template<class Cst>
+ using type = lcp_bitcompressed;
+
+ private:
+
+ int_vector<t_width> m_lcp;
+
+ public:
+
+ //! Default Constructor
+ lcp_bitcompressed() {}
+ lcp_bitcompressed(const lcp_bitcompressed&) = default;
+ lcp_bitcompressed(lcp_bitcompressed&&) = default;
+ lcp_bitcompressed& operator=(const lcp_bitcompressed&) = default;
+ lcp_bitcompressed& operator=(lcp_bitcompressed&&) = default;
+
+ //! Constructor taking a cache_config
+ lcp_bitcompressed(cache_config& config) {
+ std::string lcp_file = cache_file_name(conf::KEY_LCP, config);
+ int_vector_buffer<> lcp_buf(lcp_file);
+ m_lcp = int_vector<t_width>(lcp_buf.size(), 0, lcp_buf.width());
+ for (size_type i=0; i < m_lcp.size(); ++i) {
+ m_lcp[i] = lcp_buf[i];
+ }
+ }
+
+ //! Number of elements in the instance.
+ size_type size()const {
+ return m_lcp.size();
+ }
+
+ //! Returns the largest size that lcp_bitcompressed can ever have.
+ static size_type max_size() {
+ return int_vector<t_width>::max_size();
+ }
+
+ //! Returns if the data structure is empty.
+ bool empty()const {
+ return m_lcp.empty();
+ }
+
+ //! Swap method for lcp_bitcompressed
+ void swap(lcp_bitcompressed& lcp_c) {
+ m_lcp.swap(lcp_c.m_lcp);
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! Access operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ */
+ value_type operator[](size_type i)const {
+ return m_lcp[i];
+ }
+
+ //! Serialize to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name,
+ util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_lcp.serialize(out, child, "lcp");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in) {
+ m_lcp.load(in);
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/lcp_byte.hpp b/include/sdsl/lcp_byte.hpp
new file mode 100644
index 0000000..8aa544e
--- /dev/null
+++ b/include/sdsl/lcp_byte.hpp
@@ -0,0 +1,192 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file lcp_byte.hpp
+ \brief lcp_byte.hpp contains a (compressed) lcp array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP_BYTE
+#define INCLUDED_SDSL_LCP_BYTE
+
+#include "lcp.hpp"
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include <iostream>
+#include <algorithm> // for lower_bound
+#include <cassert>
+#include <iomanip>
+#include <iterator>
+#include <vector>
+#include <utility> // for pair
+
+namespace sdsl
+{
+
+//! A class for a simple compressed version of LCP information
+/*! Each small LCP value x=LCP[i] (\f$\leq 254\f$) is represented in a byte.
+ * For x=LCP[i] \f$\geq 255\f$ a pair (i, x) is store an list of word pairs.
+ * This list is binary search to access LCP[i].
+ * \par Time complexity
+ * - \f$\Order{1}\f$ if the value is less than 255 and
+ * - \f$\Order{\log n}\f$ (\f$n=size()\f$) otherwise.
+ * \par Reference
+ * Mohamed Ibrahim Abouelhoda, Stefan Kurtz, Enno Ohlebusch:
+ * Replacing suffix trees with enhanced suffix arrays.
+ * J. Discrete Algorithms 2(1): 53-86 (2004)
+ */
+template<uint8_t t_width=0>
+class lcp_byte
+{
+ public:
+
+ typedef typename int_vector<t_width>::value_type value_type;
+ typedef random_access_const_iterator<lcp_byte> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef ptrdiff_t difference_type;
+
+ typedef lcp_plain_tag lcp_category;
+
+ enum { fast_access = 0,
+ text_order = 0,
+ sa_order = 1
+ }; // as the lcp_byte is not fast for texts with long repetition
+
+ template<class Cst>
+ using type = lcp_byte;
+
+ private:
+
+ int_vector<8> m_small_lcp; // vector for LCP values < 255
+ int_vector<t_width> m_big_lcp; // vector for LCP values > 254
+ int_vector<t_width> m_big_lcp_idx; // index of LCP entries in the LCP array
+
+ typedef std::pair<size_type, size_type> tPII;
+ typedef std::vector<tPII> tVPII;
+
+ public:
+
+ //! Default Constructor
+ lcp_byte() = default;
+ lcp_byte(const lcp_byte&) = default;
+ lcp_byte(lcp_byte&&) = default;
+ lcp_byte& operator=(const lcp_byte&) = default;
+ lcp_byte& operator=(lcp_byte&&) = default;
+
+ //! Constructor
+ lcp_byte(cache_config& config) {
+ std::string lcp_file = cache_file_name(conf::KEY_LCP, config);
+ int_vector_buffer<> lcp_buf(lcp_file);
+ m_small_lcp = int_vector<8>(lcp_buf.size());
+ size_type l=0, max_l=0, max_big_idx=0, big_sum=0;
+
+ for (size_type i=0; i < m_small_lcp.size(); ++i) {
+ if ((l=lcp_buf[i]) < 255) {
+ m_small_lcp[i] = l;
+ } else {
+ m_small_lcp[i] = 255;
+ if (l > max_l) max_l = l;
+ max_big_idx = i;
+ ++big_sum;
+ }
+ }
+ m_big_lcp = int_vector<>(big_sum, 0, bits::hi(max_l)+1);
+ m_big_lcp_idx = int_vector<>(big_sum, 0, bits::hi(max_big_idx)+1);
+
+ for (size_type i=0,ii=0; i<m_small_lcp.size(); ++i) {
+ if ((l=lcp_buf[i]) >= 255) {
+ m_big_lcp[ii] = l;
+ m_big_lcp_idx[ii] = i;
+ ++ii;
+ }
+ }
+ }
+
+ //! Number of elements in the instance.
+ size_type size()const {
+ return m_small_lcp.size();
+ }
+
+ //! Returns the largest size that lcp_byte can ever have.
+ static size_type max_size() {
+ return int_vector<8>::max_size();
+ }
+
+ //! Returns if the data strucutre is empty.
+ bool empty()const {
+ return m_small_lcp.empty();
+ }
+
+ //! Swap method for lcp_byte
+ void swap(lcp_byte& lcp_c) {
+ m_small_lcp.swap(lcp_c.m_small_lcp);
+ m_big_lcp.swap(lcp_c.m_big_lcp);
+ m_big_lcp_idx.swap(lcp_c.m_big_lcp_idx);
+ }
+
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ * Time complexity: O(1) for small and O(log n) for large values
+ */
+ inline value_type operator[](size_type i)const {
+ if (m_small_lcp[i]!=255) {
+ return m_small_lcp[i];
+ } else {
+ size_type idx = lower_bound(m_big_lcp_idx.begin(),
+ m_big_lcp_idx.end(),i)
+ - m_big_lcp_idx.begin();
+ return m_big_lcp[idx];
+ }
+ }
+
+ //! Serialize to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name,
+ util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_small_lcp.serialize(out, child, "small_lcp");
+ written_bytes += m_big_lcp.serialize(out, child, "large_lcp");
+ written_bytes += m_big_lcp_idx.serialize(out, child, "large_lcp_idx");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in) {
+ m_small_lcp.load(in);
+ m_big_lcp.load(in);
+ m_big_lcp_idx.load(in);
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/lcp_dac.hpp b/include/sdsl/lcp_dac.hpp
new file mode 100644
index 0000000..420ec69
--- /dev/null
+++ b/include/sdsl/lcp_dac.hpp
@@ -0,0 +1,42 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011-2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file lcp_dac.hpp
+ \brief lcp_dac.hpp contains an implementation of a (compressed) LCP array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP_DAC
+#define INCLUDED_SDSL_LCP_DAC
+
+#include "lcp.hpp"
+#include "vectors.hpp"
+#include "rank_support_v5.hpp"
+
+namespace sdsl
+{
+
+//! A class for the compressed version of LCP information of an suffix array
+/*! A dac_vector is used to compress represent the values compressed.
+ * The template parameter are forwarded to the dac_vector.
+ * \tparam t_b Split block size.
+ * \tparam t_rank Rank structure to navigate between the different levels.
+ */
+template<uint8_t t_b = 4,
+ typename t_rank = rank_support_v5<>>
+using lcp_dac = lcp_vlc<dac_vector<t_b, t_rank>>;
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/lcp_support_sada.hpp b/include/sdsl/lcp_support_sada.hpp
new file mode 100644
index 0000000..b48d609
--- /dev/null
+++ b/include/sdsl/lcp_support_sada.hpp
@@ -0,0 +1,238 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file lcp_support_sada.hpp
+ \brief lcp_support_sada.hpp contains a compressed lcp array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP_SUPPORT_SADA
+#define INCLUDED_SDSL_LCP_SUPPORT_SADA
+
+#include "lcp.hpp"
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include "csa_sada.hpp" // for default template initialization
+#include "select_support.hpp" // for default template initialization
+#include <cassert>
+
+namespace sdsl
+{
+
+
+//! A class to represent the LCP array in compressed form.
+/*!
+ * \tparam t_csa Type of the Underlying CSA.
+ * \tparam t_bitvec Type of the bitvector used to store the unary
+ * representation of the deltas of the permuted LCP array.
+ * \tparam t_select Type of the select structure use to select on the
+ * bitvector of the unary representation of the PLCP array.
+ *
+ * \par Space complexity
+ * \f$ 2n+o(n) \f$ bits, where 2n is the worst case size of the
+ * unary encoding of the deltas of the PLCP array and o(n) for
+ * the select support data structure.
+ * \par Reference
+ * Kunihiko Sadakane:
+ * Succinct representations of lcp information and improvements in the
+ * compressed suffix arrays.
+ * SODA 2002: 225-232
+ */
+template<class t_csa = csa_sada<>,
+ class t_bitvec = bit_vector,
+ class t_select = typename t_bitvec::select_1_type>
+class _lcp_support_sada
+{
+ public:
+ typedef typename t_csa::value_type value_type;
+ typedef random_access_const_iterator<
+ _lcp_support_sada> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef ptrdiff_t difference_type;
+ typedef t_bitvec bit_vector_type;
+ typedef t_csa csa_type;
+ typedef t_select select_type;
+
+
+ typedef lcp_permuted_tag lcp_category;
+
+ enum { fast_access = 0,
+ text_order = 1,
+ sa_order = 0
+ };
+ // inner class which is used in CSTs to parametrize lcp classes
+ // with information about the CST.
+ template<class Cst>
+ struct type {
+ typedef _lcp_support_sada lcp_type;
+ };
+
+ private:
+ const csa_type* m_csa;
+ bit_vector_type m_data;
+ select_type m_select_support;
+
+ void copy(const _lcp_support_sada& lcp_c) {
+ m_csa = lcp_c.m_csa;
+ m_data = lcp_c.m_data;
+ m_select_support = lcp_c.m_select_support;
+ m_select_support.set_vector(&m_data);
+ }
+ public:
+ const t_csa*& csa = m_csa;
+ //! Default Constructor
+ _lcp_support_sada() {}
+
+ //! Copy constructor
+ _lcp_support_sada(const _lcp_support_sada& lcp_c) {
+ copy(lcp_c);
+ }
+
+ //! Move constructor
+ _lcp_support_sada(_lcp_support_sada&& lcp_c) {
+ *this = std::move(lcp_c);
+ }
+
+ //! Constructor
+ _lcp_support_sada(cache_config& config, const t_csa* f_csa) {
+ typedef typename t_csa::size_type size_type;
+ set_csa(f_csa);
+ if (!cache_file_exists(conf::KEY_ISA, config)) {
+ construct_isa(config);
+ }
+ int_vector<> lcp;
+ load_from_file(lcp, cache_file_name(conf::KEY_LCP, config));
+ std::string isa_file = cache_file_name(conf::KEY_ISA, config);
+ int_vector_buffer<> isa_buf(isa_file);
+ size_type n = lcp.size();
+ bit_vector data = bit_vector(2*n, 0);
+ size_type data_cnt=0;
+ for (size_type i=0, l=0, old_l=1; i < n; ++i) {
+ l = lcp[isa_buf[i]];
+ data_cnt += l + 1 - old_l;
+ data[data_cnt++] = 1;
+ old_l = l;
+ }
+ data.resize(data_cnt);
+ m_data = bit_vector_type(data);
+ util::init_support(m_select_support, &m_data);
+ }
+
+ void set_csa(const t_csa* f_csa) {
+ m_csa = f_csa;
+ }
+
+ //! Number of elements in the instance.
+ size_type size()const {
+ return m_csa->size();
+ }
+
+ //! Returns the largest size that _lcp_support_sada can ever have.
+ static size_type max_size() {
+ return t_csa::max_size();
+ }
+
+ //! Returns if the data structure is empty.
+ bool empty()const {
+ return m_csa->empty();
+ }
+
+ //! Swap method for _lcp_support_sada
+ void swap(_lcp_support_sada& lcp_c) {
+ m_data.swap(lcp_c.m_data);
+ util::swap_support(m_select_support, lcp_c.m_select_support,
+ &m_data, &(lcp_c.m_data));
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ * Time complexity: O(suffix array access)
+ */
+ inline value_type operator[](size_type i)const {
+ size_type j = (*m_csa)[i];
+ size_type s = m_select_support.select(j+1);
+ return s-(j<<1);
+ }
+
+ //! Assignment Operator.
+ _lcp_support_sada& operator=(const _lcp_support_sada& lcp_c) {
+ if (this != &lcp_c) {
+ copy(lcp_c);
+ }
+ return *this;
+ }
+
+ //! Assignment Move Operator.
+ _lcp_support_sada& operator=(_lcp_support_sada&& lcp_c) {
+ if (this != &lcp_c) {
+ m_csa = std::move(lcp_c.m_csa);
+ m_data = std::move(lcp_c.m_data);
+ m_select_support = std::move(lcp_c.m_select_support);
+ m_select_support.set_vector(&m_data);
+ }
+ return *this;
+ }
+
+ //! Serialize to a stream.
+ size_type
+ serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name,
+ util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_data.serialize(out, child, "data");
+ written_bytes += m_select_support.serialize(out, child,
+ "select_support");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in, const t_csa* csa) {
+ m_csa = csa;
+ m_data.load(in);
+ m_select_support.load(in, &m_data);
+ }
+};
+
+//! Helper class which provides _lcp_support_sada the context of a CSA.
+template<class t_bitvec = bit_vector,
+ class t_select = typename t_bitvec::select_1_type>
+struct lcp_support_sada
+{
+ template<class t_cst>
+ using type = _lcp_support_sada<typename t_cst::csa_type,
+ t_bitvec,
+ t_select>;
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/lcp_support_tree.hpp b/include/sdsl/lcp_support_tree.hpp
new file mode 100644
index 0000000..e291eda
--- /dev/null
+++ b/include/sdsl/lcp_support_tree.hpp
@@ -0,0 +1,157 @@
+#ifndef INCLUDED_SDSL_SUPPORT_LCP_TREE
+#define INCLUDED_SDSL_SUPPORT_LCP_TREE
+
+#include "lcp.hpp"
+#include "util.hpp"
+#include "lcp_wt.hpp"
+#include <iostream>
+#include <string>
+
+namespace sdsl
+{
+
+void construct_first_child_lcp(int_vector_buffer<>& lcp_buf, int_vector<>& fc_lcp);
+
+/*! This class composes a virtual LCP array from a LCP arrays which is in suffix array order
+ * (e.g. lcp_byte or lcp_bitcompressed) and a CST.
+ * The time consumption of the []-operator depends on:
+ * - The time consumption of the tlcp_idx function of the CST
+ * - The access time to the suffix array ordered LCP array
+ *
+ * \tparam t_lcp Type of the underlying LCP array. Must be an suffix array ordered one.
+ * \tparam t_cst Type of the underlying CST.
+ */
+template<class t_lcp, class t_cst>
+class _lcp_support_tree
+{
+ public:
+ typedef typename t_lcp::value_type value_type;
+ typedef random_access_const_iterator<_lcp_support_tree> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef typename t_lcp::size_type size_type;
+ typedef typename t_lcp::difference_type difference_type;
+
+ typedef lcp_tree_compressed_tag lcp_category;
+
+ enum { fast_access = 0,
+ text_order = t_lcp::text_order,
+ sa_order = t_lcp::sa_order
+ };
+
+ template<class CST>
+ struct type {
+ typedef _lcp_support_tree lcp_type;
+ };
+
+ private:
+
+ const t_cst* m_cst;
+ t_lcp m_lcp;
+
+ public:
+
+ //! Default constructor
+ _lcp_support_tree() = default;
+
+ // Destructor
+ ~_lcp_support_tree() = default;
+
+ //! Copy/Move constructor
+ _lcp_support_tree(const _lcp_support_tree&) = default;
+ _lcp_support_tree(_lcp_support_tree&&) = default;
+ _lcp_support_tree& operator=(const _lcp_support_tree&) = default;
+ _lcp_support_tree& operator=(_lcp_support_tree&&) = default;
+
+ //! Constructor
+ /*!
+ * \param config Cache configuration.
+ * \param cst A pointer to the CST.
+ */
+ _lcp_support_tree(cache_config& config, const t_cst* cst = nullptr) {
+ m_cst = cst;
+ std::string fc_lcp_key = "fc_lcp_" + util::to_string(util::id());
+ std::string tmp_file = cache_file_name(fc_lcp_key, config);
+ {
+ int_vector<0> temp_lcp;
+ int_vector_buffer<> lcp_buf(cache_file_name(conf::KEY_LCP, config));
+ construct_first_child_lcp(lcp_buf, temp_lcp);
+ // TODO: store LCP values directly
+ store_to_file(temp_lcp, tmp_file);
+ }
+ {
+ {
+ t_lcp tmp_lcp(config, fc_lcp_key); // works for lcp_kurtz, lcp_wt and lcp_bitcompressed
+ m_lcp.swap(tmp_lcp);
+ }
+ }
+ sdsl::remove(tmp_file);
+ }
+
+ size_type size()const {
+ return m_cst->size();
+ }
+
+ void set_cst(const t_cst* cst) {
+ m_cst = cst;
+ }
+
+ static size_type max_size() {
+ return t_lcp::max_size();
+ }
+
+ size_type empty()const {
+ return m_lcp.empty();
+ }
+
+ void swap(_lcp_support_tree& lcp_c) {
+ m_lcp.swap(lcp_c.m_lcp);
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{t_{find\_close} + t_{rank}} \f$
+ */
+ inline value_type operator[](size_type i)const {
+ return m_lcp[ m_cst->tlcp_idx(i) ];
+ }
+
+ //! Serialize to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ size_type written_bytes = 0;
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ written_bytes += m_lcp.serialize(out, child, "lcp");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in, const t_cst* cst=nullptr) {
+ m_lcp.load(in); // works for lcp_byte and lcp_bitcompressed
+ m_cst = cst;
+ }
+};
+
+//! Helper class which provides _lcp_support_tree the context of a CST.
+template<class t_lcp = lcp_wt<> >
+struct lcp_support_tree {
+ template<class t_cst>
+ using type = _lcp_support_tree<t_lcp, t_cst>;
+};
+
+} // end namespace
+#endif
diff --git a/include/sdsl/lcp_support_tree2.hpp b/include/sdsl/lcp_support_tree2.hpp
new file mode 100644
index 0000000..0dcec7a
--- /dev/null
+++ b/include/sdsl/lcp_support_tree2.hpp
@@ -0,0 +1,290 @@
+#ifndef INCLUDED_SDSL_SUPPORT_TREE2
+#define INCLUDED_SDSL_SUPPORT_TREE2
+
+#include "lcp.hpp"
+#include "util.hpp"
+#include "rank_support_v.hpp"
+#include "wt_huff.hpp"
+#include "sorted_multi_stack_support.hpp"
+#include <iostream>
+#include <string>
+
+namespace sdsl
+{
+
+// Forward declaration of helper method
+template<uint32_t t_dens, uint8_t t_bwt_width>
+void construct_first_child_and_lf_lcp(int_vector_buffer<>&,
+ int_vector_buffer<t_bwt_width>&,
+ const std::string&,
+ const std::string&, int_vector<>&);
+
+
+/*! An lcp array class for cst_sct3 and cst_sada.
+ * The time of the []-operator depends on:
+ * - The time of the []-operation of the wt_huff
+ * - The time of the LF calculation of the underlying CSA of the CST
+ * - The time of the tlcp_idx function of the CST
+ *
+ * \tparam t_dens Sample density in the CST.
+ * \tparam t_cst Underlying CST.
+ */
+template<uint32_t t_dens, class t_cst>
+class _lcp_support_tree2
+{
+ public:
+ typedef int_vector<>::value_type value_type;
+ typedef random_access_const_iterator<_lcp_support_tree2> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<>::difference_type difference_type;
+ typedef t_cst cst_type;
+ typedef wt_huff<bit_vector, rank_support_v5<>,
+ select_support_scan<1>,
+ select_support_scan<0> > small_lcp_type;
+
+ typedef lcp_tree_and_lf_compressed_tag lcp_category;
+
+ enum { fast_access = 0,
+ text_order = 0,
+ sa_order = 0
+ };
+
+ template<class CST>
+ struct type {
+ typedef _lcp_support_tree2 lcp_type;
+ };
+
+ private:
+ const cst_type* m_cst;
+ small_lcp_type m_small_lcp; // vector for lcp values < 254
+ int_vector<> m_big_lcp; // vector for lcp values >= 254
+
+ public:
+
+ //! Default constructor
+ _lcp_support_tree2() {}
+
+ //! Copy / Move constructor
+ _lcp_support_tree2(const _lcp_support_tree2&) = default;
+ _lcp_support_tree2(_lcp_support_tree2&&) = default;
+ _lcp_support_tree2& operator=(const _lcp_support_tree2&) = default;
+ _lcp_support_tree2& operator=(_lcp_support_tree2&&) = default;
+
+
+ //! Constructor
+ /*! \param config Cache configuration.
+
+ */
+ _lcp_support_tree2(cache_config& config, const cst_type* cst = nullptr) {
+ m_cst = cst;
+
+ int_vector_buffer<> lcp_buf(cache_file_name(conf::KEY_LCP, config));
+ std::string bwt_file = cache_file_name(key_trait<t_cst::csa_type::alphabet_type::int_width>::KEY_BWT, config);
+ int_vector_buffer<t_cst::csa_type::alphabet_type::int_width> bwt_buf(bwt_file);
+
+ std::string sml_lcp_file = tmp_file(config, "_fc_lf_lcp_sml");
+ std::string big_lcp_file = tmp_file(config, "_fc_lf_lcp_big");
+
+ construct_first_child_and_lf_lcp<t_dens>(lcp_buf, bwt_buf, sml_lcp_file, big_lcp_file, m_big_lcp);
+ int_vector_buffer<8> sml_lcp_buf(sml_lcp_file);
+
+ {
+ small_lcp_type tmp_small_lcp(sml_lcp_buf, sml_lcp_buf.size());
+ m_small_lcp.swap(tmp_small_lcp);
+ }
+ sml_lcp_buf.close(true);
+ sdsl::remove(big_lcp_file);
+ }
+
+ void set_cst(const cst_type* cst) {
+ m_cst = cst;
+ }
+
+ size_type size()const {
+ return m_cst->size();
+ }
+
+ static size_type max_size() {
+ return int_vector<>::max_size();
+ }
+
+ size_type empty()const {
+ return m_small_lcp.empty();
+ }
+
+ void swap(_lcp_support_tree2& lcp_c) {
+ m_small_lcp.swap(lcp_c.m_small_lcp);
+ m_big_lcp.swap(lcp_c.m_big_lcp);
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{t_{find\_close} + t_{rank}} \f$
+ */
+ inline value_type operator[](size_type i)const {
+ size_type idx, offset=0;
+ uint8_t val;
+start:
+ idx = m_cst->tlcp_idx(i);
+ val = m_small_lcp[idx];
+ if (val < 254) {
+ return val;// - offset;
+ } else if (val == 254) { // if lcp value is >= 254 and position i is reducible
+ i = m_cst->csa.lf[i]; // i = LF[i] // (*m_psi)(i);
+ ++offset; // goto lcp value, which is one bigger
+ goto start;
+ } else { // if lcp value is >= 254 and (not reducable or sampled)
+ return m_big_lcp[m_small_lcp.rank(idx ,255)] - offset;
+ }
+ }
+
+ //! Serialize to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_small_lcp.serialize(out, child, "small_lcp");
+ written_bytes += m_big_lcp.serialize(out, child, "large_lcp");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in, const t_cst* cst=nullptr) {
+ m_small_lcp.load(in);
+ m_big_lcp.load(in);
+ m_cst = cst;
+ }
+};
+
+//! Helper class which provides _lcp_support_tree2 the context of a CST.
+template<uint32_t t_dens=16>
+struct lcp_support_tree2 {
+ template<class t_cst>
+ using type = _lcp_support_tree2<t_dens, t_cst>;
+};
+
+
+/*!
+ * \tparam t_dens Sample an LCP value x if x modulo t_dens == 0
+ * \tparam t_bwt_width Width of the integers of the streamed BWT array.
+ * \tparam
+ */
+template<uint32_t t_dens, uint8_t t_bwt_width>
+void construct_first_child_and_lf_lcp(int_vector_buffer<>& lcp_buf,
+ int_vector_buffer<t_bwt_width>& bwt_buf,
+ const std::string& small_lcp_file,
+ const std::string& big_lcp_file,
+ int_vector<>& big_lcp)
+{
+ typedef int_vector<>::size_type size_type;
+ const size_type M = 255; // limit for values represented in the small LCP part
+ size_type buf_len = 1000000;
+ lcp_buf.buffersize(buf_len);
+ bwt_buf.buffersize(buf_len);
+ size_type n = lcp_buf.size();
+
+ osfstream sml_lcp_out(small_lcp_file, std::ios::out | std::ios::trunc);
+ uint64_t bit_size = 8*n;
+ sml_lcp_out.write((char*) &bit_size, sizeof(bit_size));
+
+ osfstream big_lcp_out(big_lcp_file, std::ios::out | std::ios::trunc);
+
+ size_type fc_cnt = 0; // number of lcp values at the first child r
+ size_type fc_cnt_big = 0; // number of lcp values at the first child which are big and not reducible
+ size_type fc_cnt_big2 = 0;
+ sorted_multi_stack_support vec_stack(n); // occupies 2n bits
+ bit_vector is_big_and_not_reducable(n, 0); // initialized with 0s
+ bool is_one_big_and_not_reducable = false; // all positions have to be reducible
+
+ size_type y, max_lcp=0;
+ uint64_t last_bwti=0, val;
+ for (size_type i=0, x; i < n; ++i) {
+ x = lcp_buf[i];
+ is_one_big_and_not_reducable = false;
+
+ while (!vec_stack.empty() and x < vec_stack.top()) {
+ y = vec_stack.top();
+ is_one_big_and_not_reducable |= is_big_and_not_reducable[vec_stack.size()-1];
+ if (vec_stack.pop()) { // if y was the last copy of y on the stack
+ if (y > M-2) {
+ if (is_one_big_and_not_reducable) {
+ val = M;
+ big_lcp_out.write((char*)&y, sizeof(y));
+ ++fc_cnt_big;
+ if (y > max_lcp) max_lcp = y;
+ } else {
+ val = M-1;
+ ++fc_cnt_big2;
+ }
+ } else {
+ val = y;
+ }
+ sml_lcp_out.write((const char*)&val, 1);
+ ++fc_cnt;
+ is_one_big_and_not_reducable = false;
+ }
+ }
+ if (x > M-2 and(0 == i or last_bwti != bwt_buf[i] or x % t_dens == 0)) {
+ is_big_and_not_reducable[vec_stack.size()] = 1;
+ } else {
+ is_big_and_not_reducable[vec_stack.size()] = 0;
+ }
+ vec_stack.push(x);
+ last_bwti = bwt_buf[i];
+ }
+
+ while (!vec_stack.empty()) {
+ y = vec_stack.top();
+ if (vec_stack.pop()) {
+ if (y > M-2) {
+ if (is_big_and_not_reducable[vec_stack.size()]) {
+ val = M;
+ big_lcp_out.write((char*)&y, sizeof(y));
+ ++fc_cnt_big;
+ if (y > max_lcp) max_lcp = y;
+ } else {
+ val = M-1;
+ ++fc_cnt_big2;
+ }
+ } else {
+ val = y;
+ }
+ sml_lcp_out.write((const char*)&val, 1);
+ ++fc_cnt;
+ }
+ }
+ // write number of elements of sml_lcp into the out file stream
+ sml_lcp_out.seekp(0);
+ bit_size = 8*fc_cnt;
+ sml_lcp_out.write((char*) &bit_size, sizeof(bit_size));
+ sml_lcp_out.close();
+
+ big_lcp_out.close();
+ isfstream big_lcp_in(big_lcp_file);
+ big_lcp.width(bits::hi(max_lcp)+1);
+ big_lcp.resize(fc_cnt_big);
+
+ for (size_type i=0; i<fc_cnt_big; ++i) {
+ big_lcp_in.read((char*)&y, sizeof(y));
+ big_lcp[i] = y;
+ }
+}
+
+} // end namespace
+#endif
diff --git a/include/sdsl/lcp_vlc.hpp b/include/sdsl/lcp_vlc.hpp
new file mode 100644
index 0000000..f0015aa
--- /dev/null
+++ b/include/sdsl/lcp_vlc.hpp
@@ -0,0 +1,143 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/* \file lcp_vlc.hpp
+ \brief lcp_vlc.hpp contains an implementation of a (compressed) LCP array.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP_VLC
+#define INCLUDED_SDSL_LCP_VLC
+
+#include "lcp.hpp"
+#include "vlc_vector.hpp"
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include <iostream>
+#include <cassert>
+#include <vector>
+
+namespace sdsl
+{
+
+// A class for a compressed LCP array based on variable-length coding.
+/*
+ * \tparam t_vlc_vec Type of the underlying variable-length coder.
+ */
+template<class t_vlc_vec = vlc_vector<> >
+class lcp_vlc
+{
+ public:
+
+ typedef typename t_vlc_vec::value_type value_type;
+ typedef random_access_const_iterator<lcp_vlc> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef typename t_vlc_vec::size_type size_type;
+ typedef typename t_vlc_vec::difference_type difference_type;
+ typedef t_vlc_vec vlc_vec_type;
+
+ typedef lcp_plain_tag lcp_category;
+
+ enum { fast_access = 0,
+ text_order = 0,
+ sa_order = 1
+ };
+
+ template<class Cst>
+ using type = lcp_vlc;
+
+ private:
+
+ vlc_vec_type m_vec;
+
+ public:
+
+ //! Default Constructor
+ lcp_vlc() = default;
+
+ //! Copy / Move constructor
+ lcp_vlc(const lcp_vlc&) = default;
+ lcp_vlc(lcp_vlc&&) = default;
+ lcp_vlc& operator=(const lcp_vlc&) = default;
+ lcp_vlc& operator=(lcp_vlc&&) = default;
+
+ //! Construct
+ lcp_vlc(cache_config& config, std::string other_key="") {
+ std::string lcp_key = conf::KEY_LCP;
+ if ("" != other_key) {
+ lcp_key = other_key;
+ }
+ int_vector_buffer<> lcp_buf(cache_file_name(lcp_key, config));
+ vlc_vec_type tmp_vec(lcp_buf);
+ m_vec.swap(tmp_vec);
+ }
+
+ //! Number of elements in the instance.
+ size_type size()const {
+ return m_vec.size();
+ }
+
+ //! Returns the largest size that lcp_vlc can ever have.
+ static size_type max_size() {
+ return vlc_vec_type::max_size();
+ }
+
+ //! Returns if the data strucutre is empty.
+ bool empty()const {
+ return m_vec.empty();
+ }
+
+ //! Swap method for lcp_vlc
+ void swap(lcp_vlc& lcp_c) {
+ m_vec.swap(lcp_c.m_vec);
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ inline value_type operator[](size_type i)const {
+ return m_vec[i];
+ }
+
+ //! Serialize to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_vec.serialize(out, child, "vec");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in) {
+ m_vec.load(in);
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/lcp_wt.hpp b/include/sdsl/lcp_wt.hpp
new file mode 100644
index 0000000..dd6bc9d
--- /dev/null
+++ b/include/sdsl/lcp_wt.hpp
@@ -0,0 +1,199 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file lcp_wt.hpp
+ \brief lcp_wt.hpp contains a (compressed) LCP array based on a WT.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LCP_WT
+#define INCLUDED_SDSL_LCP_WT
+
+#include "lcp.hpp"
+#include "wt_huff.hpp"
+#include "int_vector.hpp"
+#include "iterators.hpp"
+#include "util.hpp"
+#include <iostream>
+#include <algorithm> // for lower_bound
+#include <cassert>
+#include <cstring> // for strlen
+#include <iomanip>
+#include <iterator>
+#include <vector>
+#include <utility> // for pair
+#include <stdexcept>
+
+namespace sdsl
+{
+
+//! A class for the compressed version of lcp information of an suffix array
+/*! We use \f$H_0\f$ bit for each lcp values < 255 and \f$ log n \f$ bits for
+ * each LCP value which is greater than 254.
+ * \tparam t_width Width of int_vector storing the large LCP values.
+ * \par Time complexity
+ * - \f$\Order{1}\f$ if the value is less than 255 and
+ * - \f$\Order{\log n}\f$ (\f$n=size()\f$) otherwise.
+ */
+template<uint8_t t_width=0>
+class lcp_wt
+{
+ public:
+
+ typedef typename int_vector<t_width>::value_type value_type;
+ typedef random_access_const_iterator<lcp_wt> const_iterator;
+ typedef const_iterator iterator;
+ typedef const value_type const_reference;
+ typedef const_reference reference;
+ typedef const_reference* pointer;
+ typedef const pointer const_pointer;
+ typedef int_vector<>::size_type size_type;
+ typedef ptrdiff_t difference_type;
+ typedef wt_huff<bit_vector, rank_support_v<>,
+ select_support_scan<1>,
+ select_support_scan<0>> small_lcp_type;
+
+ typedef lcp_plain_tag lcp_category;
+
+ enum { fast_access = 0,
+ text_order = 0,
+ sa_order = 1
+ }; // as the lcp_wt is not fast for texts with long repetition
+
+ template<class Cst>
+ using type = lcp_wt;
+
+ private:
+
+ small_lcp_type m_small_lcp; // vector for lcp values < 255
+ int_vector<t_width> m_big_lcp; // vector for lcp values > 254
+
+ typedef std::pair<size_type, size_type> tPII;
+ typedef std::vector<tPII> tVPII;
+
+ public:
+
+ //! Default Constructor
+ lcp_wt() = default;
+ //! Copy / Move constructor
+ lcp_wt(const lcp_wt&) = default;
+ lcp_wt(lcp_wt&&) = default;
+ lcp_wt& operator=(const lcp_wt&) = default;
+ lcp_wt& operator=(lcp_wt&&) = default;
+
+ //! Constructor
+ lcp_wt(cache_config& config, std::string other_key="") {
+ std::string temp_file = tmp_file(config, "_lcp_sml");
+ std::string lcp_key = conf::KEY_LCP;
+ if ("" != other_key) {
+ lcp_key = other_key;
+ }
+ int_vector_buffer<> lcp_buf(cache_file_name(lcp_key, config));
+ size_type l=0, max_l=0, big_sum=0, n = lcp_buf.size();
+ {
+ int_vector<8> small_lcp = int_vector<8>(n);
+ for (size_type i=0; i < n; ++i) {
+ if ((l=lcp_buf[i]) < 255) {
+ small_lcp[i] = l;
+ } else {
+ small_lcp[i] = 255;
+ if (l > max_l) max_l = l;
+ ++big_sum;
+ }
+ }
+ store_to_file(small_lcp, temp_file);
+ }
+ {
+ int_vector_buffer<8> lcp_sml_buf(temp_file);
+ small_lcp_type tmp(lcp_sml_buf, lcp_sml_buf.size());
+ m_small_lcp.swap(tmp);
+ }
+ sdsl::remove(temp_file);
+ m_big_lcp = int_vector<>(big_sum, 0, bits::hi(max_l)+1);
+ {
+ for (size_type i=0, ii=0; i < n; ++i) {
+ if (lcp_buf[i] >= 255) {
+ m_big_lcp[ ii++ ] = lcp_buf[i];
+ }
+ }
+ }
+ }
+
+ //! Number of elements in the instance.
+ size_type size()const {
+ return m_small_lcp.size();
+ }
+
+ //! Returns the largest size that lcp_wt can ever have.
+ static size_type max_size() {
+ return int_vector<8>::max_size();
+ }
+
+ //! Returns if the data structure is empty.
+ bool empty()const {
+ return 0==m_small_lcp.size();
+ }
+
+ //! Swap method for lcp_wt
+ void swap(lcp_wt& lcp_c) {
+ m_small_lcp.swap(lcp_c.m_small_lcp);
+ m_big_lcp.swap(lcp_c.m_big_lcp);
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! []-operator
+ /*! \param i Index of the value. \f$ i \in [0..size()-1]\f$.
+ */
+ inline value_type operator[](size_type i)const {
+ if (m_small_lcp[i]!=255) {
+ return m_small_lcp[i];
+ } else {
+ return m_big_lcp[ m_small_lcp.rank(i, 255) ];
+ }
+ }
+
+ //! Serialize to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_small_lcp.serialize(out, child, "small_lcp");
+ written_bytes += m_big_lcp.serialize(out, child, "large_lcp");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load from a stream.
+ void load(std::istream& in) {
+ m_small_lcp.load(in);
+ m_big_lcp.load(in);
+ }
+
+
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/louds_tree.hpp b/include/sdsl/louds_tree.hpp
new file mode 100644
index 0000000..b1cc36a
--- /dev/null
+++ b/include/sdsl/louds_tree.hpp
@@ -0,0 +1,206 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+*/
+/*! \file louds_tree.hpp
+ \brief louds_tree.hpp contains a classes for the succinct tree representation LOUDS (level order unary degree sequence).
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_LOUDS_TREE
+#define INCLUDED_SDSL_LOUDS_TREE
+
+#include "int_vector.hpp"
+#include "util.hpp"
+#include <ostream>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A class for the node representation of louds_tree
+class louds_node
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ private:
+ size_type m_nr; // node number
+ size_type m_pos; // position in the LOUDS
+ public:
+ const size_type& nr;
+ const size_type& pos;
+
+ louds_node(size_type f_nr=0, size_type f_pos=0):m_nr(f_nr), m_pos(f_pos),nr(m_nr),pos(m_pos) {}
+
+ bool operator==(const louds_node& v)const {
+ return m_nr == v.m_nr and m_pos ==v.m_pos;
+ }
+
+ bool operator!=(const louds_node& v)const {
+ return !(v==*this);
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const louds_node& v);
+
+//! A tree class based on the level order unary degree sequence (LOUDS) representation.
+/*!
+ * \tparam bit_vec_t The bit vector representation used for LOUDS.
+ * \tparam select_1_t A select_support on 1-bits required for the child(v,i) operation.
+ * \tparam select_0_t A select_support on 0-bits required for the parent operation.
+ *
+ * Example of the structure: A tree with balanced parentheses representation (()()(()()))
+ * is translated into 10001110011. Traverse the tree in breadth-first order an write
+ * for each node a 1-bit followed by as many 0-bits as the node has children.
+ *
+ * Disadvantages of louds: No efficient support for subtree size.
+*/
+template<class bit_vec_t = bit_vector, class select_1_t = typename bit_vec_t::select_1_type, class select_0_t = typename bit_vec_t::select_0_type>
+class louds_tree
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef louds_node node_type;
+ typedef bit_vec_t bit_vector_type;
+ typedef select_1_t select_1_type;
+ typedef select_0_t select_0_type;
+
+ private:
+ bit_vector_type m_bv; // bit vector for the LOUDS sequence
+ select_1_type m_bv_select1; // select support for 1-bits on m_bv
+ select_0_type m_bv_select0; // select support for 0-bits on m_bv
+ public:
+ const bit_vector_type& bv; // const reference to the LOUDS sequence
+
+ //! Constructor for a cst and a root node for the traversal
+ template<class Cst, class CstBfsIterator>
+ louds_tree(const Cst& cst, const CstBfsIterator begin, const CstBfsIterator end):m_bv(), m_bv_select1(), m_bv_select0(), bv(m_bv) {
+ bit_vector tmp_bv(4*cst.size(*begin) , 0); // resize the bit_vector to the maximal
+ // possible size 2*2*#leaves in the tree
+ size_type pos = 0;
+ for (CstBfsIterator it = begin; it != end;) {
+ tmp_bv[pos++] = 1;
+ size_type size = it.size();
+ ++it;
+ pos += it.size()+1-size;
+ }
+ tmp_bv.resize(pos);
+ m_bv = bit_vector_type(std::move(tmp_bv));
+ util::init_support(m_bv_select1, &m_bv);
+ util::init_support(m_bv_select0, &m_bv);
+ }
+
+ louds_tree(const louds_tree& lt) : bv(m_bv) {
+ *this = lt;
+ }
+
+ louds_tree(louds_tree&& lt) : bv(m_bv) {
+ *this = std::move(lt);
+ }
+
+ louds_tree& operator=(const louds_tree& lt) {
+ if (this != <) {
+ m_bv = lt.m_bv;
+ m_bv_select1 = lt.m_bv_select1;
+ m_bv_select1.set_vector(&m_bv);
+ m_bv_select0 = lt.m_bv_select0;
+ m_bv_select0.set_vector(&m_bv);
+ }
+ return *this;
+ }
+
+ louds_tree& operator=(louds_tree&& lt) {
+ if (this != <) {
+ m_bv = std::move(lt.m_bv);
+ m_bv_select1 = std::move(lt.m_bv_select1);
+ m_bv_select1.set_vector(&m_bv);
+ m_bv_select0 = std::move(lt.m_bv_select0);
+ m_bv_select0.set_vector(&m_bv);
+ }
+ return *this;
+ }
+
+ //! Returns the root node
+ node_type root() const {
+ return louds_node(0, 0);
+ }
+
+ //! Returns the number of nodes in the tree.
+ size_type nodes()const {
+ return m_bv.size()+1/2;
+ }
+
+ //! Indicates if a node is a leaf.
+ /*! \param v A node.
+ */
+ bool is_leaf(const node_type& v) const {
+ // node is the last leaf or has no children, so m_bv[v.pos]==1
+ return (v.pos+1 == m_bv.size()) or m_bv[v.pos+1];
+ }
+
+ //! Returns the number of children of a node.
+ /*!
+ * \param v A node.
+ */
+ size_type degree(const node_type& v) const {
+ if (is_leaf(v)) { // handles boundary cases
+ return 0;
+ }
+ // position of the next node - node position - 1
+ return m_bv_select1(v.nr+2) - v.pos - 1;
+ }
+
+ //! Returns the i-child of a node.
+ /*!
+ * \param v The parent node.
+ * \param i Index of the child. Indexing starts at 1.
+ * \pre \f$ i \in [1..degree(v)] \f$
+ */
+ node_type child(const node_type& v, size_type i)const {
+ size_type pos = v.pos+i; // go to the position of the child's zero
+ // (#bits = pos+1) - (#1-bits = v.nr+1)
+ size_type zeros = pos+1 - (v.nr+1);
+ return louds_node(zeros, m_bv_select1(zeros+1));
+ }
+
+ //! Returns the parent of a node v or root() if v==root().
+ node_type parent(const node_type& v)const {
+ if (v == root()) {
+ return root();
+ }
+ size_type zero_pos = m_bv_select0(v.nr);
+ size_type parent_nr = (zero_pos+1) - v.nr - 1;
+ return node_type(parent_nr, m_bv_select1(parent_nr+1));
+ }
+
+ //! Returns an unique id for each node in [0..size()-1]
+ size_type id(const node_type& v)const {
+ return v.nr;
+ }
+
+
+ void swap(louds_tree& tree) {
+ m_bv.swap(tree.m_bv);
+ util::swap_support(m_bv_select1, tree.m_select1, &m_bv, &(tree.m_bv));
+ util::swap_support(m_bv_select0, tree.m_select0, &m_bv, &(tree.m_bv));
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ m_bv.serialize(out, child, "bitvector");
+ m_bv_select1(out, child, "select1");
+ m_bv_select0(out, child, "select0");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ m_bv.load(in);
+ m_bv_select1.load(in);
+ m_bv_select1.set_vector(&m_bv);
+ m_bv_select0.load(in);
+ m_bv_select0.set_vector(&m_bv);
+ }
+};
+
+}// end namespace sdsl
+#endif
diff --git a/include/sdsl/memory_management.hpp b/include/sdsl/memory_management.hpp
new file mode 100644
index 0000000..6804a80
--- /dev/null
+++ b/include/sdsl/memory_management.hpp
@@ -0,0 +1,343 @@
+/*!\file memory_management.hpp
+ \brief memory_management.hpp contains two function for allocating and deallocating memory
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_MEMORY_MANAGEMENT
+#define INCLUDED_SDSL_MEMORY_MANAGEMENT
+
+#include "uintx_t.hpp"
+#include "util.hpp"
+#include <map>
+#include <iostream>
+#include <cstdlib>
+#include <mutex>
+#include <chrono>
+#include <cstring>
+#include <set>
+#include <cstddef>
+#include <stack>
+#include "config.hpp"
+
+namespace sdsl
+{
+
+class memory_monitor;
+
+template<format_type F>
+void write_mem_log(std::ostream& out,const memory_monitor& m);
+
+class memory_monitor
+{
+ public:
+ using timer = std::chrono::high_resolution_clock;
+ struct mm_alloc {
+ timer::time_point timestamp;
+ int64_t usage;
+ mm_alloc(timer::time_point t,int64_t u) : timestamp(t) , usage(u) {};
+ };
+ struct mm_event {
+ std::string name;
+ std::vector<mm_alloc> allocations;
+ mm_event(std::string n,int64_t usage) : name(n) {
+ allocations.emplace_back(timer::now(),usage);
+ };
+ bool operator< (const mm_event& a) const {
+ if (a.allocations.size() && this->allocations.size()) {
+ if (this->allocations[0].timestamp == a.allocations[0].timestamp) {
+ return this->allocations.back().timestamp < a.allocations.back().timestamp;
+ } else {
+ return this->allocations[0].timestamp < a.allocations[0].timestamp;
+ }
+ }
+ return true;
+ }
+ };
+ struct mm_event_proxy {
+ bool add;
+ timer::time_point created;
+ mm_event_proxy(const std::string& name,int64_t usage,bool a) : add(a) {
+ if (add) {
+ auto& m = the_monitor();
+ std::lock_guard<util::spin_lock> lock(m.spinlock);
+ m.event_stack.emplace(name,usage);
+ }
+ }
+ ~mm_event_proxy() {
+ if (add) {
+ auto& m = the_monitor();
+ std::lock_guard<util::spin_lock> lock(m.spinlock);
+ auto& cur = m.event_stack.top();
+ auto cur_time = timer::now();
+ cur.allocations.emplace_back(cur_time,m.current_usage);
+ m.completed_events.emplace_back(std::move(cur));
+ m.event_stack.pop();
+ // add a point to the new "top" with the same memory
+ // as before but just ahead in time
+ if (! m.event_stack.empty()) {
+ if (m.event_stack.top().allocations.size()) {
+ auto last_usage = m.event_stack.top().allocations.back().usage;
+ m.event_stack.top().allocations.emplace_back(cur_time,last_usage);
+ }
+ }
+ }
+ }
+ };
+ std::chrono::milliseconds log_granularity = std::chrono::milliseconds(20);
+ int64_t current_usage = 0;
+ bool track_usage = false;
+ std::vector<mm_event> completed_events;
+ std::stack<mm_event> event_stack;
+ timer::time_point start_log;
+ timer::time_point last_event;
+ util::spin_lock spinlock;
+ private:
+ // disable construction of the object
+ memory_monitor() {};
+ ~memory_monitor() {
+ if (track_usage) {
+ stop();
+ }
+ }
+ memory_monitor(const memory_monitor&) = delete;
+ memory_monitor& operator=(const memory_monitor&) = delete;
+ private:
+ static memory_monitor& the_monitor() {
+ static memory_monitor m;
+ return m;
+ }
+ public:
+ static void granularity(std::chrono::milliseconds ms) {
+ auto& m = the_monitor();
+ m.log_granularity = ms;
+ }
+ static int64_t peak() {
+ auto& m = the_monitor();
+ int64_t max = 0;
+ for (auto events : m.completed_events) {
+ for (auto alloc : events.allocations) {
+ if (max < alloc.usage) {
+ max = alloc.usage;
+ }
+ }
+ }
+ return max;
+ }
+
+ static void start() {
+ auto& m = the_monitor();
+ m.track_usage = true;
+ // clear if there is something there
+ if (m.completed_events.size()) {
+ m.completed_events.clear();
+ }
+ while (m.event_stack.size()) {
+ m.event_stack.pop();
+ }
+ m.start_log = timer::now();
+ m.current_usage = 0;
+ m.last_event = m.start_log;
+ m.event_stack.emplace("unknown",0);
+ }
+ static void stop() {
+ auto& m = the_monitor();
+ while (! m.event_stack.empty()) {
+ m.completed_events.emplace_back(std::move(m.event_stack.top()));
+ m.event_stack.pop();
+ }
+ m.track_usage = false;
+ }
+ static void record(int64_t delta) {
+ auto& m = the_monitor();
+ if (m.track_usage) {
+ std::lock_guard<util::spin_lock> lock(m.spinlock);
+ auto cur = timer::now();
+ if (m.last_event + m.log_granularity < cur) {
+ m.event_stack.top().allocations.emplace_back(cur,m.current_usage);
+ m.current_usage = m.current_usage + delta;
+ m.event_stack.top().allocations.emplace_back(cur,m.current_usage);
+ m.last_event = cur;
+ } else {
+ if (m.event_stack.top().allocations.size()) {
+ m.current_usage = m.current_usage + delta;
+ m.event_stack.top().allocations.back().usage = m.current_usage;
+ m.event_stack.top().allocations.back().timestamp = cur;
+ }
+ }
+ }
+ }
+ static mm_event_proxy event(const std::string& name) {
+ auto& m = the_monitor();
+ if (m.track_usage) {
+ return mm_event_proxy(name,m.current_usage,true);
+ }
+ return mm_event_proxy(name,m.current_usage,false);
+ }
+ template<format_type F>
+ static void write_memory_log(std::ostream& out) {
+ write_mem_log<F>(out,the_monitor());
+ }
+};
+
+#pragma pack(push, 1)
+typedef struct mm_block {
+ size_t size;
+ struct mm_block* next;
+ struct mm_block* prev;
+} mm_block_t;
+
+typedef struct bfoot {
+ size_t size;
+} mm_block_foot_t;
+#pragma pack(pop)
+
+#include <sys/mman.h>
+
+class hugepage_allocator
+{
+ private:
+ uint8_t* m_base = nullptr;
+ mm_block_t* m_first_block = nullptr;
+ uint8_t* m_top = nullptr;
+ size_t m_total_size = 0;
+ std::multimap<size_t,mm_block_t*> m_free_large;
+ private:
+ size_t determine_available_hugepage_memory();
+ void coalesce_block(mm_block_t* block);
+ void split_block(mm_block_t* bptr,size_t size);
+ uint8_t* hsbrk(size_t size);
+ mm_block_t* new_block(size_t size);
+ void remove_from_free_set(mm_block_t* block);
+ void insert_into_free_set(mm_block_t* block);
+ mm_block_t* find_free_block(size_t size_in_bytes);
+ mm_block_t* last_block();
+ void print_heap();
+ public:
+ void init(SDSL_UNUSED size_t size_in_bytes = 0) {
+#ifdef MAP_HUGETLB
+ if (size_in_bytes == 0) {
+ size_in_bytes = determine_available_hugepage_memory();
+ }
+
+ m_total_size = size_in_bytes;
+ m_base = (uint8_t*) mmap(nullptr, m_total_size,
+ (PROT_READ | PROT_WRITE),
+ (MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE), 0, 0);
+ if (m_base == MAP_FAILED) {
+ throw std::system_error(ENOMEM,std::system_category(),
+ "hugepage_allocator could not allocate hugepages");
+ } else {
+ // init the allocator
+ m_top = m_base;
+ m_first_block = (mm_block_t*) m_base;
+ }
+#else
+ throw std::system_error(ENOMEM,std::system_category(),
+ "hugepage_allocator: MAP_HUGETLB / hugepage support not available");
+#endif
+ }
+ void* mm_realloc(void* ptr, size_t size);
+ void* mm_alloc(size_t size_in_bytes);
+ void mm_free(void* ptr);
+ bool in_address_space(void* ptr) {
+ // check if ptr is in the hugepage address space
+ if (ptr == nullptr) {
+ return true;
+ }
+ if (ptr >= m_base && ptr < m_top) {
+ return true;
+ }
+ return false;
+ }
+ static hugepage_allocator& the_allocator() {
+ static hugepage_allocator a;
+ return a;
+ }
+};
+
+class memory_manager
+{
+ private:
+ bool hugepages = false;
+ private:
+ static memory_manager& the_manager() {
+ static memory_manager m;
+ return m;
+ }
+ public:
+ static uint64_t* alloc_mem(size_t size_in_bytes) {
+ auto& m = the_manager();
+ if (m.hugepages) {
+ return (uint64_t*) hugepage_allocator::the_allocator().mm_alloc(size_in_bytes);
+ } else {
+ return (uint64_t*) calloc(size_in_bytes,1);
+ }
+ }
+ static void free_mem(uint64_t* ptr) {
+ auto& m = the_manager();
+ if (m.hugepages and hugepage_allocator::the_allocator().in_address_space(ptr)) {
+ hugepage_allocator::the_allocator().mm_free(ptr);
+ } else {
+ std::free(ptr);
+ }
+ }
+ static uint64_t* realloc_mem(uint64_t* ptr,size_t size) {
+ auto& m = the_manager();
+ if (m.hugepages and hugepage_allocator::the_allocator().in_address_space(ptr)) {
+ return (uint64_t*) hugepage_allocator::the_allocator().mm_realloc(ptr,size);
+ } else {
+ return (uint64_t*) realloc(ptr,size);
+ }
+ }
+ public:
+ static void use_hugepages(size_t bytes = 0) {
+ auto& m = the_manager();
+ hugepage_allocator::the_allocator().init(bytes);
+ m.hugepages = true;
+ }
+ template<class t_vec>
+ static void resize(t_vec& v, const typename t_vec::size_type size) {
+ uint64_t old_size_in_bytes = ((v.m_size+63)>>6)<<3;
+ uint64_t new_size_in_bytes = ((size+63)>>6)<<3;
+ bool do_realloc = old_size_in_bytes != new_size_in_bytes;
+ v.m_size = size;
+ if (do_realloc || v.m_data == nullptr) {
+ // Note that we allocate 8 additional bytes if m_size % 64 == 0.
+ // We need this padding since rank data structures do a memory
+ // access to this padding to answer rank(size()) if size()%64 ==0.
+ // Note that this padding is not counted in the serialize method!
+ size_t allocated_bytes = (((size+64)>>6)<<3);
+ v.m_data = memory_manager::realloc_mem(v.m_data,allocated_bytes);
+ if (allocated_bytes != 0 && v.m_data == nullptr) {
+ throw std::bad_alloc();
+ }
+ // update and fill with 0s
+ if (v.bit_size() < v.capacity()) {
+ bits::write_int(v.m_data+(v.bit_size()>>6), 0, v.bit_size()&0x3F, v.capacity() - v.bit_size());
+ }
+ if (((v.m_size) % 64) == 0) { // initialize unreachable bits with 0
+ v.m_data[v.m_size/64] = 0;
+ }
+
+ // update stats
+ if (do_realloc) {
+ memory_monitor::record((int64_t)new_size_in_bytes-(int64_t)old_size_in_bytes);
+ }
+ }
+ }
+ template<class t_vec>
+ static void clear(t_vec& v) {
+ int64_t size_in_bytes = ((v.m_size+63)>>6)<<3;
+ // remove mem
+ memory_manager::free_mem(v.m_data);
+ v.m_data = nullptr;
+
+ // update stats
+ if (size_in_bytes) {
+ memory_monitor::record(size_in_bytes*-1);
+ }
+ }
+};
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/nearest_neighbour_dictionary.hpp b/include/sdsl/nearest_neighbour_dictionary.hpp
new file mode 100644
index 0000000..6f3880b
--- /dev/null
+++ b/include/sdsl/nearest_neighbour_dictionary.hpp
@@ -0,0 +1,270 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file nearest_neighbour_dictionary.hpp
+ \brief nearest_neighbour_dictionary.hpp contains a class which supports rank/select for sparse populated sdsl::bit_vectors.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_NEAREST_NEIGHBOUR_DICTIONARY
+#define INCLUDED_SDSL_NEAREST_NEIGHBOUR_DICTIONARY
+
+#include "int_vector.hpp"
+#include "rank_support.hpp"
+#include "util.hpp"
+#include <stdexcept>
+#include <string>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! Nearest neighbour dictionary for sparse uniform sets (described in Geary et al., A Simple Optimal Representation for Balanced Parentheses, CPM 2004).
+/*!
+ * Template parameter t_sample_dens corresponds to parameter t in the paper.
+ * The data structure the following methods:
+ * - rank
+ * - select
+ * - prev
+ * - next
+ * @ingroup rank_support_group
+ * @ingroup select_support_group
+ *
+*/
+// TODO: implement an iterator for the ones in the nearest neighbour dictionary!!! used in the construction of the balanced parentheses support
+template<uint8_t t_sample_dens>
+class nearest_neighbour_dictionary
+{
+ private:
+ static_assert(t_sample_dens != 0 , "nearest_neighbour_dictionary: t_sample_dens should not be equal 0!");
+ public:
+ typedef bit_vector::size_type size_type;
+ private:
+ int_vector<> m_abs_samples; // absolute samples array corresponds to array \f$ A_1 \f$ in the paper
+ int_vector<> m_differences; // vector for the differences in between the samples; corresponds to array \f$ A_2 \f$ in the paper
+ size_type m_ones; // corresponds to N in the paper
+ size_type m_size; // corresponds to M in the paper
+ bit_vector m_contains_abs_sample; // vector which stores for every block of length t_sample_dens of the original bit_vector if an absolute sample lies in this block.
+ // Corresponds to array \f$ A_3 \f$ in the paper.
+ rank_support_v<> m_rank_contains_abs_sample; // rank support for m_contains_abs_sample. Corresponds to array \f$ A_4 \f$ in the paper.
+ // NOTE: A faster version should store the absolute samples and the differences interleaved
+
+ void copy(const nearest_neighbour_dictionary& nnd) {
+ // copy all members of the data structure
+ m_abs_samples = nnd.m_abs_samples;
+ m_differences = nnd.m_differences;
+ m_ones = nnd.m_ones;
+ m_size = nnd.m_size;
+ m_contains_abs_sample = nnd.m_contains_abs_sample;
+ m_rank_contains_abs_sample = nnd.m_rank_contains_abs_sample;
+ m_rank_contains_abs_sample.set_vector(&m_contains_abs_sample);
+ }
+
+ public:
+
+ //! Default constructor
+ nearest_neighbour_dictionary():m_ones(0),m_size(0) { }
+
+ //! Constructor
+ /*! \param v The supported bit_vector.
+ */
+ nearest_neighbour_dictionary(const bit_vector& v):m_ones(0), m_size(0) {
+ size_type max_distance_between_two_ones = 0;
+ size_type ones = 0; // counter for the ones in v
+
+ // get maximal distance between to ones in the bit vector
+ // speed this up by broadword computing
+ for (size_type i=0, last_one_pos_plus_1=0; i < v.size(); ++i) {
+ if (v[i]) {
+ if (i+1-last_one_pos_plus_1 > max_distance_between_two_ones)
+ max_distance_between_two_ones = i+1-last_one_pos_plus_1;
+ last_one_pos_plus_1 = i+1;
+ ++ones;
+
+ }
+ }
+ m_ones = ones;
+ m_size = v.size();
+// std::cerr<<ones<<std::endl;
+ // initialize absolute samples m_abs_samples[0]=0
+ m_abs_samples = int_vector<>(m_ones/t_sample_dens + 1, 0, bits::hi(v.size())+1);
+ // initialize different values
+ m_differences = int_vector<>(m_ones - m_ones/t_sample_dens, 0, bits::hi(max_distance_between_two_ones)+1);
+ // initialize m_contains_abs_sample
+ m_contains_abs_sample = bit_vector((v.size()+t_sample_dens-1)/t_sample_dens, 0);
+ ones = 0;
+ for (size_type i=0, last_one_pos=0; i < v.size(); ++i) {
+ if (v[i]) {
+ ++ones;
+ if ((ones % t_sample_dens) == 0) { // insert absolute samples
+ m_abs_samples[ones/t_sample_dens] = i;
+ m_contains_abs_sample[i/t_sample_dens] = 1;
+ } else {
+ m_differences[ones - ones/t_sample_dens - 1] = i - last_one_pos;
+ }
+ last_one_pos = i;
+ }
+ }
+ util::init_support(m_rank_contains_abs_sample, &m_contains_abs_sample);
+ }
+
+ //! Copy constructor
+ nearest_neighbour_dictionary(const nearest_neighbour_dictionary& nnd) {
+ // copy all members of the data structure
+ copy(nnd);
+ }
+
+ //! Move constructor
+ nearest_neighbour_dictionary(nearest_neighbour_dictionary&& nnd) {
+ *this = std::move(nnd);
+ }
+
+ //! Destructor
+ ~nearest_neighbour_dictionary() {}
+
+ nearest_neighbour_dictionary& operator=(const nearest_neighbour_dictionary& nnd) {
+ if (this != &nnd) {
+ copy(nnd);
+ }
+ return *this;
+ }
+
+ nearest_neighbour_dictionary& operator=(nearest_neighbour_dictionary&& nnd) {
+ if (this != &nnd) {
+ m_abs_samples = std::move(nnd.m_abs_samples);
+ m_differences = std::move(nnd.m_differences);
+ m_ones = std::move(nnd.m_ones);
+ m_size = std::move(nnd.m_size);
+ m_contains_abs_sample = std::move(nnd.m_contains_abs_sample);
+ m_rank_contains_abs_sample = std::move(nnd.m_rank_contains_abs_sample);
+ m_rank_contains_abs_sample.set_vector(&m_contains_abs_sample);
+ }
+ return *this;
+ }
+
+ void swap(nearest_neighbour_dictionary& nnd) {
+ // copy all members of the data structure
+ m_abs_samples.swap(nnd.m_abs_samples);
+ m_differences.swap(nnd.m_differences);
+ std::swap(m_ones, nnd.m_ones);
+ std::swap(m_size, nnd.m_size);
+ m_contains_abs_sample.swap(nnd.m_contains_abs_sample);
+ util::swap_support(m_rank_contains_abs_sample, nnd.m_rank_contains_abs_sample,
+ &m_contains_abs_sample, &(nnd.m_contains_abs_sample));
+ }
+
+ //! Answers rank queries for the supported bit_vector
+ /*! \param idx Argument for the length of the prefix v[0..idx-1].
+ * \return Number of 1-bits in the prefix [0..idx-1] of the supported bit_vector.
+ * \par Time complexity \f$ \Order{1} \f$
+ */
+ size_type rank(size_type idx)const {
+ assert(idx <= m_size);
+ size_type r = m_rank_contains_abs_sample.rank(idx/t_sample_dens); //
+ size_type result = r*t_sample_dens;
+ size_type i = m_abs_samples[r];
+ while (++result <= m_ones) {
+ if ((result % t_sample_dens) == 0) {
+ i = m_abs_samples[result/t_sample_dens];
+ } else {
+ i = i+m_differences[result - result/t_sample_dens-1];
+ }
+ if (i >= idx)
+ return result-1;
+ }
+ return result-1;
+ };
+
+ //! Answers select queries for the supported bit_vector
+ /*! \param i Select the \f$i\f$th 1 in the supported bit_vector. \f$i\in [1..ones()]\f$
+ * \return The position of the \f$i\f$th 1 in the supported bit_vector.
+ * \par Time complexity \f$ \Order{1} \f$
+ */
+ size_type select(size_type i)const {
+ assert(i > 0 and i <= m_ones);
+ size_type j = i/t_sample_dens;
+ size_type result = m_abs_samples[j];
+ j = j*t_sample_dens - j;
+ for (size_type end = j + (i%t_sample_dens); j < end; ++j) {
+ result += m_differences[j];
+ }
+ return result;
+ }
+
+ //! Answers "previous occurence of one" queries for the supported bit_vector.
+ /*! \param i Position \f$ i \in [0..size()-1] \f$.
+ * \return The maximal position \f$j \leq i\f$ where the supported bit_vector v equals 1.
+ * \pre rank(i+1)>0
+ * \par Time complexity \f$ \Order{1} \f$
+ */
+ size_type prev(size_type i)const {
+ size_type r = rank(i+1);
+ assert(r>0);
+ return select(r);
+ }
+ /*! Answers "next occurence of one" queries for the supported bit_vector.
+ * \param i Position \f$ i \in [0..size()-1] \f$.
+ * \return The minimal position \f$ j \geq i \f$ where the supported bit_vector v equals 1.
+ * \pre rank(i) < ones()
+ * \par Time complexity \f$ \Order{1} \f$
+ */
+ size_type next(size_type i)const {
+ size_type r = rank(i);
+ assert(r < m_ones);
+ return select(r+1);
+ }
+
+ size_type size()const {
+ return m_size;
+ }
+
+ size_type ones()const {
+ return m_ones;
+ }
+
+ //! Serializes the nearest_neighbour_dictionary.
+ /*! \param out Out-Stream to serialize the data to.
+ */
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ size_type written_bytes = 0;
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ written_bytes += m_abs_samples.serialize(out, child, "absolute_samples");
+ written_bytes += m_differences.serialize(out, child, "differences");
+ written_bytes += write_member(m_ones, out, child, "ones");
+ written_bytes += write_member(m_size,out, child, "size");
+ written_bytes += m_contains_abs_sample.serialize(out, child, "contains_abs_sample");
+ written_bytes += m_rank_contains_abs_sample.serialize(out, child, "rank_contains_abs_sample");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the nearest_neighbour_dictionary.
+ /*! \param in In-Stream to load the rank_support data from.
+ */
+ void load(std::istream& in) {
+ m_abs_samples.load(in);
+ m_differences.load(in);
+ read_member(m_ones, in);
+ read_member(m_size, in);
+ m_contains_abs_sample.load(in);
+ m_rank_contains_abs_sample.load(in, &m_contains_abs_sample);
+ }
+};
+
+
+}// end namespace sdsl
+
+
+#endif // end file
diff --git a/include/sdsl/nn_dict_dynamic.hpp b/include/sdsl/nn_dict_dynamic.hpp
new file mode 100644
index 0000000..ffabb5a
--- /dev/null
+++ b/include/sdsl/nn_dict_dynamic.hpp
@@ -0,0 +1,363 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011 Timo Beller, Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file nn_dict_dynamic.hpp
+ \brief nn_dict_dynamic.hpp contains a class for a dynamic bit vector which also supports the prev and next operations
+ \author Timo Beller, Simon Gog
+*/
+
+#ifndef INCLUDED_NN_DICT_DYNAMIC
+#define INCLUDED_NN_DICT_DYNAMIC
+
+#include <sdsl/int_vector.hpp>
+#include <sdsl/util.hpp>
+
+namespace sdsl
+{
+
+class nn_dict_dynamic; // forward declaration
+
+namespace util
+{
+void set_zero_bits(nn_dict_dynamic& nn);
+}
+
+
+// possible TODO: resize(size_type size)
+
+//! A class for a dynamic bit vector which also supports the prev and next operations
+class nn_dict_dynamic
+{
+ public:
+ typedef int_vector<64>::size_type size_type;
+ class reference; // forward declaration of inner class
+
+ friend class reference;
+ friend void util::set_zero_bits(nn_dict_dynamic& nn);
+ private:
+ uint64_t m_depth; // Depth of the tree (1 level corresonds to 0, 2 levels corresponds to 1,...)
+ uint64_t m_v_begin_leaves; // Virtual begin of leaves
+ size_type m_size;
+ int_vector<64> m_offset; // Number of nodes to skip on each level
+ int_vector<64> m_tree; // Tree
+
+ void copy(const nn_dict_dynamic& nn) {
+ m_depth = nn.m_depth;
+ m_v_begin_leaves = nn.m_v_begin_leaves;
+ m_size = nn.m_size;
+ m_offset = nn.m_offset;
+ m_tree = nn.m_tree;
+ }
+
+ public:
+
+ const uint64_t& depth;
+
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Constructor
+ /*! \param n Number of supported bits
+ */
+ nn_dict_dynamic(const uint64_t n = 0):depth(m_depth) {
+ m_size = n;
+ if (n == 0)
+ return;
+ uint64_t level; // level indicator
+ uint64_t nodes = 1; // number of nodes (=64 bit integer)
+ uint64_t tmp; // tmp-variable
+
+ /* Calc depth and begin of leaves */
+ m_depth = bits::hi(n)/6; // if, n>0 calculate \f$ \lfloor log_64(n) \rfloor \f$
+ m_v_begin_leaves = (1ULL<<(m_depth*6))/63;
+
+ /* Calc how many nodes to skip on each level */
+ m_offset = int_vector<64>(m_depth+2, 0);
+ level = m_depth;
+ tmp = n;
+ while (level) {
+ tmp = (tmp+63)/64; // get real number of nodes, of the next higher level
+ // <number of nodes in the full tree> - <real number of nodes>
+ m_offset[level+1] = (1ULL<<(6*level)) - tmp;
+ nodes += tmp;
+ --level;
+ }
+
+ /* Calc how many nodes to skip up to each level*/
+ for (level = 1; level <= m_depth; ++level) {
+ m_offset[level] += m_offset[level-1];
+ }
+
+ /* Create Tree incl. leaves */
+ m_tree = int_vector<64>(nodes);
+ }
+
+ //! Copy constructor
+ nn_dict_dynamic(const nn_dict_dynamic& nn):depth(m_depth) {
+ copy(nn);
+ }
+
+ //! move constructor
+ nn_dict_dynamic(nn_dict_dynamic&& nn):depth(m_depth) {
+ *this = std::move(nn);
+ }
+
+ //! Assignment operator
+ nn_dict_dynamic& operator=(const nn_dict_dynamic& nn) {
+ if (this != &nn) {
+ copy(nn);
+ }
+ return *this;
+ }
+
+ //! Assignment move operator
+ nn_dict_dynamic& operator=(nn_dict_dynamic&& nn) {
+ if (this != &nn) {
+ m_depth = std::move(nn.m_depth);
+ m_v_begin_leaves = std::move(nn.m_v_begin_leaves);
+ m_size = std::move(nn.m_size);
+ m_offset = std::move(nn.m_offset);
+ m_tree = std::move(nn.m_tree);
+ // set nn to default-constructor state
+ nn.m_size = 0;
+ nn.m_depth = 0;
+ nn.m_v_begin_leaves = 0;
+ }
+ return *this;
+ }
+
+ void swap(nn_dict_dynamic& nn) {
+ if (this != &nn) {
+ std::swap(m_depth, nn.m_depth);
+ std::swap(m_v_begin_leaves, nn.m_v_begin_leaves);
+ std::swap(m_size, nn.m_size);
+ m_offset.swap(nn.m_offset);
+ m_tree.swap(nn.m_tree);
+ }
+ }
+
+ //! Access the bit at index idx
+ /*! \param idx Index
+ * \par Precondition
+ * \f$ 0 \leq idx < size() \f$
+ */
+ bool operator[](const size_type& idx)const {
+ uint64_t node = m_tree[(m_v_begin_leaves + (idx>>6)) - m_offset[m_depth] ];
+ return (node >> (idx&0x3F)) & 1;
+ }
+
+ inline reference operator[](const size_type& idx) {
+ return reference(this, idx);
+ }
+
+
+ //! Get the leftmost index \f$i\geq idx\f$ where a bit is set.
+ /*! \param idx Left border of the search interval. \f$ 0\leq idx < size()\f$
+ *
+ * \return If there exists a leftmost index \f$i\geq idx\f$ where a bit is set,
+ * then \f$i\f$ is returned, otherwise size().
+ */
+ size_type next(const size_type idx)const {
+ uint64_t v_node_position; // virtual node position
+ uint64_t node; // current node
+ uint64_t depth = m_depth; // current depth of node
+ uint64_t position; // position of the 1-bit
+
+ v_node_position = m_v_begin_leaves + (idx>>6);
+ uint8_t off = idx & 0x3F; // mod 64
+
+ // Go up until a 1-bit is found
+ node = m_tree[ v_node_position-m_offset[depth] ]>>off;
+ while (!node or off==64) {
+ // Not in the root
+ if (v_node_position) {
+ --depth;
+ --v_node_position;
+ off = (v_node_position&0x3F)+1;
+ v_node_position >>= 6;
+ node = m_tree[ v_node_position-m_offset[depth] ]>>off;
+ } else {
+ return size();
+ }
+ }
+ // Calculate the position of the 1-bit
+ position = bits::lo(node)+off;
+
+ // Go down to the leaf
+ while (v_node_position < m_v_begin_leaves) {
+ ++depth;
+ v_node_position = (v_node_position<<6) + 1 + position;
+ node = m_tree[ v_node_position-m_offset[depth] ];
+
+ // Calculate the position of the 1-bit
+ position = bits::lo(node);
+ }
+ return ((v_node_position - m_v_begin_leaves)<<6) + position;
+ }
+
+ //! Get the rightmost index \f$i \leq idx\f$ where a bit is set.
+ /*! \param idx Right border of the search interval. \f$ 0 \leq idx < size()\f$
+ *
+ * \return If there exists a rightmost index \f$i \leq idx\f$ where a bit is set,
+ * then \f$i\f$ is returned, otherwise size().
+ */
+ size_type prev(const size_type idx)const {
+ uint64_t v_node_position; // virtual node position
+ uint64_t node; // current node
+ uint64_t depth = m_depth; // current depth of node
+ uint64_t position; // position of the 1-bit
+
+ v_node_position = m_v_begin_leaves + (idx>>6);
+ uint8_t off = idx & 0x3F; // mod 64
+
+ // Go up until a 1-bit is found
+ node = m_tree[ v_node_position-m_offset[depth] ]<<(63-off);
+ while (!node or off == (uint8_t)-1) {
+
+ // Not in the root
+ if (v_node_position) {
+ --depth;
+ --v_node_position;
+
+ off = ((uint8_t)(v_node_position&0x3F))-1;
+ v_node_position >>= 6;
+
+ node = m_tree[ v_node_position-m_offset[depth] ]<<(63-off);
+ } else {
+ return size();
+ }
+ }
+ // Calculate the position of the 1-bit
+ position = bits::hi(node)-(63-off);
+
+ // Go down to the leaf
+ while (v_node_position < m_v_begin_leaves) {
+ ++depth;
+ v_node_position = (v_node_position<<6) + 1 + position;
+ node = m_tree[ v_node_position-m_offset[depth] ];
+
+ // Calculate the position of the 1-bit
+ position = bits::hi(node); //-(63-off)
+ }
+ return ((v_node_position - m_v_begin_leaves)<<6) + position;
+ }
+
+
+ //! Load the data structure
+ void load(std::istream& in) {
+ read_member(m_depth, in);
+ read_member(m_v_begin_leaves, in);
+ read_member(m_size, in);
+ m_offset.load(in);
+ m_tree.load(in);
+ }
+
+ //! Serialize the data structure
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_depth, out, child, "depth");
+ written_bytes += write_member(m_v_begin_leaves, out, child, "v_begin_leaves");
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += m_offset.serialize(out, child, "offset");
+ written_bytes += m_tree.serialize(out, child, "tree");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ class reference
+ {
+ private:
+ nn_dict_dynamic* m_pbv; // pointer to the bit_vector_nearest_neigbour
+ size_type m_idx; // virtual node position
+ public:
+ //! Constructor
+ reference(nn_dict_dynamic* pbv,
+ nn_dict_dynamic::size_type idx):m_pbv(pbv),m_idx(idx) {};
+
+ //! Assignment operator for the proxy class
+ reference& operator=(bool x) {
+ uint64_t v_node_position; // virtual node position
+ uint64_t r_node_position; // real node position
+ uint64_t depth = m_pbv->m_depth; // current depth of node
+
+ v_node_position = m_pbv->m_v_begin_leaves + (m_idx>>6);
+ uint8_t offset = m_idx & 0x3F; // pos mod 64
+ if (x) {
+ while (true) {
+ r_node_position = v_node_position - m_pbv->m_offset[depth];
+ uint64_t w = m_pbv->m_tree[r_node_position];
+ if ((w>>offset) & 1) { // if the bit was already set
+ return *this;
+ } else {
+ m_pbv->m_tree[r_node_position] |= (1ULL<<offset); // set bit
+ if (!w and depth) { // go up in the tree
+ --depth; --v_node_position;
+ offset = v_node_position&0x3F;
+ v_node_position >>= 6;
+ } else {
+ return *this;
+ }
+ }
+ }
+ } else {
+ while (true) {
+ r_node_position = v_node_position - m_pbv->m_offset[depth];
+ uint64_t w = m_pbv->m_tree[r_node_position];
+ if (!((w>>offset) & 1)) { // if the bit is already 0
+ return *this;
+ } else {
+ m_pbv->m_tree[r_node_position] &= (~(1ULL<<offset)); // unset bit
+ if (!m_pbv->m_tree[r_node_position] and depth) { // go up in the tree
+ --depth; --v_node_position;
+ offset = v_node_position&0x3F;
+ v_node_position >>= 6;
+ } else {
+ return *this;
+ }
+ }
+ }
+ }
+ return *this;
+ }
+
+ reference& operator=(const reference& x) {
+ return *this = bool(x);
+ }
+
+ //! Cast the reference to a bool
+ operator bool()const {
+ uint64_t node = m_pbv->m_tree[(m_pbv->m_v_begin_leaves + (m_idx>>6)) - m_pbv->m_offset[m_pbv->m_depth] ];
+ return (node >> (m_idx&0x3F)) & 1;
+ }
+
+ bool operator==(const reference& x)const {
+ return bool(*this) == bool(x);
+ }
+
+ bool operator<(const reference& x)const {
+ return !bool(*this) and bool(x);
+ }
+ };
+
+};
+
+
+
+} // end of namespace
+
+#endif // end file
diff --git a/include/sdsl/qsufsort.hpp b/include/sdsl/qsufsort.hpp
new file mode 100644
index 0000000..0091849
--- /dev/null
+++ b/include/sdsl/qsufsort.hpp
@@ -0,0 +1,512 @@
+/* qsufsort.c
+ Copyright 1999, N. Jesper Larsson, all rights reserved.
+
+ This file contains an implementation of the algorithm presented in "Faster
+ Suffix Sorting" by N. Jesper Larsson (jesper at cs.lth.se) and Kunihiko
+ Sadakane (sada at is.s.u-tokyo.ac.jp).
+
+ This software may be used freely for any purpose. However, when distributed,
+ the original source must be clearly stated, and, when the source code is
+ distributed, the copyright notice must be retained and any alterations in
+ the code must be clearly marked. No warranty is given regarding the quality
+ of this software.*/
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file qsufsort.hpp
+ \brief qsufsort.hpp contains the interface for the suffix array construction algorithm of Larsson.
+ Larssons code was downloaded from http://www.larsson.dogma.net/qsufsort.c and adapted to the
+ use of sdsl bitvectors.
+ \author Simon Gog
+*/
+
+#ifndef INCLUDED_SDSL_QSUFSORT
+#define INCLUDED_SDSL_QSUFSORT
+
+#define DBG_OUT if(0)std::cout
+
+#include <sdsl/int_vector.hpp>
+
+namespace sdsl
+{
+namespace qsufsort
+{
+
+template<class int_vector_type=int_vector<> >
+class sorter;
+
+//void sort(int_iter text, int_iter sa, int64_t n, int64_t k, int64_t l);
+
+//! Construct a suffix array for the sequence stored in a file.
+/*!
+ * \param sa A reference to the resulting suffix array.
+ * \param file Name of the file.
+ * \param num_bytes Bytes per symbol in the file. I.e.
+ * - num_bytes=1: byte sequence
+ * - num_bytes=2: sequence of two byte symbols
+ * - num_bytes=4: sequence of four byte symbols
+ * - num_bytes=8: sequence of eight byte symbols.
+ * - num_bytes=0: the algorithm assumes a serialized
+ * int_vector<> in the file and
+ * loads it.
+ * \par Note
+ * If `int_vector_type` is `int_vector<>` then the bit-width of `sa` is
+ * the maximum of `bits::hi( max(sa.size()-1, 0) )` and the
+ * bit-width of the text.
+ */
+// TODO: problem when int_width==64!!!
+template<class int_vector_type>
+void construct_sa(int_vector_type& sa, const char* file, uint8_t num_bytes)
+{
+ sorter<int_vector_type> s;
+ s.sort(sa, file, num_bytes);
+};
+
+template<class int_vector_type, class t_vec>
+void construct_sa(int_vector_type& sa, t_vec& text)
+{
+ sorter<int_vector_type> s;
+ s.sort(sa, text);
+};
+
+template<class int_vector_type>
+class sorter
+{
+ typedef int_vector_type tIV;
+ typedef typename tIV::iterator int_iter;
+ typedef typename tIV::size_type size_type;
+
+ private:
+
+ int_iter m_SA, // group array, ultimately suffix array.
+ m_VV; // inverse array, ultimately inverse of SA.
+ uint64_t m_rr, // number of symbols aggregated by transform.
+ m_hh; // length of already-sorted prefixes.
+ uint8_t m_msb; // most significant bit position starting from 0
+ uint64_t m_msb_mask;// mask for 1ULL<<msb
+
+ inline int64_t to_sign(uint64_t x)const {
+ return x & m_msb_mask ? -((int64_t)(x&~m_msb_mask)) : x;
+ }
+ // return the absolute value of integer x
+ inline int64_t mark_pos(uint64_t x)const {
+ return (x&~m_msb_mask);
+ }
+ // mark the number x as negative
+ inline int64_t mark_neg(uint64_t x)const {
+ return x|m_msb_mask;
+ }
+ // check if x is not negative
+ inline bool not_neg(uint64_t x)const {
+ return !(x>>m_msb);
+ }
+ // check if x is negative
+ inline bool is_neg(uint64_t x)const {
+ return x&m_msb_mask;
+ }
+ // returns the key of iterator p at the current sorting depth
+ inline uint64_t key(const int_iter& p)const {
+ return m_VV[*p+m_hh];
+ }
+ // swap the value of two iterators
+ inline void swap(int_iter& p, int_iter& q)const {
+ uint64_t tmp = *p; *p=*q; *q=tmp;
+ }
+ // select the median out of 3 elements
+ inline const int_iter& med3(const int_iter& a, const int_iter& b, const int_iter& c)const {
+ return key(a)<key(b)? (key(b)<key(c)?b:(key(a)<key(c)?c:a))
+ : (key(b)>key(c)?b:(key(a)>key(c)?c:a));
+ }
+
+ /* Subroutine for select_sort_split and sort_split. Sets group numbers for a
+ group whose lowest position in m_SA is pl and highest position is pm.*/
+ void update_group(int_iter pl, int_iter pm) {
+ int64_t g=pm-m_SA; /* group number.*/
+ m_VV[*pl]=g; /* update group number of first position.*/
+ if (pl==pm)
+ *pl=mark_neg(1); /* one element, sorted group.*/
+ else
+ do /* more than one element, unsorted group.*/
+ m_VV[*++pl]=g; /* update group numbers.*/
+ while (pl<pm);
+ }
+
+ /* Quadratic sorting method to use for small subarrays. To be able to update
+ group numbers consistently, a variant of selection sorting is used.*/
+ void select_sort_split(const int_iter& p, int64_t n) {
+ int_iter pa, pb, pi, pn;
+ uint64_t f, v;
+
+ pa=p; /* pa is start of group being picked out.*/
+ pn=p+n-1; /* pn is last position of subarray.*/
+ while (pa<pn) {
+ for (pi=pb=(pa+1), f=key(pa); pi<=pn; ++pi)
+ if ((v=key(pi))<f) {
+ f=v; /* f is smallest key found.*/
+ swap(pi, pa); /* place smallest element at beginning.*/
+ pb=pa+1; /* pb is position for elements equal to f.*/
+ } else if (v==f) { /* if equal to smallest key.*/
+ swap(pi, pb); /* place next to other smallest elements.*/
+ ++pb;
+ }
+ update_group(pa, pb-1); /* update group values for new group.*/
+ pa=pb; /* continue sorting rest of the subarray.*/
+ }
+ if (pa==pn) { /* check if last part is single element.*/
+ m_VV[*pa]=pa-m_SA;
+ *pa=mark_neg(1); /* sorted group.*/
+ }
+ }
+
+ /* Subroutine for sort_split, algorithm by Bentley & McIlroy.*/
+ uint64_t choose_pivot(const int_iter& p, int64_t n) {
+ int_iter pl, pm, pn;
+ int64_t s;
+
+ pm=p+(n>>1); /* small arrays, middle element.*/
+ if (n>7LL) {
+ pl=p;
+ pn=p+n-1;
+ if (n>40LL) { /* big arrays, pseudomedian of 9.*/
+ s=n>>3;
+ pl=med3(pl, pl+s, pl+s+s);
+ pm=med3(pm-s, pm, pm+s);
+ pn=med3(pn-s-s, pn-s, pn);
+ }
+ pm=med3(pl, pm, pn); /* midsize arrays, median of 3.*/
+ }
+ return key(pm);
+ }
+
+ /* Sorting routine called for each unsorted group. Sorts the array of integers
+ (suffix numbers) of length n starting at p. The algorithm is a ternary-split
+ quicksort taken from Bentley & McIlroy, "Engineering a Sort Function",
+ Software -- Practice and Experience 23(11), 1249-1265 (November 1993). This
+ function is based on Program 7.*/
+ void sort_split(const int_iter& p, int64_t n) {
+ int_iter pa, pb, pc, pd, pl, pm, pn;
+ uint64_t f, v;
+ int64_t s, t;
+
+ if (n<7) { /* multi-selection sort smallest arrays.*/
+ select_sort_split(p, n);
+ return;
+ }
+
+ v=choose_pivot(p, n);
+ pa=pb=p; // pa: iterator for equal elements
+ pc=pd=p+n-1; // pc = right border (inclusive)
+ while (1) { /* split-end partition.*/
+ while (pb<=pc && (f=key(pb))<=v) { // go to the right as long as there are keys smaller equal than v
+ if (f==v) {
+ swap(pa, pb); ++pa; // swap equal chars to the left
+ }
+ ++pb;
+ }
+ while (pc>=pb && (f=key(pc))>=v) { // go to the left as long as there are keys bigger or equal to v
+ if (f==v) {
+ swap(pc, pd); --pd; // swap equal chars to the right end
+ }
+ --pc;
+ }
+ if (pb>pc)
+ break;
+ swap(pb, pc); // swap element > v (pb) to the third part and element < v (pc) to the second
+ ++pb;
+ --pc;
+ }
+ pn=p+n;
+ if ((s=pa-p)>(t=pb-pa))
+ s=t;
+ for (pl=p, pm=pb-s; s; --s, ++pl, ++pm)
+ swap(pl, pm);
+ if ((s=pd-pc)>(t=pn-pd-1))
+ s=t;
+ for (pl=pb, pm=pn-s; s; --s, ++pl, ++pm)
+ swap(pl, pm);
+ s=pb-pa;
+ t=pd-pc;
+ if (pa > pb) {
+ if (s>0) {
+ std::cout<<"s="<<s<<">0 but should be <0; n="<<n<<std::endl;
+ }
+ }
+ if (pc > pd) {
+ if (t>0) {
+ std::cout<<"t="<<t<<">0 but should be <0; n="<<n<<std::endl;
+ }
+ }
+ if (s>0)
+ sort_split(p, s);
+ update_group(p+s, p+n-t-1);
+ if (t>0)
+ sort_split(p+n-t, t);
+ }
+
+ /* Bucketsort for first iteration.
+
+ Input: x[0...n-1] holds integers in the range 1...k-1, all of which appear
+ at least once. x[n] is 0. (This is the corresponding output of transform.) k
+ must be at most n+1. p is array of size n+1 whose contents are disregarded.
+
+ Output: x is m_VV and p is m_SA after the initial sorting stage of the refined
+ suffix sorting algorithm.*/
+ void bucketsort(const int_iter& x, const int_iter& p, int64_t n, int64_t k) {
+ int_iter pi;
+ int64_t i, d, g;
+ uint64_t c;
+
+ for (pi=p; pi<p+k; ++pi)
+ *pi=mark_neg(1); /* mark linked lists empty.*/
+ for (i=0; i<=n; ++i) {
+ x[i]=p[c=x[i]]; /* insert in linked list.*/
+ p[c]=i;
+ }
+ for (pi=p+k-1, i=n; pi>=p; --pi) {
+ d=x[c=*pi]; /* c is position, d is next in list.*/
+ x[c]=g=i; /* last position equals group number.*/
+ if (not_neg(d)) { /* if more than one element in group.*/
+ p[i--]=c; /* p is permutation for the sorted x.*/
+ do {
+ d=x[c=d]; /* next in linked list.*/
+ x[c]=g; /* group number in x.*/
+ p[i--]=c; /* permutation in p.*/
+ } while (not_neg(d));
+ } else
+ p[i--]=mark_neg(1); /* one element, sorted group.*/
+ }
+ }
+
+ public:
+
+ /* Transforms the alphabet of x by attempting to aggregate several symbols into
+ one, while preserving the suffix order of x. The alphabet may also be
+ compacted, so that x on output comprises all integers of the new alphabet
+ with no skipped numbers.
+
+ Input: x is an array of size n+1 whose first n elements are positive
+ integers in the range l...k-1. p is array of size n+1, used for temporary
+ storage. q controls aggregation and compaction by defining the maximum value
+ for any symbol during transformation: q must be at least k-l; if q<=n,
+ compaction is guaranteed; if k-l>n, compaction is never done; if q is
+ INT_MAX, the maximum number of symbols are aggregated into one.
+
+ Output: Returns an integer j in the range 1...q representing the size of the
+ new alphabet. If j<=n+1, the alphabet is compacted. The global variable r is
+ set to the number of old symbols grouped into one. Only x[n] is 0.*/
+
+ int64_t transform(const int_iter& x, const int_iter& p, int64_t n, int64_t k, int64_t l, int64_t q) {
+ if (!(q >= k-l)) {
+ std::cout << "q="<<q<<" k-l="<<k-l<<std::endl;
+ }
+ assert(q >= k-l);
+ DBG_OUT<<"transform(n="<<n<<", k="<<k<<", l="<<l<<", q="<<q<<")"<<std::endl;
+ uint64_t bb, cc,dd;
+ int64_t jj;
+ int_iter pi, pj;
+ int s = bits::hi(k-l)+(k>l); /* s is number of bits in old symbol.*/
+ uint8_t len = 0; /* len is for overflow checking.*/
+ m_rr = 0;
+ for (bb=dd=0; (int)m_rr<n && (int)len < m_msb+1-s && (int64_t)(cc=dd<<s|(k-l)) <= q; ++m_rr, len+=s) {
+ bb=bb<<s|(x[m_rr]-l+1); /* bb is start of x in chunk alphabet.*/
+ dd=cc; /* dd is max symbol in chunk alphabet.*/
+ }
+ DBG_OUT<<"m_rr="<<m_rr<<std::endl;
+ uint64_t mm=(1ULL<<(m_rr-1)*s)-1; /* mm masks off top old symbol from chunk.*/
+ x[n]=l-1; /* emulate zero terminator.*/
+ if ((int64_t)dd <= n) { /* if bucketing possible, compact alphabet.*/
+ for (pi=p; pi<=p+dd; ++pi)
+ *pi=0; /* zero transformation table.*/
+ for (pi=x+m_rr, cc=bb; pi<=x+n; ++pi) {
+ p[cc]=1; /* mark used chunk symbol.*/
+ cc=(cc&mm)<<s|(*pi-l+1); /* shift in next old symbol in chunk.*/
+ }
+ for (uint64_t i=1; i<m_rr; ++i) { /* handle last r-1 positions.*/
+ p[cc]=1; /* mark used chunk symbol.*/
+ cc=(cc&mm)<<s; /* shift in next old symbol in chunk.*/
+ }
+ for (pi=p, jj=1; pi<=p+dd; ++pi)
+ if (*pi)
+ *pi=jj++; /* j is new alphabet size.*/
+ for (pi=x, pj=x+m_rr, cc=bb; pj<=x+n; ++pi, ++pj) {
+ *pi=p[cc]; /* transform to new alphabet.*/
+ cc=(cc&mm)<<s|(*pj-l+1); /* shift in next old symbol in chunk.*/
+ }
+ while (pi<x+n) { /* handle last r-1 positions.*/
+ *pi++=p[cc]; /* transform to new alphabet.*/
+ cc=(cc&mm)<<s; /* shift right-end zero in chunk.*/
+ }
+ } else { /* bucketing not possible, don't compact.*/
+ for (pi=x, pj=x+m_rr, cc=bb; pj<=x+n; ++pi, ++pj) {
+ *pi=cc; /* transform to new alphabet.*/
+ cc=(cc&mm)<<s|(*pj-l+1); /* shift in next old symbol in chunk.*/
+ }
+ while (pi<x+n) { /* handle last r-1 positions.*/
+ *pi++=cc; /* transform to new alphabet.*/
+ cc=(cc&mm)<<s; /* shift right-end zero in chunk.*/
+ }
+ jj=dd+1; /* new alphabet size.*/
+ }
+ x[n]=0; /* end-of-string symbol is zero.*/
+ DBG_OUT<<"end transformation jj="<<jj<<std::endl;
+ return jj; /* return new alphabet size.*/
+ }
+
+ /* Makes suffix array p of x. x becomes inverse of p. p and x are both of size
+ n+1. Contents of x[0...n-1] are integers in the range l...k-1. Original
+ contents of x[n] is disregarded, the n-th symbol being regarded as
+ end-of-string smaller than all other symbols.*/
+ void sort(const int_iter& x, const int_iter& p, int64_t n, int64_t k, int64_t l) {
+ int_iter pi, pk;
+ m_VV=x; /* set global values.*/
+ m_SA=p;
+ if (n>=k-l) { /* if bucketing possible,*/
+ int64_t j = transform(m_VV, m_SA, n, k, l, n);
+ DBG_OUT<<"begin bucketsort j="<<j<<std::endl;
+ bucketsort(m_VV, m_SA, n, j); /* bucketsort on first r positions.*/
+ DBG_OUT<<"end bucketsort"<<std::endl;
+ } else {
+ transform(m_VV, m_SA, n, k, l, m_msb_mask-1);
+ DBG_OUT<<"initialize SA begin"<<std::endl;
+ for (int64_t i=0; i<=n; ++i)
+ m_SA[i]=i; /* initialize I with suffix numbers.*/
+ DBG_OUT<<"initialize SA end"<<std::endl;
+ m_hh=0;
+ sort_split(m_SA, n+1); /* quicksort on first r positions.*/
+ }
+ m_hh=m_rr; /* number of symbols aggregated by transform.*/
+// while ( is_neg(*m_SA) and mark_pos(*m_SA) <= n) {
+ while (to_sign(*m_SA) >= -n) {
+//std::cout<<"m_hh="<<m_hh<<std::endl;
+ DBG_OUT<<"SA = ";
+//for(size_t iii=0; iii<=(size_t)n; ++iii){
+// uint64_t D = *(m_SA+iii);
+// printf("%c%lld ", is_neg(D)?'-':' ', mark_pos(D));
+//}
+ DBG_OUT<<std::endl;
+ DBG_OUT<<"TEXT = ";
+//for(size_t iii=0; iii<=(size_t)n; ++iii){
+// uint64_t D = *(m_VV+iii);
+// printf("%c%lld ", is_neg(D)?'-':' ', mark_pos(D));
+//}
+ DBG_OUT<<std::endl;
+ DBG_OUT<<"*m_SA="<< to_sign(*m_SA) <<std::endl;
+//std::cout<<"mark_pos(*m_SA)="<<mark_pos(*m_SA)<<std::endl;
+ pi=m_SA; /* pi is first position of group.*/
+ int64_t sl=0; /* sl is length of sorted groups.*/
+ DBG_OUT<<"m_hh="<<m_hh<<std::endl;
+ do {
+ uint64_t s = *pi;
+ if (to_sign(s) < (int64_t)0) {
+ pi += mark_pos(s); /* skip over sorted group.*/
+ sl += mark_pos(s); /* add length to sl.*/
+ } else {
+ if (sl) {
+ *(pi-sl)=mark_neg(sl); /* combine sorted groups before pi.*/
+ sl=0;
+ }
+ pk=m_SA+m_VV[s]+1; /* pk-1 is last position of unsorted group.*/
+ sort_split(pi, pk-pi);
+ pi=pk; /* next group.*/
+ }
+ } while ((pi-m_SA) <= n);
+ if (sl) /* if the array ends with a sorted group.*/
+ *(pi-sl)=mark_neg(sl); /* combine sorted groups at end of m_SA.*/
+ m_hh=2*m_hh; /* double sorted-depth.*/
+ DBG_OUT<<"m_hh="<<m_hh<<std::endl;
+ }
+ for (int64_t i=0; i<=n; ++i) { /* reconstruct suffix array from inverse.*/
+ m_SA[m_VV[i]]=i;
+ }
+ }
+
+ void do_sort(tIV& sa, tIV& x) {
+ assert(x.size()>0);
+ DBG_OUT<<"x.width()="<< (int)x.width() <<std::endl;
+ DBG_OUT<<"x.size()="<<x.size()<<std::endl;
+ DBG_OUT<<"sa.width()="<<(int)sa.width()<<std::endl;
+ DBG_OUT<<"sa.size()="<<sa.size()<<std::endl;
+ if (x.size() == 1) {
+ sa = tIV(1, 0);
+ return;
+ }
+
+ int64_t max_symbol = 0, min_symbol = x.width() < 64 ? bits::lo_set[x.width()] : 0x7FFFFFFFFFFFFFFFLL;
+
+ for (size_type i=0; i < x.size()-1; ++i) {
+ max_symbol = std::max(max_symbol, (int64_t)x[i]);
+ min_symbol = std::min(min_symbol, (int64_t)x[i]);
+ }
+
+ if (0 == min_symbol) {
+ throw std::logic_error("Text contains 0-symbol. Suffix array can not be constructed.");
+ }
+ if (x[x.size()-1] > 0) {
+ throw std::logic_error("Last symbol is not 0-symbol. Suffix array can not be constructed.");
+ }
+ DBG_OUT<<"sorter: min_symbol="<<min_symbol<<std::endl;
+ DBG_OUT<<"sorter: max_symbol="<<max_symbol<<std::endl;
+
+ int64_t n = x.size()-1;
+ DBG_OUT<<"x.size()-1="<<x.size()-1<<" n="<<n<<std::endl;
+ uint8_t width = std::max(bits::hi(max_symbol)+2, bits::hi(n+1)+2);
+ DBG_OUT<<"sorter: width="<<(int)width<<" max_symbol_width="<<bits::hi(max_symbol)+1<<" n_width="<< bits::hi(n) <<std::endl;
+ util::expand_width(x, width);
+ sa = x;
+ if (sa.width() < x.width()) {
+ throw std::logic_error("Fixed size suffix array is to small for the specified text.");
+ return;
+ }
+
+ m_msb = sa.width()-1;
+ m_msb_mask = 1ULL<<m_msb;
+ DBG_OUT<<"sorter: m_msb="<< (int)m_msb <<" m_msb_mask="<<m_msb_mask<<std::endl;
+ sort(x.begin(), sa.begin(), x.size()-1, max_symbol+1, min_symbol);
+ }
+
+
+ void sort(tIV& sa, const char* file_name, uint8_t num_bytes) {
+ DBG_OUT<<"sorter: sort("<<file_name<<")"<<std::endl;
+ DBG_OUT<<"sizeof(int_vector<>::difference_type)="<<sizeof(int_vector<>::difference_type)<<std::endl;
+ util::clear(sa); // free space for sa
+ tIV x;
+ if (num_bytes == 0 and typeid(typename tIV::reference) == typeid(uint64_t)) {
+ DBG_OUT<<"sorter: use int_vector<64>"<<std::endl;
+ int_vector<> temp;
+ load_vector_from_file(temp, file_name, num_bytes);
+ x.resize(temp.size());
+ for (size_type i=0; i<temp.size(); ++i) x[i] = temp[i];
+ } else {
+ load_vector_from_file(x, file_name, num_bytes);
+ util::bit_compress(x);
+ }
+ do_sort(sa, x);
+ }
+
+ template<class t_vec>
+ void sort(tIV& sa, t_vec& text) {
+ tIV x;
+ x.resize(text.size());
+ for (size_type i=0; i<text.size(); ++i) x[i] = text[i];
+ do_sort(sa, x);
+ }
+};
+
+} // end namespace qsufsort
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/ram_filebuf.hpp b/include/sdsl/ram_filebuf.hpp
new file mode 100644
index 0000000..cae92fc
--- /dev/null
+++ b/include/sdsl/ram_filebuf.hpp
@@ -0,0 +1,56 @@
+#ifndef INCLUDED_SDSL_RAM_FSTREAMBUF
+#define INCLUDED_SDSL_RAM_FSTREAMBUF
+
+#include <fstream>
+#include <vector>
+#include "ram_fs.hpp"
+
+namespace sdsl
+{
+
+class ram_filebuf : public std::streambuf
+{
+ private:
+ ram_fs::content_type* m_ram_file = nullptr; // file handle
+ void pbump64(std::ptrdiff_t);
+
+ public:
+ virtual ~ram_filebuf();
+
+ ram_filebuf();
+ ram_filebuf(std::vector<char>& ram_file);
+
+ std::streambuf*
+ open(const std::string s, std::ios_base::openmode mode);
+
+ bool is_open();
+
+ ram_filebuf*
+ close();
+
+ pos_type
+ seekpos(pos_type sp,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
+
+ pos_type
+ pubseekoff(off_type off, std::ios_base::seekdir way,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
+
+ pos_type
+ pubseekpos(pos_type sp,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
+
+
+// std::streamsize
+// xsputn(const char_type* s, std::streamsize n) override;
+
+ int
+ sync() override;
+
+ int_type
+ overflow(int_type c = traits_type::eof()) override;
+};
+
+}
+
+#endif
diff --git a/include/sdsl/ram_fs.hpp b/include/sdsl/ram_fs.hpp
new file mode 100644
index 0000000..1f3d4ac
--- /dev/null
+++ b/include/sdsl/ram_fs.hpp
@@ -0,0 +1,81 @@
+/*! \file ram_fs.hpp
+ * \brief ram_fs.hpp
+ * \author Simon Gog
+ */
+#ifndef INCLUDED_SDSL_RAM_FS
+#define INCLUDED_SDSL_RAM_FS
+
+#include "uintx_t.hpp"
+#include <string>
+#include <map>
+#include <vector>
+#include <mutex>
+
+namespace sdsl
+{
+
+class ram_fs_initializer
+{
+ public:
+ ram_fs_initializer();
+ ~ram_fs_initializer();
+};
+
+} // end namespace sdsl
+
+
+static sdsl::ram_fs_initializer init_ram_fs;
+
+namespace sdsl
+{
+
+
+//! ram_fs is a simple store for RAM-files.
+/*!
+ * Simple key-value store which maps file names
+ * (strings) to file content (content_type).
+ */
+class ram_fs
+{
+ public:
+ typedef std::vector<char> content_type;
+
+ private:
+ friend class ram_fs_initializer;
+ typedef std::map<std::string, content_type> mss_type;
+ static mss_type m_map;
+ static std::recursive_mutex m_rlock;
+
+ public:
+ //! Default construct
+ ram_fs();
+ static void store(const std::string& name, content_type data);
+ //! Check if the file exists
+ static bool exists(const std::string& name);
+ //! Get the file size
+ static size_t file_size(const std::string& name);
+ //! Get the content
+ static content_type& content(const std::string& name);
+ //! Remove the file with key `name`
+ static int remove(const std::string& name);
+ //! Rename the file. Change key `old_filename` into `new_filename`.
+ static int rename(const std::string old_filename, const std::string new_filename);
+};
+
+//! Determines if the given file is a RAM-file.
+bool is_ram_file(const std::string& file);
+
+//! Returns the corresponding RAM-file name for file.
+std::string ram_file_name(const std::string& file);
+
+//! Returns for a RAM-file the corresponding disk file name
+std::string disk_file_name(const std::string& file);
+
+//! Remove a file.
+int remove(const std::string& file);
+
+//! Rename a file
+int rename(const std::string& old_filename, const std::string& new_filename);
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/rank_support.hpp b/include/sdsl/rank_support.hpp
new file mode 100644
index 0000000..4e620ab
--- /dev/null
+++ b/include/sdsl/rank_support.hpp
@@ -0,0 +1,208 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rank_support.hpp
+ \brief rank_support.hpp contains classes that support a sdsl::bit_vector with constant time rank information.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RANK_SUPPORT
+#define INCLUDED_SDSL_RANK_SUPPORT
+
+/** \defgroup rank_support_group Rank Support (RS)
+ * This group contains data structures which support an sdsl::bit_vector with the rank method.
+ */
+
+#include "int_vector.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! The base class of classes supporting rank_queries for a sdsl::bit_vector in constant time.
+/*!
+*/
+class rank_support
+{
+ protected:
+ const bit_vector* m_v; //!< Pointer to the rank supported bit_vector
+ public:
+ typedef bit_vector::size_type size_type;
+
+ //! Constructor
+ /*! \param v The supported bit_vector.
+ */
+ rank_support(const bit_vector* v = nullptr);
+ //! Copy constructor
+ rank_support(const rank_support&) = default;
+ rank_support(rank_support&&) = default;
+ rank_support& operator=(const rank_support&) = default;
+ rank_support& operator=(rank_support&&) = default;
+ //! Destructor
+ virtual ~rank_support() {}
+
+ //! Answers rank queries for the supported bit_vector.
+ /*! \param i Argument for the length of the prefix v[0..i-1].
+ \returns Number of 1-bits in the prefix [0..i-1] of the supported bit_vector.
+ \note Method init has to be called before the first call of rank.
+ \sa init
+ */
+ virtual size_type rank(size_type i) const = 0;
+ //! Alias for rank(i)
+ virtual size_type operator()(size_type idx) const = 0;
+ //! Serializes rank_support.
+ /*! \param out Out-Stream to serialize the data to.
+ */
+ virtual size_type serialize(std::ostream& out, structure_tree_node* v, std::string name)const = 0;
+ //! Loads the rank_support.
+ /*! \param in In-Stream to load the rank_support data from.
+ \param v The supported bit_vector.
+ */
+ virtual void load(std::istream& in, const bit_vector* v=nullptr) = 0;
+ //! Sets the supported bit_vector to the given pointer.
+ /*! \param v The new bit_vector to support.
+ * \note Method init has to be called before the next call of rank.
+ * \sa init, rank
+ */
+ virtual void set_vector(const bit_vector* v=nullptr) = 0;
+};
+
+inline rank_support::rank_support(const bit_vector* v)
+{
+ m_v = v;
+}
+
+//----------------------------------------------------------------------
+
+template<uint8_t bit_pattern, uint8_t pattern_len>
+struct rank_support_trait {
+ typedef rank_support::size_type size_type;
+
+ static size_type args_in_the_word(uint64_t, uint64_t&) {
+ return 0;
+ }
+
+ static uint32_t word_rank(const uint64_t*, size_type) {
+ return 0;
+ }
+
+ static uint32_t full_word_rank(const uint64_t*, size_type) {
+ return 0;
+ }
+
+ static uint64_t init_carry() {
+ return 0;
+ }
+};
+
+template<>
+struct rank_support_trait<0,1> {
+ typedef rank_support::size_type size_type;
+
+ static size_type args_in_the_word(uint64_t w, uint64_t&) {
+ return bits::cnt(~w);
+ }
+
+ static uint32_t word_rank(const uint64_t* data, size_type idx) {
+ return bits::cnt((~*(data+(idx>>6))) & bits::lo_set[idx&0x3F]);
+ }
+
+ static uint32_t full_word_rank(const uint64_t* data, size_type idx) {
+ return bits::cnt((~*(data+(idx>>6))));
+ }
+
+ static uint64_t init_carry() {
+ return 0;
+ }
+};
+
+template<>
+struct rank_support_trait<1,1> {
+ typedef rank_support::size_type size_type;
+
+ static size_type args_in_the_word(uint64_t w, uint64_t&) {
+ return bits::cnt(w);
+ }
+
+ static uint32_t word_rank(const uint64_t* data, size_type idx) {
+ return bits::cnt(*(data+(idx>>6)) & bits::lo_set[idx&0x3F]);
+ }
+
+ static uint32_t full_word_rank(const uint64_t* data, size_type idx) {
+ return bits::cnt(*(data+(idx>>6)));
+ }
+
+ static uint64_t init_carry() {
+ return 0;
+ }
+};
+
+template<>
+struct rank_support_trait<10,2> {
+ typedef rank_support::size_type size_type;
+
+ static size_type args_in_the_word(uint64_t w, uint64_t& carry) {
+ return bits::cnt10(w, carry);
+ }
+
+ static uint32_t word_rank(const uint64_t* data, size_type idx) {
+ data = data+(idx>>6);
+ uint64_t carry = (idx>63) ? *(data-1)>>63 : 0;
+ return bits::cnt(bits::map10(*data, carry) & bits::lo_set[idx&0x3F]);
+ }
+
+ static uint32_t full_word_rank(const uint64_t* data, size_type idx) {
+ data = data+(idx>>6);
+ uint64_t carry = (idx>63) ? *(data-1)>>63 : 0;
+ return bits::cnt(bits::map10(*data, carry));
+ }
+
+ static uint64_t init_carry() {
+ return 0;
+ }
+};
+
+template<>
+struct rank_support_trait<01,2> {
+ typedef rank_support::size_type size_type;
+
+ static size_type args_in_the_word(uint64_t w, uint64_t& carry) {
+ return bits::cnt01(w, carry);
+ }
+
+ static uint32_t word_rank(const uint64_t* data, size_type idx) {
+ data = data+(idx>>6);
+ uint64_t carry = (idx>63) ? *(data-1)>>63 : 0;
+ return bits::cnt(bits::map01(*data, carry) & bits::lo_set[idx&0x3F]);
+ }
+
+ static uint32_t full_word_rank(const uint64_t* data, size_type idx) {
+ data = data+(idx>>6);
+ uint64_t carry = (idx>63) ? *(data-1)>>63 : 0;
+ return bits::cnt(bits::map01(*data, carry));
+ }
+
+ static uint64_t init_carry() {
+ return 1;
+ }
+};
+
+}// end namespace sdsl
+
+#include "rank_support_v.hpp"
+#include "rank_support_v5.hpp"
+#include "rank_support_scan.hpp"
+
+#endif // end file
diff --git a/include/sdsl/rank_support_scan.hpp b/include/sdsl/rank_support_scan.hpp
new file mode 100644
index 0000000..81b97d1
--- /dev/null
+++ b/include/sdsl/rank_support_scan.hpp
@@ -0,0 +1,100 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rank_support_scan.hpp
+ \brief rank_support_scan.hpp contains rank_support_scan that support a sdsl::bit_vector with linear time rank information.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RANK_SUPPORT_SCAN
+#define INCLUDED_SDSL_RANK_SUPPORT_SCAN
+
+#include "rank_support.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A class supporting rank queries in linear time.
+/*! \par Space complexity
+ * Constant.
+ * \par Time complexity
+ * Linear in the size of the supported vector.
+ *
+ * \tparam t_b Bit pattern which should be supported. Either `0`,`1`,`10`,`01`.
+ * \tparam t_pat_len Length of the bit pattern.
+ * @ingroup rank_support_group
+ */
+template<uint8_t t_b=1, uint8_t t_pat_len=1>
+class rank_support_scan : public rank_support
+{
+ private:
+ static_assert(t_b == 1u or t_b == 0u or t_b == 10u , "rank_support_scan: bit pattern must be `0`,`1`,`10` or `01`");
+ static_assert(t_pat_len == 1u or t_pat_len == 2u , "rank_support_scan: bit pattern length must be 1 or 2");
+ public:
+ typedef bit_vector bit_vector_type;
+ enum { bit_pat = t_b };
+ public:
+ explicit rank_support_scan(const bit_vector* v = nullptr) {
+ set_vector(v);
+ }
+ rank_support_scan(const rank_support_scan& rs) {
+ set_vector(rs.m_v);
+ }
+ size_type rank(size_type idx) const;
+ size_type operator()(size_type idx)const {
+ return rank(idx);
+ };
+ size_type size()const {
+ return m_v->size();
+ };
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return serialize_empty_object(out, v, name, this);
+ }
+ void load(std::istream&, const int_vector<1>* v=nullptr) {
+ set_vector(v);
+ }
+ void set_vector(const bit_vector* v=nullptr) {
+ m_v=v;
+ }
+
+ //! Assign Operator
+ rank_support_scan& operator=(const rank_support_scan& rs) {
+ set_vector(rs.m_v);
+ return *this;
+ }
+
+ //! swap Operator
+ void swap(rank_support_scan&) {}
+};
+
+template<uint8_t t_b, uint8_t t_pat_len>
+inline typename rank_support_scan<t_b, t_pat_len>::size_type rank_support_scan<t_b, t_pat_len>::rank(size_type idx)const
+{
+ assert(m_v != nullptr);
+ assert(idx <= m_v->size());
+ const uint64_t* p = m_v->data();
+ size_type i = 0;
+ size_type result = 0;
+ while (i+64 <= idx) {
+ result += rank_support_trait<t_b, t_pat_len>::full_word_rank(p, i);
+ i += 64;
+ }
+ return result+rank_support_trait<t_b, t_pat_len>::word_rank(p, idx);
+}
+
+}// end namespace sds
+
+#endif // end file
diff --git a/include/sdsl/rank_support_v.hpp b/include/sdsl/rank_support_v.hpp
new file mode 100644
index 0000000..7548dc6
--- /dev/null
+++ b/include/sdsl/rank_support_v.hpp
@@ -0,0 +1,162 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rank_support_v.hpp
+ \brief rank_support_v.hpp contains rank_support_v.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RANK_SUPPORT_V
+#define INCLUDED_SDSL_RANK_SUPPORT_V
+
+#include "rank_support.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+
+//! A rank structure proposed by Sebastiano Vigna
+/*! \par Space complexity
+ * \f$ 0.25n\f$ for a bit vector of length n bits.
+ *
+ * The superblock size is 512. Each superblock is subdivided into 512/64 = 8
+ * blocks. So absolute counts for the superblock add 64/512 bits on top of each
+ * supported bit. Since the first of the 8 relative count values is 0, we can
+ * fit the remaining 7 (each of width log(512)=9) in a 64bit word. The relative
+ * counts add another 64/512 bits on top of each supported bit.
+ * In total this results in 128/512=25% overhead.
+ *
+ * \tparam t_b Bit pattern `0`,`1`,`10`,`01` which should be ranked.
+ * \tparam t_pat_len Length of the bit pattern.
+ *
+ * \par Reference
+ * Sebastiano Vigna:
+ * Broadword Implementation of Rank/Select Queries.
+ * WEA 2008: 154-168
+ *
+ * @ingroup rank_support_group
+ */
+template<uint8_t t_b=1, uint8_t t_pat_len=1>
+class rank_support_v : public rank_support
+{
+ private:
+ static_assert(t_b == 1u or t_b == 0u or t_b == 10u , "rank_support_v: bit pattern must be `0`,`1`,`10` or `01`");
+ static_assert(t_pat_len == 1u or t_pat_len == 2u , "rank_support_v: bit pattern length must be 1 or 2");
+ public:
+ typedef bit_vector bit_vector_type;
+ typedef rank_support_trait<t_b, t_pat_len> trait_type;
+ enum { bit_pat = t_b };
+ private:
+ // basic block for interleaved storage of superblockrank and blockrank
+ int_vector<64> m_basic_block;
+ public:
+ explicit rank_support_v(const bit_vector* v = nullptr) {
+ set_vector(v);
+ if (v == nullptr) {
+ return;
+ } else if (v->empty()) {
+ m_basic_block = int_vector<64>(2,0); // resize structure for basic_blocks
+ return;
+ }
+ size_type basic_block_size = ((v->capacity() >> 9)+1)<<1;
+ m_basic_block.resize(basic_block_size); // resize structure for basic_blocks
+ if (m_basic_block.empty())
+ return;
+ const uint64_t* data = m_v->data();
+ size_type i, j=0;
+ m_basic_block[0] = m_basic_block[1] = 0;
+
+ uint64_t carry = trait_type::init_carry();
+ uint64_t sum = trait_type::args_in_the_word(*data, carry);
+ uint64_t second_level_cnt = 0;
+ for (i = 1; i < (m_v->capacity()>>6) ; ++i) {
+ if (!(i&0x7)) {// if i%8==0
+ j += 2;
+ m_basic_block[j-1] = second_level_cnt;
+ m_basic_block[j] = m_basic_block[j-2] + sum;
+ second_level_cnt = sum = 0;
+ } else {
+ second_level_cnt |= sum<<(63-9*(i&0x7));// 54, 45, 36, 27, 18, 9, 0
+ }
+ sum += trait_type::args_in_the_word(*(++data), carry);
+ }
+ if (i&0x7) { // if i%8 != 0
+ second_level_cnt |= sum << (63-9*(i&0x7));
+ m_basic_block[j+1] = second_level_cnt;
+ } else { // if i%8 == 0
+ j += 2;
+ m_basic_block[j-1] = second_level_cnt;
+ m_basic_block[j] = m_basic_block[j-2] + sum;
+ m_basic_block[j+1] = 0;
+ }
+ }
+
+ rank_support_v(const rank_support_v&) = default;
+ rank_support_v(rank_support_v&&) = default;
+ rank_support_v& operator=(const rank_support_v&) = default;
+ rank_support_v& operator=(rank_support_v&&) = default;
+
+
+ size_type rank(size_type idx) const {
+ assert(m_v != nullptr);
+ assert(idx <= m_v->size());
+ const uint64_t* p = m_basic_block.data()
+ + ((idx>>8)&0xFFFFFFFFFFFFFFFEULL); // (idx/512)*2
+ if (idx&0x3F) // if (idx%64)!=0
+ return *p + ((*(p+1)>>(63 - 9*((idx&0x1FF)>>6)))&0x1FF) +
+ trait_type::word_rank(m_v->data(), idx);
+ else
+ return *p + ((*(p+1)>>(63 - 9*((idx&0x1FF)>>6)))&0x1FF);
+ }
+
+ inline size_type operator()(size_type idx)const {
+ return rank(idx);
+ }
+
+ size_type size()const {
+ return m_v->size();
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const {
+ size_type written_bytes = 0;
+ structure_tree_node* child = structure_tree::add_child(v, name,
+ util::class_name(*this));
+ written_bytes += m_basic_block.serialize(out, child,
+ "cumulative_counts");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in, const int_vector<1>* v=nullptr) {
+ set_vector(v);
+ m_basic_block.load(in);
+ }
+
+ void set_vector(const bit_vector* v=nullptr) {
+ m_v = v;
+ }
+
+ void swap(rank_support_v& rs) {
+ if (this != &rs) { // if rs and _this_ are not the same object
+ m_basic_block.swap(rs.m_basic_block);
+ }
+ }
+};
+
+}// end namespace sds
+
+#endif // end file
diff --git a/include/sdsl/rank_support_v5.hpp b/include/sdsl/rank_support_v5.hpp
new file mode 100644
index 0000000..a9ee772
--- /dev/null
+++ b/include/sdsl/rank_support_v5.hpp
@@ -0,0 +1,169 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rank_support_v5.hpp
+ \brief rank_support_v5.hpp contains rank_support_v5.5
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RANK_SUPPORT_VFIVE
+#define INCLUDED_SDSL_RANK_SUPPORT_VFIVE
+
+#include "rank_support.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+template<uint8_t, uint8_t>
+struct rank_support_trait;
+
+//! A class supporting rank queries in constant time.
+/*! \par Space complexity
+ * \f$ 0.0625n\f$ bits for a bit vector of length n bits.
+ *
+ * The superblock size is 2048. Each superblock is subdivided into
+ * 2048/(6*64) = 5 blocks (with some bit remaining). So absolute counts for
+ * the superblock add 64/2048 bits on top of each supported bit. Since the
+ * first of the 6 relative count values is 0, we can fit the remaining 5 in
+ * (each of width log(2048)=11) in a 64 bit word. The relative counts add
+ * another 64/2048 bits bits on top of each supported bit. In total this
+ * results is 128/2048= 6.25% overhead.
+ *
+ * \tparam t_b Bit pattern `0`,`1`,`10`,`01` which should be ranked.
+ * \tparam t_pat_len Length of the bit pattern.
+ *
+ * @ingroup rank_support_group
+ */
+template<uint8_t t_b=1, uint8_t t_pat_len=1>
+class rank_support_v5 : public rank_support
+{
+ private:
+ static_assert(t_b == 1u or t_b == 0u or t_b == 10u , "rank_support_v5: bit pattern must be `0`,`1`,`10` or `01`");
+ static_assert(t_pat_len == 1u or t_pat_len == 2u , "rank_support_v5: bit pattern length must be 1 or 2");
+ public:
+ typedef bit_vector bit_vector_type;
+ typedef rank_support_trait<t_b, t_pat_len> trait_type;
+ enum { bit_pat = t_b };
+ private:
+// basic block for interleaved storage of superblockrank and blockrank
+ int_vector<64> m_basic_block;
+ public:
+ explicit rank_support_v5(const bit_vector* v = nullptr) {
+ set_vector(v);
+ if (v == nullptr) {
+ return;
+ } else if (v->empty()) {
+ m_basic_block = int_vector<64>(2,0);
+ return;
+ }
+ size_type basic_block_size = ((v->capacity() >> 11)+1)<<1;
+ m_basic_block.resize(basic_block_size); // resize structure for basic_blocks
+ if (m_basic_block.empty())
+ return;
+ const uint64_t* data = m_v->data();
+ size_type i, j=0;
+ m_basic_block[0] = m_basic_block[1] = 0;
+
+ uint64_t carry = trait_type::init_carry();
+ uint64_t sum = trait_type::args_in_the_word(*data, carry);
+ uint64_t second_level_cnt = 0;
+ uint64_t cnt_words=1;
+ for (i = 1; i < (m_v->capacity()>>6) ; ++i, ++cnt_words) {
+ if (cnt_words == 32) {
+ j += 2;
+ m_basic_block[j-1] = second_level_cnt;
+ m_basic_block[j] = m_basic_block[j-2] + sum;
+ second_level_cnt = sum = cnt_words = 0;
+ } else if ((cnt_words%6)==0) {
+ // pack the prefix sum for each 6x64bit block into the second_level_cnt
+ second_level_cnt |= sum<<(60-12*(cnt_words/6));// 48, 36, 24, 12, 0
+ }
+ sum += trait_type::args_in_the_word(*(++data), carry);
+ }
+
+ if ((cnt_words%6)==0) {
+ second_level_cnt |= sum<<(60-12*(cnt_words/6));
+ }
+ if (cnt_words == 32) {
+ j += 2;
+ m_basic_block[j-1] = second_level_cnt;
+ m_basic_block[j] = m_basic_block[j-2] + sum;
+ m_basic_block[j+1] = 0;
+ } else {
+ m_basic_block[j+1] = second_level_cnt;
+ }
+ }
+
+ rank_support_v5(const rank_support_v5&) = default;
+ rank_support_v5(rank_support_v5&&) = default;
+ rank_support_v5& operator=(const rank_support_v5&) = default;
+ rank_support_v5& operator=(rank_support_v5&&) = default;
+
+ size_type rank(size_type idx) const {
+ assert(m_v != nullptr);
+ assert(idx <= m_v->size());
+ const uint64_t* p = m_basic_block.data()
+ + ((idx>>10)&0xFFFFFFFFFFFFFFFEULL);// (idx/2048)*2
+// ( prefix sum of the 6x64bit blocks | (idx%2048)/(64*6) )
+ size_type result = *p
+ + ((*(p+1)>>(60-12*((idx&0x7FF)/(64*6))))&0x7FFULL)
+ + trait_type::word_rank(m_v->data(), idx);
+ idx -= (idx&0x3F);
+ uint8_t to_do = ((idx>>6)&0x1FULL)%6;
+ --idx;
+ while (to_do) {
+ result += trait_type::full_word_rank(m_v->data(), idx);
+ --to_do;
+ idx-=64;
+ }
+ return result;
+ }
+
+ inline size_type operator()(size_type idx)const {
+ return rank(idx);
+ }
+ size_type size()const {
+ return m_v->size();
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ size_type written_bytes = 0;
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ written_bytes += m_basic_block.serialize(out, child, "cumulative_counts");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in, const bit_vector* v=nullptr) {
+ set_vector(v);
+ assert(m_v != nullptr); // supported bit vector should be known
+ m_basic_block.load(in);
+ }
+
+ void set_vector(const bit_vector* v=nullptr) {
+ m_v = v;
+ }
+ //! swap Operator
+ void swap(rank_support_v5& rs) {
+ if (this != &rs) { // if rs and _this_ are not the same object
+ m_basic_block.swap(rs.m_basic_block);
+ }
+ }
+};
+
+}// end namespace sds
+
+#endif // end file
diff --git a/include/sdsl/rmq_succinct_sada.hpp b/include/sdsl/rmq_succinct_sada.hpp
new file mode 100644
index 0000000..6f579af
--- /dev/null
+++ b/include/sdsl/rmq_succinct_sada.hpp
@@ -0,0 +1,251 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rmq_succinct_sada.hpp
+ \brief rmq_succinct_sada.hpp contains the class rmq_succinct_sada which supports range minimum or range maximum queries on a random access container in constant time and \f$4 n+o(n) bits\f$ space.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RMQ_SUCCINCT_SADA
+#define INCLUDED_SDSL_RMQ_SUCCINCT_SADA
+
+#include "rmq_support.hpp"
+#include "int_vector.hpp"
+#include "bp_support_sada.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "suffix_tree_helper.hpp"
+#include "util.hpp"
+#include <utility> // for pair
+#include <stack>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+
+template<bool t_min = true,
+ class t_bp_support = bp_support_sada<256, 32, rank_support_v5<1>, select_support_scan<1> >,
+ class t_rank_10 = rank_support_v<10,2>, class t_select_10 = select_support_mcl<10,2> >
+class rmq_succinct_sada;
+
+template<class t_bp_support = bp_support_sada<256, 32, rank_support_v5<>, select_support_scan<1> >,
+ class t_rank_10 = rank_support_v<10,2>, class t_select_10 = select_support_mcl<10,2> >
+struct range_maximum_support_sada
+{
+ typedef rmq_succinct_sada<false, t_bp_support, t_rank_10, t_select_10> type;
+};
+
+//! A class to support range minimum or range maximum queries on a random access container.
+/*!
+ * \tparam t_min Specifies whether the data structure should answer range min/max queries (mimumum=true)
+ * \tparam t_bp_support Type of Support structure for the BPS-DFS
+ * \tparam t_rank_10 Type of rank structure for it pattern `10`.
+ * \tparam t_select_10 Type of select structure for bit pattern `10`.
+ * \par Time complexity
+ * \f$ \Order{1} \f$ for the range min/max queries if the BPS supports constant time operations.
+ * \par Space complexity:
+ * \f$ 4n+o(n) \f$ bits for the data structure ( \f$ n=size() \f$ ).
+ *
+ * \par Reference
+ * TODO: Kunihiko Sadakane
+ *
+ */
+template<bool t_min, class t_bp_support, class t_rank_10, class t_select_10>
+class rmq_succinct_sada
+{
+ bit_vector m_ect_bp; //!< A bit vector which contains the BP-DFS
+ t_bp_support m_ect_bp_support; //!< Support structure for the BP-DFS
+ t_rank_10 m_ect_bp_rank10; //!< A rank support for bit pattern `10`
+ t_select_10 m_ect_bp_select10;//!< A select support for bit pattern `10`
+
+ public:
+ typedef typename bit_vector::size_type size_type;
+ typedef typename bit_vector::size_type value_type;
+
+ typedef t_bp_support bp_support_type;
+ typedef t_rank_10 rank_support10_type;
+ typedef t_select_10 select_support10_type;
+
+ const bit_vector& ect_bp = m_ect_bp;
+ const bp_support_type& ect_bp_support = m_ect_bp_support;
+ const rank_support10_type& ect_bp_rank10 = m_ect_bp_rank10;
+ const select_support10_type& ect_bp_select10 = m_ect_bp_select10;
+
+ private:
+
+ typedef rmq_succinct_sct<t_min> rmq_construct_helper_type;
+
+ // helper class for the construction
+ struct state {
+ size_type l, r; // left and right interval
+ size_type m; // index of the rmq
+ uint8_t visit; // 1==first, 2==second, 3==third visit
+ state(size_type fl=0, size_type fr=0, size_type fm=0, uint8_t fvisit=0)
+ : l(fl), r(fr), m(fm), visit(fvisit) {}
+ };
+
+ //! Constructor
+ /*! \tparam t_rac A random access container.
+ * \param v Ponter to container object.
+ */
+ template<class t_rac>
+ void construct_bp_of_extended_cartesian_tree(const t_rac* v, const rmq_construct_helper_type& rmq_helper) {
+ m_ect_bp.resize(4*v->size());
+ if (v->size() > 0) {
+ size_type bp_cnt = 0;
+ size_type l = 0, r = v->size()-1;
+ std::stack<state> state_stack;
+ state_stack.push(state(l, r, rmq_helper(l, r), 1));
+ while (!state_stack.empty()) {
+ state s = state_stack.top(); state_stack.pop();
+ if (1 == s.visit) {
+ m_ect_bp[bp_cnt++] = 1; // write beginning of inner node
+ state_stack.push(state(s.l, s.r, s.m, 2));
+ if (s.m > s.l) {
+ state_stack.push(state(s.l, s.m-1, rmq_helper(s.l, s.m-1), 1));
+ }
+ } else if (2 == s.visit) {
+ m_ect_bp[bp_cnt++] = 1; // write leaf
+ m_ect_bp[bp_cnt++] = 0;
+ state_stack.push(state(s.l, s.r, s.m, 3));
+ if (s.m < s.r) {
+ state_stack.push(state(s.m+1, s.r, rmq_helper(s.m+1, s.r), 1));
+ }
+ } else if (3 == s.visit) {
+ m_ect_bp[bp_cnt++] = 0; // write end of inner node
+ }
+ }
+ assert(bp_cnt == 4*v->size());
+ }
+ }
+
+ void copy(const rmq_succinct_sada& rm) {
+ m_ect_bp = rm.m_ect_bp;
+ m_ect_bp_support = rm.m_ect_bp_support;
+ m_ect_bp_support.set_vector(&m_ect_bp);
+ m_ect_bp_rank10 = rm.m_ect_bp_rank10;
+ m_ect_bp_rank10.set_vector(&m_ect_bp);
+ m_ect_bp_select10 = rm.m_ect_bp_select10;
+ m_ect_bp_select10.set_vector(&m_ect_bp);
+ }
+
+ public:
+ //! Default Constructor
+ rmq_succinct_sada() {}
+
+ //! Constructor
+ template<class t_rac>
+ rmq_succinct_sada(const t_rac* v=nullptr) {
+ if (v != nullptr) {
+ rmq_construct_helper_type rmq_helper(v);
+ m_ect_bp.resize(4*v->size());
+ construct_bp_of_extended_cartesian_tree(v, rmq_helper);
+ m_ect_bp_support = bp_support_type(&m_ect_bp);
+ util::init_support(m_ect_bp_rank10, &m_ect_bp);
+ util::init_support(m_ect_bp_select10, &m_ect_bp);
+ }
+ }
+
+ //! Copy constructor
+ rmq_succinct_sada(const rmq_succinct_sada& rm) {
+ if (this != &rm) { // if v is not the same object
+ copy(rm);
+ }
+ }
+
+ //! Move constructor
+ rmq_succinct_sada(rmq_succinct_sada&& rm) {
+ *this = rm;
+ }
+
+ //! Destructor
+ ~rmq_succinct_sada() { }
+
+ rmq_succinct_sada& operator=(const rmq_succinct_sada& rm) {
+ if (this != &rm) {
+ copy(rm);
+ }
+ return *this;
+ }
+
+ rmq_succinct_sada& operator=(rmq_succinct_sada&& rm) {
+ if (this != &rm) {
+ m_ect_bp = std::move(rm.m_ect_bp);
+ m_ect_bp_support = std::move(rm.m_ect_bp_support);
+ m_ect_bp_support.set_vector(&m_ect_bp);
+ m_ect_bp_rank10 = std::move(rm.m_ect_bp_rank10);
+ m_ect_bp_rank10.set_vector(&m_ect_bp);
+ m_ect_bp_select10 = std::move(rm.m_ect_bp_select10);
+ m_ect_bp_select10.set_vector(&m_ect_bp);
+ }
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(rmq_succinct_sada& rm) {
+ m_ect_bp.swap(rm.m_ect_bp);
+ util::swap_support(m_ect_bp_support, rm.m_ect_bp_support, &m_ect_bp, &(rm.m_ect_bp));
+ util::swap_support(m_ect_bp_rank10, rm.m_ect_bp_rank10, &m_ect_bp, &(rm.m_ect_bp));
+ util::swap_support(m_ect_bp_select10, rm.m_ect_bp_select10, &m_ect_bp, &(rm.m_ect_bp));
+ }
+
+ //! Range minimum/maximum query for the supported random access container v.
+ /*!
+ * \param l Leftmost position of the interval \f$[\ell..r]\f$.
+ * \param r Rightmost position of the interval \f$[\ell..r]\f$.
+ * \return The minimal index i with \f$\ell \leq i \leq r\f$ for which \f$ v[i] \f$ is minimal/maximal.
+ * \pre
+ * - r < size()
+ * - \f$ \ell \leq r \f$
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type operator()(const size_type l, const size_type r)const {
+ assert(l <= r); assert(r < size());
+ if (l==r)
+ return l;
+ size_type x = m_ect_bp_select10(l+1);
+ size_type y = m_ect_bp_select10(r+1);
+ size_type z = m_ect_bp_support.rmq(x, y);
+ size_type f = z + 1 - 2*(m_ect_bp[z]);
+ return m_ect_bp_rank10(f-1);
+ }
+
+ size_type size()const {
+ return m_ect_bp.size()/4;
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_ect_bp.serialize(out, child, "ect_bp");
+ written_bytes += m_ect_bp_support.serialize(out, child, "ect_bp_support");
+ written_bytes += m_ect_bp_rank10.serialize(out, child, "ect_bp_rank10");
+ written_bytes += m_ect_bp_select10.serialize(out, child, "ect_bp_select10");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ m_ect_bp.load(in);
+ m_ect_bp_support.load(in, &m_ect_bp);
+ m_ect_bp_rank10.load(in, &m_ect_bp);
+ m_ect_bp_select10.load(in, &m_ect_bp);
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/rmq_succinct_sct.hpp b/include/sdsl/rmq_succinct_sct.hpp
new file mode 100644
index 0000000..6982d49
--- /dev/null
+++ b/include/sdsl/rmq_succinct_sct.hpp
@@ -0,0 +1,179 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rmq_succinct_sct.hpp
+ \brief rmq_succinct_sct.hpp contains the class rmq_succinct_sct which supports range minimum or range maximum queries on a random access container in constant time and \f$2 n+o(n) bits\f$ space.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RMQ_SUCCINCT_SCT
+#define INCLUDED_SDSL_RMQ_SUCCINCT_SCT
+
+#include "rmq_support.hpp"
+#include "int_vector.hpp"
+#include "bp_support_sada.hpp"
+#include "suffix_tree_helper.hpp"
+#include "util.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+template<bool t_min = true,
+ class t_bp_support = bp_support_sada<256,32,rank_support_v5<> > >
+class rmq_succinct_sct;
+
+template<class t_bp_support = bp_support_sada<256,32,rank_support_v5<> > >
+struct range_maximum_sct {
+ typedef rmq_succinct_sct<false, t_bp_support> type;
+};
+
+//! A class to support range minimum or range maximum queries on a random access container.
+/*!
+ * \tparam t_min Specifies whether the data structure should answer range min/max queries (mimumum=true)
+ * \tparam t_bp_support Type of Support structure for the BPS-SCT.
+ *
+ * \par Time complexity
+ * \f$ \Order{1} \f$ for the range minimum/maximum queries if the balanced parentheses support structure supports constant time operations.
+ * \par Space complexity:
+ * \f$ \Order{2n}+o(n) \f$ bits for the data structure ( \f$ n=size() \f$ ).
+ */
+template<bool t_min, class t_bp_support>
+class rmq_succinct_sct
+{
+ bit_vector m_sct_bp; //!< A bit vector which contains the BPS-SCT of the input container.
+ t_bp_support m_sct_bp_support; //!< Support structure for the BPS-SCT
+
+ void copy(const rmq_succinct_sct& rm) {
+ m_sct_bp = rm.m_sct_bp;
+ m_sct_bp_support = rm.m_sct_bp_support;
+ m_sct_bp_support.set_vector(&m_sct_bp);
+ }
+
+ public:
+ typedef typename bit_vector::size_type size_type;
+ typedef typename bit_vector::size_type value_type;
+ typedef t_bp_support bp_support_type;
+
+ const bit_vector& sct_bp = m_sct_bp;
+ const bp_support_type& sct_bp_support = m_sct_bp_support;
+
+ //! Default constructor
+ rmq_succinct_sct() {}
+
+ //! Constructor
+ /*! \tparam t_rac A random access container.
+ * \param v Pointer to container object.
+ */
+ template<class t_rac>
+ rmq_succinct_sct(const t_rac* v=nullptr) {
+ if (v != nullptr) {
+#ifdef RMQ_SCT_BUILD_BP_NOT_SUCCINCT
+ // this method takes \f$n\log n\f$ bits extra space in the worst case
+ construct_supercartesian_tree_bp(*v, m_sct_bp, t_min);
+#else
+ // this method takes only \f$n\f$ bits extra space in all cases
+ m_sct_bp = construct_supercartesian_tree_bp_succinct(*v, t_min);
+ // TODO: constructor which uses int_vector_buffer
+#endif
+ m_sct_bp_support = bp_support_type(&m_sct_bp);
+ }
+ }
+
+ //! Copy constructor
+ rmq_succinct_sct(const rmq_succinct_sct& rm) {
+ *this = rm;
+ }
+
+ //! Move constructor
+ rmq_succinct_sct(rmq_succinct_sct&& rm) {
+ *this = std::move(rm);
+ }
+
+ rmq_succinct_sct& operator=(const rmq_succinct_sct& rm) {
+ if (this != &rm) {
+ m_sct_bp = rm.m_sct_bp;
+ m_sct_bp_support = rm.m_sct_bp_support;
+ m_sct_bp_support.set_vector(&m_sct_bp);
+ }
+ return *this;
+ }
+
+ rmq_succinct_sct& operator=(rmq_succinct_sct&& rm) {
+ if (this != &rm) {
+ m_sct_bp = std::move(rm.m_sct_bp);
+ m_sct_bp_support = std::move(rm.m_sct_bp_support);
+ m_sct_bp_support.set_vector(&m_sct_bp);
+ }
+ return *this;
+ }
+
+ void swap(rmq_succinct_sct& rm) {
+ m_sct_bp.swap(rm.m_sct_bp);
+ util::swap_support(m_sct_bp_support, rm.m_sct_bp_support,
+ &m_sct_bp, &(rm.m_sct_bp));
+ }
+
+ //! Range minimum/maximum query for the supported random access container v.
+ /*!
+ * \param l Leftmost position of the interval \f$[\ell..r]\f$.
+ * \param r Rightmost position of the interval \f$[\ell..r]\f$.
+ * \return The minimal index i with \f$\ell \leq i \leq r\f$ for which \f$ v[i] \f$ is minimal/maximal.
+ * \pre
+ * - r < size()
+ * - \f$ \ell \leq r \f$
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type operator()(const size_type l, const size_type r)const {
+ assert(l <= r); assert(r < size());
+ if (l==r)
+ return l;
+ size_type i = m_sct_bp_support.select(l+1);
+ size_type j = m_sct_bp_support.select(r+1);
+ size_type fc_i = m_sct_bp_support.find_close(i);
+ if (j < fc_i) { // i < j < find_close(j) < find_close(i)
+ return l;
+ } else { // if i < find_close(i) < j < find_close(j)
+ size_type ec = m_sct_bp_support.rr_enclose(i,j);
+ if (ec == m_sct_bp_support.size()) {// no restricted enclosing pair found
+ return r;
+ } else { // found range restricted enclosing pair
+ return m_sct_bp_support.rank(ec)-1; // subtract 1, as the index is 0 based
+ }
+ }
+ }
+
+ size_type size()const {
+ return m_sct_bp.size()/2;
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_sct_bp.serialize(out, child, "sct_bp");
+ written_bytes += m_sct_bp_support.serialize(out, child, "sct_bp_support");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ m_sct_bp.load(in);
+ m_sct_bp_support.load(in, &m_sct_bp);
+ }
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/rmq_support.hpp b/include/sdsl/rmq_support.hpp
new file mode 100644
index 0000000..05a8398
--- /dev/null
+++ b/include/sdsl/rmq_support.hpp
@@ -0,0 +1,50 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rmq_support.hpp
+ \brief rmq_support.hpp contains different range minimum support data structures.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RMQ_SUPPORT
+#define INCLUDED_SDSL_RMQ_SUPPORT
+
+/** \defgroup rmq_group Range Minimum/Maximum Support (RMS) */
+
+template<class RandomAccessContainer, bool Minimum> // for range minimum queries
+struct min_max_trait {
+ static inline bool strict_compare(const typename RandomAccessContainer::value_type v1, const typename RandomAccessContainer::value_type v2) {
+ return v1 < v2;
+ }
+ static inline bool compare(const typename RandomAccessContainer::value_type v1, const typename RandomAccessContainer::value_type v2) {
+ return v1 <= v2;
+ }
+};
+
+template<class RandomAccessContainer> // for range maximum queries
+struct min_max_trait<RandomAccessContainer, false> {
+ static inline bool strict_compare(const typename RandomAccessContainer::value_type v1, const typename RandomAccessContainer::value_type v2) {
+ return v1 > v2;
+ }
+ static inline bool compare(const typename RandomAccessContainer::value_type v1, const typename RandomAccessContainer::value_type v2) {
+ return v1 >= v2;
+ }
+};
+
+#include "rmq_support_sparse_table.hpp"
+#include "rmq_succinct_sct.hpp"
+#include "rmq_succinct_sada.hpp"
+
+#endif
diff --git a/include/sdsl/rmq_support_sparse_table.hpp b/include/sdsl/rmq_support_sparse_table.hpp
new file mode 100644
index 0000000..a726ec2
--- /dev/null
+++ b/include/sdsl/rmq_support_sparse_table.hpp
@@ -0,0 +1,190 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rmq_support_sparse_table.hpp
+ \brief rmq_support_sparse_table.hpp contains the class rmq_support_sparse_table.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RMQ_SUPPORT_SPARSE_TABLE
+#define INCLUDED_SDSL_RMQ_SUPPORT_SPARSE_TABLE
+
+#include "rmq_support.hpp"
+#include "int_vector.hpp"
+#include <ostream>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+
+template<class t_rac = int_vector<>, bool t_min=true>
+class rmq_support_sparse_table;
+
+template<class t_rac = int_vector<> >
+using range_maximum_support_sparse_table = rmq_support_sparse_table<t_rac,false>;
+
+
+//! A class to support range minimum or range maximum queries on a random access container.
+/*!
+ * \tparam t_rac Type of random access container for which the structure should be build.
+ * \tparam t_min Specifies whether the data structure should answer range min/max queries (mimumum=true)
+ *
+ * \par Reference
+ * Michael A. Bender, Martin Farach-Colton:
+ * The LCA Problem Revisited.
+ * LATIN 2000: 88-94
+ *
+ * \par Time complexity
+ * \f$ \Order{1} \f$ for the range minimum/maximum queries.
+ * \par Space complexity:
+ * \f$ \Order{n\log^2 n} \f$ bits for the data structure ( \f$ n=size() \f$ ).
+ * We used bit compression to get a good result in practice.
+ */
+template<class t_rac, bool t_min>
+class rmq_support_sparse_table
+{
+ const t_rac* m_v; // pointer to the supported random access container
+ bit_vector::size_type m_k; // size of m_table
+ std::vector<int_vector<>> m_table;
+ typedef min_max_trait<t_rac, t_min> mm_trait;
+
+ void copy(const rmq_support_sparse_table& rm) {
+ m_v = rm.m_v;
+ m_k = rm.m_k;
+ m_table.resize(m_k);
+ std::copy(rm.m_table.begin(), rm.m_table.end(),
+ m_table.begin());
+ }
+
+ public:
+ typedef typename t_rac::size_type size_type;
+ typedef typename t_rac::size_type value_type;
+
+ rmq_support_sparse_table(const t_rac* v=nullptr):m_v(v), m_k(0) {
+ if (m_v == nullptr)
+ return;
+ const size_type n = m_v->size();
+ if (n < 2) // for n<2 the queries could be answerd without any table
+ return;
+ size_type k=0;
+ while (2*(1ULL<<k) < n) ++k; // calculate maximal
+ m_table.resize(k);
+ m_k = k;
+ for (size_type i=0; i<k; ++i) {
+ m_table[i] = int_vector<>(n-(1<<(i+1))+1, 0, i+1);
+ }
+ for (size_type i=0; i<n-1; ++i) {
+ if (!mm_trait::compare((*m_v)[i], (*m_v)[i+1]))
+ m_table[0][i] = 1;
+ }
+ for (size_type i=1; i<k; ++i) {
+ for (size_type j=0; j<m_table[i].size(); ++j) {
+ m_table[i][j] = mm_trait::compare((*m_v)[j+m_table[i-1][j]], (*m_v)[j+(1<<i)+m_table[i-1][j+(1<<i)]]) ? m_table[i-1][j] : (1<<i)+m_table[i-1][j+(1<<i)];
+ }
+ }
+ }
+
+ //! Copy constructor
+ rmq_support_sparse_table(const rmq_support_sparse_table& rm) {
+ if (this != &rm) { // if v is not the same object
+ copy(rm);
+ }
+ }
+
+ //! Move constructor
+ rmq_support_sparse_table(rmq_support_sparse_table&& rm) {
+ *this = std::move(rm);
+ }
+
+ rmq_support_sparse_table& operator=(const rmq_support_sparse_table& rm) {
+ if (this != &rm) {
+ copy(rm);
+ }
+ return *this;
+ }
+
+ rmq_support_sparse_table& operator=(rmq_support_sparse_table&& rm) {
+ if (this != &rm) {
+ m_v = rm.m_v;
+ m_k = rm.m_k;
+ m_table = rm.m_table;
+ }
+ return *this;
+ }
+
+ void swap(rmq_support_sparse_table& rm) {
+ std::swap(m_k, rm.m_k);
+ m_table.swap(rm.m_table);
+ }
+
+ void set_vector(const t_rac* v) {
+ m_v = v;
+ }
+
+ //! Range minimum/maximum query for the supported random access container v.
+ /*!
+ * \param l Leftmost position of the interval \f$[\ell..r]\f$.
+ * \param r Rightmost position of the interval \f$[\ell..r]\f$.
+ * \return The minimal index i with \f$\ell \leq i \leq r\f$ for which \f$ v[i] \f$ is minimal/maximal.
+ * \pre
+ * - r < size()
+ * - \f$ \ell \leq r \f$
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ */
+ size_type operator()(const size_type l, const size_type r)const {
+ assert(l <= r); assert(r < size());
+ if (l==r)
+ return l;
+ if (l+1 == r)
+ return mm_trait::compare((*m_v)[l],(*m_v)[r]) ? l : r;
+ size_type k = bits::hi(r-l);
+ const size_type rr = r-(1<<k)+1;
+ return mm_trait::compare((*m_v)[l+m_table[k-1][l]], (*m_v)[rr+m_table[k-1][rr]]) ? l+m_table[k-1][l] : rr+m_table[k-1][rr];
+ }
+
+ size_type size()const {
+ if (m_v == nullptr)
+ return 0;
+ else
+ return m_v->size();
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ size_type written_bytes = 0;
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ written_bytes += write_member(m_k, out);
+ if (m_k > 0) {
+ for (size_type i=0; i < m_k; ++i)
+ written_bytes += m_table[i].serialize(out);
+ }
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in, const t_rac* v) {
+ set_vector(v);
+ read_member(m_k, in);
+ if (m_k >0) {
+ m_table.resize(m_k);
+ for (size_type i=0; i < m_k; ++i)
+ m_table[i].load(in);
+ }
+ }
+};
+
+}// end namespace sds;
+#endif
diff --git a/include/sdsl/rrr_helper.hpp b/include/sdsl/rrr_helper.hpp
new file mode 100644
index 0000000..5fb51a6
--- /dev/null
+++ b/include/sdsl/rrr_helper.hpp
@@ -0,0 +1,539 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rrr_helper.hpp
+ \brief rrr_helper.hpp contains the sdsl::binomial struct,
+ a struct which contains informations about the binomial coefficients
+ \author Simon Gog, Matthias Petri, Stefan Arnold
+*/
+#ifndef SDSL_RRR_HELPER
+#define SDSL_RRR_HELPER
+
+#ifdef RRR_NO_OPT
+#ifndef RRR_NO_BS
+#define RRR_NO_BS
+#endif
+#endif
+
+#include <algorithm> // for next permutation
+#include <iostream>
+#include "bits.hpp"
+#include "uint128_t.hpp"
+#include "uint256_t.hpp"
+
+namespace sdsl
+{
+
+//! Trait struct for the binomial coefficient struct to handle different type of integers.
+/*! This generic implementation works for 64-bit integers.
+ */
+template<uint16_t log_n>
+struct binomial_coefficients_trait {
+ typedef uint64_t number_type;
+ static inline uint16_t hi(number_type x) {
+ return bits::hi(x);
+ }
+
+ //! Read a \f$len\f$-bit integer of type number_type from a bitvector.
+ /*!
+ * \param bv A bit_vector of int_vector from which we extract the integer.
+ * \param pos Position of the least significant bit of the integer which should be read.
+ * \param len bit-width of the integer which should be read.
+ * \return The len-bit integer.
+ */
+ template<class bit_vector_type>
+ static inline number_type get_int(const bit_vector_type& bv,
+ typename bit_vector_type::size_type pos,
+ uint16_t len) {
+ return bv.get_int(pos, len);
+ }
+
+ //! Write a \f$len\f$-bit integer x of type number_type to a bitvector.
+ /*!
+ * \param bv A bit_vecor or int_vector in which we write the integer.
+ * \param pos Position of the least significant bit of the integer which should be written.
+ * \param x The integer x which should be written.
+ * \param len Bit-width of x.
+ */
+ template<class bit_vector_type>
+ static void set_int(bit_vector_type& bv, typename bit_vector_type::size_type pos,
+ number_type x, uint16_t len) {
+ bv.set_int(pos, x, len);
+ }
+
+ //! Count the number of set bits in x.
+ /*!
+ * \param x The integer x.
+ */
+ static inline uint16_t popcount(number_type x) {
+ return bits::cnt(x);
+ }
+};
+
+//! Specialization of binomial_coefficients_trait for 128-bit integers.
+template<>
+struct binomial_coefficients_trait<7> {
+ typedef uint128_t number_type;
+ static inline uint16_t hi(number_type x) {
+ if ((x >> 64)) {
+ return bits::hi(x >> 64) + 64;
+ } else {
+ return bits::hi(x);
+ }
+ }
+
+ template<class bit_vector_type>
+ static inline number_type get_int(const bit_vector_type& bv,
+ typename bit_vector_type::size_type pos,
+ uint16_t len) {
+ if (len <= 64) {
+ return bv.get_int(pos, len);
+ } else {
+ return ((((number_type) bv.get_int(pos+64, len-64))<<64) + bv.get_int(pos, 64));
+ }
+ }
+
+ template<class bit_vector_type>
+ static void set_int(bit_vector_type& bv,
+ typename bit_vector_type::size_type pos,
+ number_type x, uint16_t len) {
+ if (len <= 64) {
+ bv.set_int(pos, x, len);
+ } else {
+ bv.set_int(pos, (uint64_t)x, 64); bv.set_int(pos+64, x>>64, len-64);
+ }
+ }
+
+ static inline uint16_t popcount(number_type x) {
+ return bits::cnt(x >> 64) + bits::cnt(x);
+ }
+};
+
+//! Specialization of binomial_coefficients_trait for 256-bit integers.
+template<>
+struct binomial_coefficients_trait<8> {
+ typedef uint256_t number_type;
+ static inline uint16_t hi(number_type x) {
+ return x.hi();
+ }
+
+ template<class bit_vector_type>
+ static inline number_type get_int(const bit_vector_type& bv,
+ typename bit_vector_type::size_type pos,
+ uint16_t len) {
+ if (len <= 64) {
+ return number_type(bv.get_int(pos, len));
+ } else if (len <= 128) {
+ return number_type(bv.get_int(pos, 64), bv.get_int(pos+64, len-64));
+ } else if (len <= 192) {
+ return number_type(bv.get_int(pos, 64), bv.get_int(pos + 64, 64),
+ (uint128_t)bv.get_int(pos + 128, len-128));
+ } else { // > 192
+ return number_type(bv.get_int(pos, 64), bv.get_int(pos+64, 64),
+ (((uint128_t)bv.get_int(pos+192, len-192))<<64) | bv.get_int(pos+128, 64));
+ }
+ }
+
+ template<class bit_vector_type>
+ static void set_int(bit_vector_type& bv,
+ typename bit_vector_type::size_type pos,
+ number_type x,
+ uint16_t len) {
+ if (len <= 64) {
+ bv.set_int(pos, x, len);
+ } else if (len <= 128) {
+ bv.set_int(pos, x, 64); bv.set_int(pos+64, x>>64, len-64);
+ } else if (len <= 192) {
+ bv.set_int(pos, x, 64); bv.set_int(pos+64, x>>64, 64);
+ bv.set_int(pos+128, x>>128, len-128);
+ } else { // > 192
+ bv.set_int(pos, x, 64); bv.set_int(pos+64, x>>64, 64);
+ bv.set_int(pos+128, x>>128, 64); bv.set_int(pos+192, x>>192, len-192);
+ }
+ }
+
+ static inline uint16_t popcount(number_type x) {
+ return x.popcount();
+ }
+};
+
+template<uint16_t n, class number_type>
+struct binomial_table {
+ static struct impl {
+ number_type table[n+1][n+1];
+ number_type L1Mask[n+1]; // L1Mask[i] contains a word with the i least significant bits set to 1.
+ // i.e. L1Mask[0] = 0, L1Mask[1] = 1,...
+ number_type O1Mask[n]; // O1Mask[i] contains a word with the i least significant bits set to 0.
+
+ impl() {
+ for (uint16_t k=0; k <= n; ++k) {
+ table[k][k] = 1; // initialize diagonal
+ }
+ for (uint16_t k=0; k <= n; ++k) {
+ table[0][k] = 0; // initialize first row
+ }
+ for (uint16_t nn=0; nn <= n; ++nn) {
+ table[nn][0] = 1; // initialize first column
+ }
+ for (int nn=1; nn<=n; ++nn) {
+ for (int k=1; k<=n; ++k) {
+ table[nn][k] = table[nn-1][k-1] + table[nn-1][k];
+ }
+ }
+ L1Mask[0] = 0;
+ number_type mask = 1;
+ O1Mask[0] = 1;
+ for (int i=1; i<=n; ++i) {
+ L1Mask[i] = mask;
+ if (i < n)
+ O1Mask[i] = O1Mask[i-1]<<1;
+ mask = (mask << 1);
+ mask |= (number_type)1;
+ }
+ }
+ } data;
+};
+
+template<uint16_t n, class number_type>
+typename binomial_table<n,number_type>::impl binomial_table<n,number_type>::data;
+
+//! A struct for the binomial coefficients \f$ n \choose k \f$.
+/*!
+ * data.table[m][k] contains the number \f${m \choose k}\f$ for \f$ k\leq m\leq \leq n\f$.
+ * Size of data.table :
+ * Let \f$ maxlog = \lceil \log n \rceil \f$ and \f$ maxsize = 2^{maxlog} \f$
+ * then the tables requires \f$ maxsize^2\times \lceil n/8 rceil \f$ bytes space.
+ * Examples:
+ * n <= 64: 64*64*8 bytes = 4 kB * 8 = 32 kB
+ * 64 < n <= 128: 128*128*16 bytes = 16 kB * 16 = 256 kB
+ * 128 < n <= 256: 256*256*32 bytes = 64 kB * 32 = 2048 kB = 2 MB
+ * The table is shared now for all n's in on of these ranges.
+ *
+ * data.space[k] returns the bits needed to encode a value between [0..data.table[n][k]], given n and k.
+ * Size of data.space is \f$ (n+1) \times \lceil n/8 \rceil \f$ bytes. E.g. 64*8=512 bytes for n=63,
+ * 2kB for n=127, and 8kB for n=255.
+ *
+ * BINARY_SEARCH_THRESHOLD is equal to \f$ n/\lceil\log{n+1}\rceil \f$
+ * \pre The template parameter n should be in the range [7..256].
+ */
+template<uint16_t n>
+struct binomial_coefficients {
+ enum {MAX_LOG = (n>128 ? 8 : (n > 64 ? 7 : 6))};
+ static const uint16_t MAX_SIZE = (1 << MAX_LOG);
+ typedef binomial_coefficients_trait<MAX_LOG> trait;
+ typedef typename trait::number_type number_type;
+ typedef binomial_table<MAX_SIZE,number_type> tBinom;
+
+ static struct impl {
+ const number_type(&table)[MAX_SIZE+1][MAX_SIZE+1] = tBinom::data.table; // table for the binomial coefficients
+ uint16_t space[n+1]; // for entry i,j \lceil \log( {i \choose j}+1 ) \rceil
+#ifndef RRR_NO_BS
+ static const uint16_t BINARY_SEARCH_THRESHOLD = n/MAX_LOG;
+#else
+ static const uint16_t BINARY_SEARCH_THRESHOLD = 0;
+#endif
+ number_type(&L1Mask)[MAX_SIZE+1] = tBinom::data.L1Mask;
+ number_type(&O1Mask)[MAX_SIZE] = tBinom::data.O1Mask;
+
+ impl() {
+ static typename binomial_table<n,number_type>::impl tmp_data;
+ for (int k=0; k<=n; ++k) {
+ space[k] = (tmp_data.table[n][k] == (number_type)1) ? 0 : trait::hi(tmp_data.table[n][k]) + 1;
+ }
+ }
+ } data;
+};
+
+template<uint16_t n>
+typename binomial_coefficients<n>::impl binomial_coefficients<n>::data;
+
+//! Class to encode and decode binomial coefficients on the fly.
+/*!
+ * The basic encoding and decoding process is described in
+ * Gonzalo Navarro and Eliana Providel: Fast, Small, Simple Rank/Select on Bitmaps, SEA 2012
+ *
+ * Implemented optimizations in the decoding process:
+ * - Constant time handling for uniform blocks (only zeros or ones in the block)
+ * - Constant time handling for blocks contains only a single one bit.
+ * - Decode blocks with at most \f$ k<n\log(n) \f$ by a binary search for the ones.
+ * - For operations decode_popcount, decode_select, and decode_bit a block
+ * is only decoded as long as the query is not answered yet.
+ */
+template<uint16_t n>
+struct rrr_helper {
+ typedef binomial_coefficients<n> binomial; //!< The struct containing the binomial coefficients
+ typedef typename binomial::number_type number_type; //!< The used number type, e.g. uint64_t, uint128_t,...
+ typedef typename binomial::trait trait; //!< The number trait
+
+ //! Returns the space usage in bits of the binary representation of the number \f${n \choose k}\f$
+ static inline uint16_t space_for_bt(uint16_t i) {
+ return binomial::data.space[i];
+ }
+
+ template<class bit_vector_type>
+ static inline number_type decode_btnr(const bit_vector_type& bv,
+ typename bit_vector_type::size_type btnrp, uint16_t btnrlen) {
+ return trait::get_int(bv, btnrp, btnrlen);
+ }
+
+ template<class bit_vector_type>
+ static void set_bt(bit_vector_type& bv, typename bit_vector_type::size_type pos,
+ number_type bt, uint16_t space_for_bt) {
+ trait::set_int(bv, pos, bt, space_for_bt);
+ }
+
+ template<class bit_vector_type>
+ static inline uint16_t get_bt(const bit_vector_type& bv, typename bit_vector_type::size_type pos,
+ uint16_t block_size) {
+ return trait::popcount(trait::get_int(bv, pos, block_size));
+ }
+
+ static inline number_type bin_to_nr(number_type bin) {
+ if (bin == (number_type)0 or bin == binomial::data.L1Mask[n]) { // handle special case
+ return 0;
+ }
+ number_type nr = 0;
+ uint16_t k = trait::popcount(bin);
+ uint16_t nn = n; // size of the block
+ while (bin != (number_type)0) {
+ if (1ULL & bin) {
+ nr += binomial::data.table[nn-1][k];
+ --k; // go to the case (n-1, k-1)
+ }// else go to the case (n-1, k)
+ bin = (bin >> 1);
+ --nn;
+ }
+ return nr;
+ }
+
+ //! Decode the bit at position \f$ off \f$ of the block encoded by the pair (k, nr).
+ static inline bool decode_bit(uint16_t k, number_type nr, uint16_t off) {
+#ifndef RRR_NO_OPT
+ if (k == n) { // if n==k, then the encoded block consists only of ones
+ return 1;
+ } else if (k == 0) { // if k==0 then the encoded block consists only of zeros
+ return 0;
+ } else if (k == 1) { // if k==1 then the encoded block contains exactly on set bit at
+ return (n-nr-1) == off; // position n-nr-1
+ }
+#endif
+ uint16_t nn = n;
+ // if k < n \log n, it is better to do a binary search for each of the on bits
+ if (k+1 < binomial::data.BINARY_SEARCH_THRESHOLD+1) {
+ while (k > 1) {
+ uint16_t nn_lb = k, nn_rb = nn+1; // invariant nr >= binomial::data.table[nn_lb-1][k]
+ while (nn_lb < nn_rb) {
+ uint16_t nn_mid = (nn_lb + nn_rb) / 2;
+ if (nr >= binomial::data.table[nn_mid-1][k]) {
+ nn_lb = nn_mid+1;
+ } else {
+ nn_rb = nn_mid;
+ }
+ }
+ nn = nn_lb-1;
+ if (n-nn >= off) {
+ return (n-nn) == off;
+ }
+ nr -= binomial::data.table[nn-1][k];
+ --k;
+ --nn;
+ }
+ } else { // else do a linear decoding
+ int i = 0;
+ while (k > 1) {
+ if (i > off) {
+ return 0;
+ }
+ if (nr >= binomial::data.table[nn-1][k]) {
+ nr -= binomial::data.table[nn-1][k];
+ --k;
+ if (i == off)
+ return 1;
+ }
+ --nn;
+ ++i;
+ }
+ }
+ return (n-nr-1) == off;
+ }
+
+ //! Decode the len-bit integer starting at position \f$ off \f$ of the block encoded by the pair (k, nr).
+ static inline uint64_t decode_int(uint16_t k, number_type nr, uint16_t off, uint16_t len) {
+#ifndef RRR_NO_OPT
+ if (k == n) { // if n==k, then the encoded block consists only of ones
+ return bits::lo_set[len];
+ } else if (k == 0) { // if k==0 then the encoded block consists only of zeros
+ return 0;
+ } else if (k == 1) { // if k==1 then the encoded block contains exactly on set bit at
+ if (n-nr-1 >= (number_type)off and n-nr-1 <= (number_type)(off+len-1)) {
+ return 1ULL << ((n-nr-1)-off);
+ } else
+ return 0;
+ }
+#endif
+ uint64_t res = 0;
+ uint16_t nn = n;
+ int i = 0;
+ while (k > 1) {
+ if (i > off+len-1) {
+ return res;
+ }
+ if (nr >= binomial::data.table[nn-1][k]) {
+ nr -= binomial::data.table[nn-1][k];
+ --k;
+ if (i >= off)
+ res |= 1ULL << (i-off);
+ }
+ --nn;
+ ++i;
+ }
+ if (n-nr-1 >= (number_type)off and n-nr-1 <= (number_type)(off+len-1)) {
+ res |= 1ULL << ((n-nr-1)-off);
+ }
+ return res;
+ }
+
+
+ //! Decode the first off bits bits of the block encoded by the pair (k, nr) and return the set bits.
+ static inline uint16_t decode_popcount(uint16_t k, number_type nr, uint16_t off) {
+#ifndef RRR_NO_OPT
+ if (k == n) { // if n==k, then the encoded block consists only of ones
+ return off; // i.e. the answer is off
+ } else if (k == 0) { // if k==0, then the encoded block consists only on zeros
+ return 0; // i.e. the result is zero
+ } else if (k == 1) { // if k==1 then the encoded block contains exactly on set bit at
+ return (n-nr-1) < off; // position n-nr-1, and popcount is 1 if off > (n-nr-1).
+ }
+#endif
+ uint16_t result = 0;
+ uint16_t nn = n;
+ // if k < n \log n, it is better to do a binary search for each of the on bits
+ if (k+1 < binomial::data.BINARY_SEARCH_THRESHOLD+1) {
+ while (k > 1) {
+ uint16_t nn_lb = k, nn_rb = nn+1; // invariant nr >= binomial::data.table[nn_lb-1][k]
+ while (nn_lb < nn_rb) {
+ uint16_t nn_mid = (nn_lb + nn_rb) / 2;
+ if (nr >= binomial::data.table[nn_mid-1][k]) {
+ nn_lb = nn_mid+1;
+ } else {
+ nn_rb = nn_mid;
+ }
+ }
+ nn = nn_lb-1;
+ if (n-nn >= off) {
+ return result;
+ }
+ ++result;
+ nr -= binomial::data.table[nn-1][k];
+ --k;
+ --nn;
+ }
+ } else {
+ int i = 0;
+ while (k > 1) {
+ if (i >= off) {
+ return result;
+ }
+ if (nr >= binomial::data.table[nn-1][k]) {
+ nr -= binomial::data.table[nn-1][k];
+ --k;
+ ++result;
+ }
+ --nn;
+ ++i;
+ }
+ }
+ return result + ((n-nr-1) < off);
+ }
+
+ /*! \pre k >= sel, sel>0
+ */
+ static inline uint16_t decode_select(uint16_t k, number_type& nr, uint16_t sel) {
+#ifndef RRR_NO_OPT
+ if (k == n) { // if n==k, then the encoded block consists only of ones
+ return sel-1;
+ } else if (k == 1 and sel == 1) {
+ return n-nr-1;
+ }
+#endif
+ uint16_t nn = n;
+ // if k < n \log n, it is better to do a binary search for each of the on bits
+ if (sel+1 < binomial::data.BINARY_SEARCH_THRESHOLD+1) {
+ while (sel > 0) {
+ uint16_t nn_lb = k, nn_rb = nn+1; // invariant nr >= iii.m_coefficients[nn_lb-1]
+ while (nn_lb < nn_rb) {
+ uint16_t nn_mid = (nn_lb + nn_rb) / 2;
+ if (nr >= binomial::data.table[nn_mid-1][k]) {
+ nn_lb = nn_mid+1;
+ } else {
+ nn_rb = nn_mid;
+ }
+ }
+ nn = nn_lb-1;
+ nr -= binomial::data.table[nn-1][k];
+ --sel;
+ --nn;
+ --k;
+ }
+ return n-nn-1;
+ } else {
+ int i = 0;
+ while (sel > 0) { // TODO: this condition only work if the precondition holds
+ if (nr >= binomial::data.table[nn-1][k]) {
+ nr -= binomial::data.table[nn-1][k];
+ --sel;
+ --k;
+ }
+ --nn;
+ ++i;
+ }
+ return i-1;
+ }
+ }
+
+ /*! \pre k >= sel, sel>0
+ */
+ template<uint8_t pattern, uint8_t len>
+ static inline uint16_t decode_select_bitpattern(uint16_t k, number_type& nr, uint16_t sel) {
+ int i = 0;
+ uint8_t decoded_pattern = 0;
+ uint8_t decoded_len = 0;
+ uint16_t nn = n;
+ while (sel > 0) { // TODO: this condition only work if the precondition holds
+ decoded_pattern = decoded_pattern<<1;
+ ++decoded_len;
+ if (nr >= binomial::data.table[nn-1][k]) {
+ nr -= binomial::data.table[nn-1][k];
+ // a one is decoded
+ decoded_pattern |= 1; // add to the pattern
+ --k;
+ }
+ --nn;
+ ++i;
+ if (decoded_len == len) { // if decoded pattern length equals len of the searched pattern
+ if (decoded_pattern == pattern) { // and pattern equals the searched pattern
+ --sel;
+ }
+ decoded_pattern = 0; decoded_len = 0; // reset pattern
+ }
+ }
+ return i-len; // return the starting position of $sel$th occurence of the pattern
+ }
+
+};
+
+} // end namespace
+#endif
diff --git a/include/sdsl/rrr_vector.hpp b/include/sdsl/rrr_vector.hpp
new file mode 100644
index 0000000..6f8914a
--- /dev/null
+++ b/include/sdsl/rrr_vector.hpp
@@ -0,0 +1,648 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rrr_vector.hpp
+ \brief rrr_vector.hpp contains the sdsl::rrr_vector class, and
+ classes which support rank and select for rrr_vector.
+ \author Simon Gog, Matthias Petri
+*/
+#ifndef INCLUDED_SDSL_RRR_VECTOR
+#define INCLUDED_SDSL_RRR_VECTOR
+
+#include "int_vector.hpp"
+#include "util.hpp"
+#include "rrr_helper.hpp" // for binomial helper class
+#include "iterators.hpp"
+#include <vector>
+#include <algorithm> // for next_permutation
+#include <iostream>
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+
+// forward declaration needed for friend declaration
+template<uint8_t t_b=1, uint16_t t_bs=15, class t_rac=int_vector<>, uint16_t t_k=32>
+class rank_support_rrr; // in rrr_vector
+
+// forward declaration needed for friend declaration
+template<uint8_t t_b=1, uint16_t t_bs=15, class t_rac=int_vector<>, uint16_t t_k=32>
+class select_support_rrr; // in rrr_vector
+
+//! A \f$H_0f$-compressed bitvector representation.
+/*!
+ * \tparam t_bs Size of a basic block.
+ * \tparam t_rac Random access integer vector. Use to store the block types.
+ * It is possible to use WTs for t_rac.
+ * \tparam t_k A rank sample value is stored before every t_k-th basic block.
+ *
+ * References:
+ * - Rasmus Pagh
+ * Low redundancy in dictionaries with O(1) worst case lookup time
+ * Technical Report 1998.
+ * ftp://ftp.cs.au.dk/BRICS/Reports/RS/98/28/BRICS-RS-98-28.pdf, Section 2.
+ * - Rajeev Raman, V. Raman and S. Srinivasa Rao
+ * Succinct Indexable Dictionaries with Applications to representations
+ * of k-ary trees and multi-sets.
+ * SODA 2002.
+ * - Francisco Claude, Gonzalo Navarro:
+ * Practical Rank/Select Queries over Arbitrary Sequences.
+ * SPIRE 2008: 176-187
+ * - On the fly-decoding and encoding was discovered in;
+ * Gonzalo Navarro, Eliana Providel:
+ * Fast, Small, Simple Rank/Select on Bitmaps.
+ * SEA 2012
+ *
+ * In this version the block size can be adjust by the template parameter t_bs!
+ * \sa sdsl::rrr_vector for a specialized version for block_size=15
+ */
+template<uint16_t t_bs=63, class t_rac=int_vector<>, uint16_t t_k=32>
+class rrr_vector
+{
+ static_assert(t_bs >= 3 and t_bs <= 256 , "rrr_vector: block size t_bs must be 3 <= t_bs <= 256.");
+ static_assert(t_k > 1, "rrr_vector: t_k must be > 0.");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef bit_vector::value_type value_type;
+ typedef bit_vector::difference_type difference_type;
+ typedef t_rac rac_type;
+ typedef random_access_const_iterator<rrr_vector> iterator;
+ typedef bv_tag index_category;
+
+ typedef rank_support_rrr<1, t_bs, t_rac, t_k> rank_1_type;
+ typedef rank_support_rrr<0, t_bs, t_rac, t_k> rank_0_type;
+ typedef select_support_rrr<1, t_bs, t_rac, t_k> select_1_type;
+ typedef select_support_rrr<0, t_bs, t_rac, t_k> select_0_type;
+
+ friend class rank_support_rrr<0, t_bs, t_rac, t_k>;
+ friend class rank_support_rrr<1, t_bs, t_rac, t_k>;
+ friend class select_support_rrr<0, t_bs, t_rac, t_k>;
+ friend class select_support_rrr<1, t_bs, t_rac, t_k>;
+
+ typedef rrr_helper<t_bs> rrr_helper_type;
+ typedef typename rrr_helper_type::number_type number_type;
+
+ enum { block_size = t_bs };
+ private:
+ size_type m_size = 0; // Size of the original bit_vector.
+ rac_type m_bt; // Vector for the block types (bt). bt equals the
+ // number of set bits in the block.
+ bit_vector m_btnr; // Compressed block type numbers.
+ int_vector<> m_btnrp; // Sample pointers into m_btnr.
+ int_vector<> m_rank; // Sample rank values.
+ bit_vector m_invert; // Specifies if a superblock (i.e. t_k blocks)
+ // have to be considered as inverted i.e. 1 and
+ // 0 are swapped
+
+ void copy(const rrr_vector& rrr) {
+ m_size = rrr.m_size;
+ m_bt = rrr.m_bt;
+ m_btnr = rrr.m_btnr;
+ m_btnrp = rrr.m_btnrp;
+ m_rank = rrr.m_rank;
+ m_invert = rrr.m_invert;
+ }
+
+ public:
+ const rac_type& bt = m_bt;
+ const bit_vector& btnr = m_btnr;
+
+ //! Default constructor
+ rrr_vector() {};
+
+ //! Copy constructor
+ rrr_vector(const rrr_vector& rrr) {
+ copy(rrr);
+ }
+
+ //! Move constructor
+ rrr_vector(rrr_vector&& rrr) : m_size(std::move(rrr.m_size)),
+ m_bt(std::move(rrr.m_bt)),
+ m_btnr(std::move(rrr.m_btnr)), m_btnrp(std::move(rrr.m_btnrp)),
+ m_rank(std::move(rrr.m_rank)), m_invert(std::move(rrr.m_invert)) {}
+
+ //! Constructor
+ /*!
+ * \param bv Uncompressed bitvector.
+ * \param k Store rank samples and pointers each k-th blocks.
+ */
+ rrr_vector(const bit_vector& bv) {
+ m_size = bv.size();
+ int_vector<> bt_array;
+ bt_array.width(bits::hi(t_bs)+1);
+ bt_array.resize((m_size+t_bs)/((size_type)t_bs)); // blocks for the bt_array + a dummy block at the end,
+ // if m_size%t_bs == 0
+
+ // (1) calculate the block types and store them in m_bt
+ size_type pos = 0, i = 0, x;
+ size_type btnr_pos = 0;
+ size_type sum_rank = 0;
+ while (pos + t_bs <= m_size) { // handle all blocks full blocks
+ bt_array[ i++ ] = x = rrr_helper_type::get_bt(bv, pos, t_bs);
+ sum_rank += x;
+ btnr_pos += rrr_helper_type::space_for_bt(x);
+ pos += t_bs;
+ }
+ if (pos < m_size) { // handle last not full block
+ bt_array[ i++ ] = x = rrr_helper_type::get_bt(bv, pos, m_size - pos);
+ sum_rank += x;
+ btnr_pos += rrr_helper_type::space_for_bt(x);
+ }
+ m_btnr = bit_vector(std::max(btnr_pos, (size_type)64), 0); // max necessary for case: t_bs == 1
+ m_btnrp = int_vector<>((bt_array.size()+t_k-1)/t_k, 0, bits::hi(btnr_pos)+1);
+ m_rank = int_vector<>((bt_array.size()+t_k-1)/t_k + ((m_size % (t_k*t_bs))>0), 0, bits::hi(sum_rank)+1);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // only add a finishing block, if the last block of the superblock is not a dummy block
+ m_invert = bit_vector((bt_array.size()+t_k-1)/t_k, 0);
+
+ // (2) calculate block type numbers and pointers into btnr and rank samples
+ pos = 0; i = 0;
+ btnr_pos= 0, sum_rank = 0;
+ bool invert = false;
+ while (pos + t_bs <= m_size) { // handle all full blocks
+ if ((i % t_k) == (size_type)0) {
+ m_btnrp[ i/t_k ] = btnr_pos;
+ m_rank[ i/t_k ] = sum_rank;
+ // calculate invert bit for that superblock
+ if (i+t_k <= bt_array.size()) {
+ size_type gt_half_t_bs = 0; // counter for blocks greater than half of the blocksize
+ for (size_type j=i; j < i+t_k; ++j) {
+ if (bt_array[j] > t_bs/2)
+ ++gt_half_t_bs;
+ }
+ if (gt_half_t_bs > (t_k/2)) {
+ m_invert[ i/t_k ] = 1;
+ for (size_type j=i; j < i+t_k; ++j) {
+ bt_array[j] = t_bs - bt_array[j];
+ }
+ invert = true;
+ } else {
+ invert = false;
+ }
+ } else {
+ invert = false;
+ }
+ }
+ uint16_t space_for_bt = rrr_helper_type::space_for_bt(x=bt_array[i++]);
+ sum_rank += (invert ? (t_bs - x) : x);
+ if (space_for_bt) {
+ number_type bin = rrr_helper_type::decode_btnr(bv, pos, t_bs);
+ number_type nr = rrr_helper_type::bin_to_nr(bin);
+ rrr_helper_type::set_bt(m_btnr, btnr_pos, nr, space_for_bt);
+ }
+ btnr_pos += space_for_bt;
+ pos += t_bs;
+ }
+ if (pos < m_size) { // handle last not full block
+ if ((i % t_k) == (size_type)0) {
+ m_btnrp[ i/t_k ] = btnr_pos;
+ m_rank[ i/t_k ] = sum_rank;
+ m_invert[ i/t_k ] = 0; // default: set last block to not inverted
+ invert = false;
+ }
+ uint16_t space_for_bt = rrr_helper_type::space_for_bt(x=bt_array[i++]);
+// no extra dummy block added to bt_array, therefore this condition should hold
+ assert(i == bt_array.size());
+ sum_rank += invert ? (t_bs - x) : x;
+ if (space_for_bt) {
+ number_type bin = rrr_helper_type::decode_btnr(bv, pos, m_size-pos);
+ number_type nr = rrr_helper_type::bin_to_nr(bin);
+ rrr_helper_type::set_bt(m_btnr, btnr_pos, nr, space_for_bt);
+ }
+ btnr_pos += space_for_bt;
+ assert(m_rank.size()-1 == ((i+t_k-1)/t_k));
+ } else { // handle last empty full block
+ assert(m_rank.size()-1 == ((i+t_k-1)/t_k));
+ }
+ // for technical reasons we add a last element to m_rank
+ m_rank[ m_rank.size()-1 ] = sum_rank; // sum_rank contains the total number of set bits in bv
+ m_bt = bt_array;
+ }
+
+ //! Swap method
+ void swap(rrr_vector& rrr) {
+ if (this != &rrr) {
+ std::swap(m_size, rrr.m_size);
+ m_bt.swap(rrr.m_bt);
+ m_btnr.swap(rrr.m_btnr);
+ m_btnrp.swap(rrr.m_btnrp);
+ m_rank.swap(rrr.m_rank);
+ m_invert.swap(rrr.m_invert);
+ }
+ }
+
+ //! Accessing the i-th element of the original bit_vector
+ /*! \param i An index i with \f$ 0 \leq i < size() \f$.
+ \return The i-th bit of the original bit_vector
+ */
+ value_type operator[](size_type i)const {
+ size_type bt_idx = i/t_bs;
+ uint16_t bt = m_bt[bt_idx];
+ size_type sample_pos = bt_idx/t_k;
+ if (m_invert[sample_pos])
+ bt = t_bs - bt;
+#ifndef RRR_NO_OPT
+ if (bt == 0 or bt == t_bs) { // very effective optimization
+ return bt>0;
+ }
+#endif
+ uint16_t off = i % t_bs; //i - bt_idx*t_bs;
+ size_type btnrp = m_btnrp[ sample_pos ];
+ for (size_type j = sample_pos*t_k; j < bt_idx; ++j) {
+ btnrp += rrr_helper_type::space_for_bt(m_bt[j]);
+ }
+ uint16_t btnrlen = rrr_helper_type::space_for_bt(bt);
+ number_type btnr = rrr_helper_type::decode_btnr(m_btnr, btnrp, btnrlen);
+ return rrr_helper_type::decode_bit(bt, btnr, off);
+ }
+
+ //! Get the integer value of the binary string of length len starting at position idx.
+ /*! \param idx Starting index of the binary representation of the integer.
+ * \param len Length of the binary representation of the integer. Default value is 64.
+ * \returns The integer value of the binary string of length len starting at position idx.
+ *
+ * \pre idx+len-1 in [0..size()-1]
+ * \pre len in [1..64]
+ */
+ uint64_t get_int(size_type idx, uint8_t len=64)const {
+ uint64_t res = 0;
+ size_type bb_idx = idx/t_bs; // begin block index
+ size_type bb_off = idx%t_bs; // begin block offset
+ uint16_t bt = m_bt[bb_idx];
+ size_type sample_pos = bb_idx/t_k;
+ size_type eb_idx = (idx+len-1)/t_bs; // end block index
+ if (bb_idx == eb_idx) { // extract only in one block
+ if (m_invert[sample_pos])
+ bt = t_bs - bt;
+ if (bt == 0) { // all bits are zero
+ res = 0;
+ } else if (bt == t_bs and t_bs <= 64) { // all bits are zero
+ res = bits::lo_set[len];
+ } else {
+ size_type btnrp = m_btnrp[ sample_pos ];
+ for (size_type j = sample_pos*t_k; j < bb_idx; ++j) {
+ btnrp += rrr_helper_type::space_for_bt(m_bt[j]);
+ }
+ uint16_t btnrlen = rrr_helper_type::space_for_bt(bt);
+ number_type btnr = rrr_helper_type::decode_btnr(m_btnr, btnrp, btnrlen);
+ res = rrr_helper_type::decode_int(bt, btnr, bb_off, len);
+ }
+ } else { // solve multiple block case by recursion
+ uint16_t b_len = t_bs-bb_off; // remaining bits in first block
+ uint16_t b_len_sum = 0;
+ do {
+ res |= get_int(idx, b_len) << b_len_sum;
+ idx += b_len;
+ b_len_sum += b_len;
+ len -= b_len;
+ b_len = t_bs;
+ b_len = std::min((uint16_t)len, b_len);
+ } while (len > 0);
+ }
+ return res;
+ }
+
+ //! Assignment operator
+ rrr_vector& operator=(const rrr_vector& rrr) {
+ if (this != &rrr) {
+ copy(rrr);
+ }
+ return *this;
+ }
+
+ //! Move assignment operator
+ rrr_vector& operator=(rrr_vector&& rrr) {
+ swap(rrr);
+ return *this;
+ }
+
+ //! Returns the size of the original bit vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Answers select queries
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += m_bt.serialize(out, child, "bt");
+ written_bytes += m_btnr.serialize(out, child, "btnr");
+ written_bytes += m_btnrp.serialize(out, child, "btnrp");
+ written_bytes += m_rank.serialize(out, child, "rank_samples");
+ written_bytes += m_invert.serialize(out, child, "invert");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ m_bt.load(in);
+ m_btnr.load(in);
+ m_btnrp.load(in);
+ m_rank.load(in);
+ m_invert.load(in);
+ }
+
+ iterator begin() const {
+ return iterator(this, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, size());
+ }
+};
+
+template<uint8_t t_bit_pattern>
+struct rank_support_rrr_trait {
+ typedef bit_vector::size_type size_type;
+ static size_type adjust_rank(size_type r, SDSL_UNUSED size_type n) {
+ return r;
+ }
+};
+
+template<>
+struct rank_support_rrr_trait<0> {
+ typedef bit_vector::size_type size_type;
+ static size_type adjust_rank(size_type r, size_type n) {
+ return n - r;
+ }
+};
+
+//! rank_support for the rrr_vector class
+/*!
+* \tparam t_b The bit pattern of size one. (so `0` or `1`)
+* \tparam t_bs The block size of the corresponding rrr_vector
+* \tparam t_rac Type used to store the block type in the corresponding rrr_vector.
+* TODO: Test if the binary search can be speed up by
+* saving the (n/2)-th rank value in T[0], the (n/4)-th in T[1],
+* the (3n/4)-th in T[2],... for small number of rank values
+* is this called hinted binary search???
+* or is this called
+*/
+template<uint8_t t_b, uint16_t t_bs, class t_rac, uint16_t t_k>
+class rank_support_rrr
+{
+ static_assert(t_b == 1u or t_b == 0u , "rank_support_rrr: bit pattern must be `0` or `1`");
+ public:
+ typedef rrr_vector<t_bs, t_rac, t_k> bit_vector_type;
+ typedef typename bit_vector_type::size_type size_type;
+ typedef typename bit_vector_type::rrr_helper_type rrr_helper_type;
+ typedef typename rrr_helper_type::number_type number_type;
+ enum { bit_pat = t_b };
+
+ private:
+ const bit_vector_type* m_v; //!< Pointer to the rank supported rrr_vector
+
+ public:
+ //! Standard constructor
+ /*! \param v Pointer to the rrr_vector, which should be supported
+ */
+ explicit rank_support_rrr(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Answers rank queries
+ /*! \param i Argument for the length of the prefix v[0..i-1], with \f$0\leq i \leq size()\f$.
+ \returns Number of 1-bits in the prefix [0..i-1] of the original bit_vector.
+ \par Time complexity
+ \f$ \Order{ sample\_rate of the rrr\_vector} \f$
+ */
+ const size_type rank(size_type i)const {
+ assert(m_v != nullptr);
+ assert(i <= m_v->size());
+ size_type bt_idx = i/t_bs;
+ size_type sample_pos = bt_idx/t_k;
+ size_type btnrp = m_v->m_btnrp[ sample_pos ];
+ size_type rank = m_v->m_rank[ sample_pos ];
+ if (sample_pos+1 < m_v->m_rank.size()) {
+ size_type diff_rank = m_v->m_rank[ sample_pos+1 ] - rank;
+#ifndef RRR_NO_OPT
+ if (diff_rank == (size_type)0) {
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank, i);
+ } else if (diff_rank == (size_type)t_bs*t_k) {
+ return rank_support_rrr_trait<t_b>::adjust_rank(
+ rank + i - sample_pos*t_k*t_bs, i);
+ }
+#endif
+ }
+ const bool inv = m_v->m_invert[ sample_pos ];
+ for (size_type j = sample_pos*t_k; j < bt_idx; ++j) {
+ uint16_t r = m_v->m_bt[j];
+ rank += (inv ? t_bs - r: r);
+ btnrp += rrr_helper_type::space_for_bt(r);
+ }
+ uint16_t off = i % t_bs;
+ if (!off) { // needed for special case: if i=size() is a multiple of t_bs
+ // the access to m_bt would cause a invalid memory access
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank, i);
+ }
+ uint16_t bt = inv ? t_bs - m_v->m_bt[ bt_idx ] : m_v->m_bt[ bt_idx ];
+
+ uint16_t btnrlen = rrr_helper_type::space_for_bt(bt);
+ number_type btnr = rrr_helper_type::decode_btnr(m_v->m_btnr, btnrp, btnrlen);
+ uint16_t popcnt = rrr_helper_type::decode_popcount(bt, btnr, off);
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank + popcnt, i);
+ }
+
+ //! Short hand for rank(i)
+ const size_type operator()(size_type i)const {
+ return rank(i);
+ }
+
+ //! Returns the size of the original vector
+ const size_type size()const {
+ return m_v->size();
+ }
+
+ //! Set the supported vector.
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ rank_support_rrr& operator=(const rank_support_rrr& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(rank_support_rrr&) { }
+
+ //! Load the data structure from a stream and set the supported vector.
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Serializes the data structure into a stream.
+ size_type serialize(std::ostream&, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ structure_tree::add_size(child, 0);
+ return 0;
+ }
+};
+
+
+//! Select support for the rrr_vector class.
+/*
+* \tparam t_b The bit pattern of size one. (so `0` or `1`)
+* \tparam t_bs The block size of the corresponding rrr_vector
+* \tparam t_rac Type used to store the block type in the corresponding rrr_vector.
+*
+* Possible TODO: Add heap which contains the 10 first items of
+* each binary search could increase performance.
+* Experiments on select_support_interleaved showed about
+* 25%.
+*/
+template<uint8_t t_b, uint16_t t_bs, class t_rac, uint16_t t_k>
+class select_support_rrr
+{
+ static_assert(t_b == 1u or t_b == 0u , "select_support_rrr: bit pattern must be `0` or `1`");
+ public:
+ typedef rrr_vector<t_bs, t_rac, t_k> bit_vector_type;
+ typedef typename bit_vector_type::size_type size_type;
+ typedef typename bit_vector_type::rrr_helper_type rrr_helper_type;
+ typedef typename rrr_helper_type::number_type number_type;
+ enum { bit_pat = t_b };
+ private:
+ const bit_vector_type* m_v; //!< Pointer to the rank supported rrr_vector
+
+ size_type select1(size_type i)const {
+ if (m_v->m_rank[m_v->m_rank.size()-1] < i)
+ return size();
+ // (1) binary search for the answer in the rank_samples
+ size_type begin=0, end=m_v->m_rank.size()-1; // min included, max excluded
+ size_type idx, rank;
+ // invariant: m_rank[end] >= i
+ // m_rank[begin] < i
+ while (end-begin > 1) {
+ idx = (begin+end) >> 1; // idx in [0..m_rank.size()-1]
+ rank = m_v->m_rank[idx];
+ if (rank >= i)
+ end = idx;
+ else { // rank < i
+ begin = idx;
+ }
+ }
+ // (2) linear search between the samples
+ rank = m_v->m_rank[begin]; // now i>rank
+ idx = begin * t_k; // initialize idx for select result
+ size_type diff_rank = m_v->m_rank[end] - rank;
+#ifndef RRR_NO_OPT
+ if (diff_rank == (size_type)t_bs*t_k) {// optimisation for select<1>
+ return idx*t_bs + i-rank -1;
+ }
+#endif
+ const bool inv = m_v->m_invert[ begin ];
+ size_type btnrp = m_v->m_btnrp[ begin ];
+ uint16_t bt = 0, btnrlen = 0; // temp variables for block_type and space for block type
+ while (i > rank) {
+ bt = m_v->m_bt[idx++]; bt = inv ? t_bs-bt : bt;
+ rank += bt;
+ btnrp += (btnrlen=rrr_helper_type::space_for_bt(bt));
+ }
+ rank -= bt;
+ number_type btnr = rrr_helper_type::decode_btnr(m_v->m_btnr, btnrp-btnrlen, btnrlen);
+ return (idx-1) * t_bs + rrr_helper_type::decode_select(bt, btnr, i-rank);
+ }
+
+ size_type select0(size_type i)const {
+ if ((size() - m_v->m_rank[m_v->m_rank.size()-1]) < i) {
+ return size();
+ }
+ // (1) binary search for the answer in the rank_samples
+ size_type begin=0, end=m_v->m_rank.size()-1; // min included, max excluded
+ size_type idx, rank;
+ // invariant: m_rank[end] >= i
+ // m_rank[begin] < i
+ while (end-begin > 1) {
+ idx = (begin+end) >> 1; // idx in [0..m_rank.size()-1]
+ rank = idx*t_bs*t_k - m_v->m_rank[idx];
+ if (rank >= i)
+ end = idx;
+ else { // rank < i
+ begin = idx;
+ }
+ }
+ // (2) linear search between the samples
+ rank = begin*t_bs*t_k - m_v->m_rank[begin]; // now i>rank
+ idx = begin * t_k; // initialize idx for select result
+ if (m_v->m_rank[end] == m_v->m_rank[begin]) { // only for select<0>
+ return idx*t_bs + i-rank -1;
+ }
+ const bool inv = m_v->m_invert[ begin ];
+ size_type btnrp = m_v->m_btnrp[ begin ];
+ uint16_t bt = 0, btnrlen = 0; // temp variables for block_type and space for block type
+ while (i > rank) {
+ bt = m_v->m_bt[idx++]; bt = inv ? t_bs-bt : bt;
+ rank += (t_bs-bt);
+ btnrp += (btnrlen=rrr_helper_type::space_for_bt(bt));
+ }
+ rank -= (t_bs-bt);
+ number_type btnr = rrr_helper_type::decode_btnr(m_v->m_btnr, btnrp-btnrlen, btnrlen);
+ return (idx-1) * t_bs + rrr_helper_type::template decode_select_bitpattern<0, 1>(bt, btnr, i-rank);
+ }
+
+
+
+ public:
+ explicit select_support_rrr(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Answers select queries
+ size_type select(size_type i)const {
+ return t_b ? select1(i) : select0(i);
+ }
+
+ const size_type operator()(size_type i)const {
+ return select(i);
+ }
+
+ const size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ select_support_rrr& operator=(const select_support_rrr& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(select_support_rrr&) { }
+
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream&, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ structure_tree::add_size(child, 0);
+ return 0;
+ }
+};
+
+}// end namespace sdsl
+#include "rrr_vector_15.hpp" // include specialization
+
+#endif
diff --git a/include/sdsl/rrr_vector_15.hpp b/include/sdsl/rrr_vector_15.hpp
new file mode 100644
index 0000000..d64d387
--- /dev/null
+++ b/include/sdsl/rrr_vector_15.hpp
@@ -0,0 +1,683 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file rrr_vector.hpp
+ \brief rrr_vector.hpp contains a specialisation of the sdsl::rrr_vector class,
+ with block size k=15 and lookup table access.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_RRR_VECTOR_15
+#define INCLUDED_SDSL_RRR_VECTOR_15
+
+#include "int_vector.hpp"
+#include "util.hpp"
+#include "rrr_helper.hpp" // for binomial helper class
+#include "rrr_vector.hpp"
+#include "iterators.hpp"
+#include <vector>
+#include <algorithm> // for next_permutation
+#include <iostream>
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+
+// Helper class for the binomial coefficients \f$ 15 \choose k \f$
+/*
+ * Size of lookup tables:
+ * * m_nr_to_bin: 64 kB = (2^15 entries x 2 bytes)
+ * * m_bin_to_nr: 64 kB = (2^15 entries x 2 bytes)
+ */
+class binomial15
+{
+ public:
+ typedef uint32_t number_type;
+ private:
+
+ static class impl
+ {
+ public:
+ static const int n = 15;
+ static const int MAX_SIZE=32;
+ uint8_t m_space_for_bt[16];
+ uint8_t m_space_for_bt_pair[256];
+ uint64_t m_C[MAX_SIZE];
+ int_vector<16> m_nr_to_bin;
+ int_vector<16> m_bin_to_nr;
+
+ impl() {
+ m_nr_to_bin.resize(1<<n);
+ m_bin_to_nr.resize(1<<n);
+ for (int i=0, cnt=0, class_cnt=0; i<=n; ++i) {
+ m_C[i] = cnt;
+ class_cnt = 0;
+ std::vector<bool> b(n,0);
+ for (int j=0; j<i; ++j) b[n-j-1] = 1;
+ do {
+ uint32_t x=0;
+ for (int k=0; k<n; ++k)
+ x |= ((uint32_t)b[n-k-1])<<(n-1-k);
+ m_nr_to_bin[cnt] = x;
+ m_bin_to_nr[x] = class_cnt;
+ ++cnt;
+ ++class_cnt;
+ } while (next_permutation(b.begin(), b.end()));
+ if (class_cnt == 1)
+ m_space_for_bt[i] = 0;
+ else
+ m_space_for_bt[i] = bits::hi(class_cnt)+1;
+ }
+ if (n == 15) {
+ for (int x=0; x<256; ++x) {
+ m_space_for_bt_pair[x] = m_space_for_bt[x>>4] + m_space_for_bt[x&0x0F];
+ }
+ }
+ }
+ } iii;
+
+ public:
+
+ static inline uint8_t space_for_bt(uint32_t i) {
+ return iii.m_space_for_bt[i];
+ }
+
+ static inline uint32_t nr_to_bin(uint8_t k, uint32_t nr) {
+ return iii.m_nr_to_bin[iii.m_C[k]+nr];
+ }
+
+ static inline uint32_t bin_to_nr(uint32_t bin) {
+ return iii.m_bin_to_nr[bin];
+ }
+
+ static inline uint8_t space_for_bt_pair(uint8_t x) {
+ return iii.m_space_for_bt_pair[x];
+ }
+};
+
+
+//! A specialization of the rrr_vector class for a block_size of 15.
+/*!
+ * \tparam t_rac Random access integer vector. Use to store the block types.
+ *
+ * Several tricks were used to speed-up the operations:
+ * * Whenever possible 2 4-bit blocks are decoded at once.
+ * * When the rank position lies in a block which consists only of zeros or
+ * ones (a uniform block), then we only have to sum up the values of the
+ * block type array between the last sampled position and the
+ * destination block. That can be done by using bit-parallelism on
+ * 64-bit words.
+*/
+template<class t_rac, uint16_t t_k>
+class rrr_vector<15, t_rac, t_k>
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef bit_vector::value_type value_type;
+ typedef bit_vector::difference_type difference_type;
+ typedef t_rac rac_type;
+ typedef random_access_const_iterator<rrr_vector> iterator;
+ typedef bv_tag index_category;
+
+ friend class rank_support_rrr<0, 15, t_rac, t_k>;
+ friend class rank_support_rrr<1, 15, t_rac, t_k>;
+ friend class select_support_rrr<0, 15, t_rac, t_k>;
+ friend class select_support_rrr<1, 15, t_rac, t_k>;
+
+ typedef rank_support_rrr<1, 15, t_rac, t_k> rank_1_type;
+ typedef rank_support_rrr<0, 15, t_rac, t_k> rank_0_type;
+ typedef select_support_rrr<1, 15, t_rac, t_k> select_1_type;
+ typedef select_support_rrr<0, 15, t_rac, t_k> select_0_type;
+
+ enum { block_size = 15 };
+ typedef binomial15 bi_type;
+ private:
+ size_type m_size = 0; // Size of the original bit_vector.
+ rac_type m_bt; // Vector for block types (bt). bt equals the
+ // number of set bits in the block.
+ bit_vector m_btnr; // Compressed block type numbers.
+ int_vector<> m_btnrp; // Sample pointers into m_btnr.
+ int_vector<> m_rank; // Sample rank values.
+
+ void copy(const rrr_vector& rrr) {
+ m_size = rrr.m_size;
+ m_bt = rrr.m_bt;
+ m_btnr = rrr.m_btnr;
+ m_btnrp = rrr.m_btnrp;
+ m_rank = rrr.m_rank;
+ }
+ public:
+ const rac_type& bt = m_bt;
+ const bit_vector& btnr = m_btnr;
+
+ //! Default constructor
+ /*! \param k Store rank samples and pointers each k-th blocks.
+ */
+ rrr_vector() {};
+
+ //! Copy constructor
+ rrr_vector(const rrr_vector& rrr) {
+ copy(rrr);
+ }
+
+ //! Move constructor
+ rrr_vector(rrr_vector&& rrr) : m_size(std::move(rrr.m_size)),
+ m_bt(std::move(rrr.m_bt)),
+ m_btnr(std::move(rrr.m_btnr)), m_btnrp(std::move(rrr.m_btnrp)),
+ m_rank(std::move(rrr.m_rank)) {}
+
+ //! Constructor
+ /*!
+ * \param bv Uncompressed bitvector.
+ * \param k Store rank samples and pointers each k-th blocks.
+ */
+ rrr_vector(const bit_vector& bv) {
+ m_size = bv.size();
+ int_vector<> bt_array;
+ bt_array = int_vector<>(m_size/block_size+1, 0, bits::hi(block_size)+1);
+
+ // (1) calculate the block types and store them in m_bt
+ size_type pos = 0, i = 0, x;
+ size_type btnr_pos = 0;
+ size_type sum_rank = 0;
+ while (pos + block_size <= m_size) { // handle all full blocks
+ bt_array[ i++ ] = x = bits::cnt(bv.get_int(pos, block_size));
+ sum_rank += x;
+ btnr_pos += bi_type::space_for_bt(x);
+ pos += block_size;
+ }
+ if (pos < m_size) { // handle last full block
+ bt_array[ i++ ] = x = bits::cnt(bv.get_int(pos, m_size - pos));
+ sum_rank += x;
+ btnr_pos += bi_type::space_for_bt(x);
+ }
+ m_btnr = bit_vector(std::max(btnr_pos, (size_type)64), 0); // max necessary for case: block_size == 1
+ m_btnrp = int_vector<>((bt_array.size()+t_k-1)/t_k, 0, bits::hi(btnr_pos)+1);
+
+ m_rank = int_vector<>((bt_array.size()+t_k-1)/t_k + ((m_size % (t_k*block_size))>0), 0, bits::hi(sum_rank)+1);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // only add a finishing block, if the last block of the superblock is not a dummy block
+ // (2) calculate block type numbers and pointers into btnr and rank samples
+ pos = 0; i = 0;
+ btnr_pos= 0, sum_rank = 0;
+ while (pos + block_size <= m_size) { // handle all full blocks
+ if ((i % t_k) == 0) {
+ m_btnrp[ i/t_k ] = btnr_pos;
+ m_rank[ i/t_k ] = sum_rank;
+ }
+ uint16_t space_for_bt = bi_type::space_for_bt(x=bt_array[i++]);
+ sum_rank += x;
+ if (space_for_bt) {
+ m_btnr.set_int(btnr_pos, bi_type::bin_to_nr(bv.get_int(pos, block_size)), space_for_bt);
+ }
+ btnr_pos += space_for_bt;
+ pos += block_size;
+ }
+ if (pos < m_size) { // handle last not full block
+ if ((i % t_k) == 0) {
+ m_btnrp[ i/t_k ] = btnr_pos;
+ m_rank[ i/t_k ] = sum_rank;
+ }
+ uint16_t space_for_bt = bi_type::space_for_bt(x=bt_array[i++]);
+ sum_rank += x;
+ if (space_for_bt) {
+ m_btnr.set_int(btnr_pos, bi_type::bin_to_nr(bv.get_int(pos, m_size - pos)), space_for_bt);
+ }
+ btnr_pos += space_for_bt;
+ assert(m_rank.size()-1 == ((i+t_k-1)/t_k));
+ } else { // handle last empty full block
+ assert(m_rank.size()-1 == ((i+t_k-1)/t_k));
+ }
+ // for technical reasons add an additional element to m_rank
+ m_rank[ m_rank.size()-1 ] = sum_rank; // sum_rank contains the total number of set bits in bv
+ m_bt = rac_type(std::move(bt_array));
+ }
+
+ //! Swap method
+ void swap(rrr_vector& rrr) {
+ if (this != &rrr) {
+ std::swap(m_size, rrr.m_size);
+ m_bt.swap(rrr.m_bt);
+ m_btnr.swap(rrr.m_btnr);
+ m_btnrp.swap(rrr.m_btnrp);
+ m_rank.swap(rrr.m_rank);
+ }
+ }
+
+ //! Accessing the i-th element of the original bit_vector
+ /*! \param i An index i with \f$ 0 \leq i < size() \f$.
+ \return The i-th bit of the original bit_vector
+ */
+ value_type operator[](size_type i)const {
+ size_type bt_idx = i/block_size ;
+ uint8_t* bt = (uint8_t*)(m_bt.data());
+ uint32_t i_bt = *(bt + (bt_idx/2));
+ if (bt_idx%2 == 1) {
+ i_bt >>= 4;
+ } else {
+ i_bt &= 0x0F;
+ }
+ if (i_bt == 0 or i_bt == block_size) {
+ return i_bt > 0;
+ }
+ size_type sample_pos = bt_idx/t_k;
+ size_type btnrp = m_btnrp[ sample_pos ];
+ size_type j = (sample_pos*t_k);
+ bt += j/2;
+ if (j%2 == 1 and j < bt_idx) {
+ btnrp += bi_type::space_for_bt((*bt++)>>4);
+ ++j;
+ }
+ while (j+1 < bt_idx) {
+ btnrp += bi_type::space_for_bt_pair(*(bt++)); // decode two entries at once
+ j+=2;
+ }
+ if (j < bt_idx) {
+ btnrp += bi_type::space_for_bt((*bt)&0x0F);
+ }
+
+ uint32_t btnr = m_btnr.get_int(btnrp, bi_type::space_for_bt(i_bt));
+
+ uint8_t off = (uint8_t)(i % block_size); //i - bt_idx*block_size;
+ return (bi_type::nr_to_bin(i_bt, btnr) >> off) & (uint32_t)1;
+ }
+
+ //! Get the integer value of the binary string of length len starting at position idx.
+ /*! \param idx Starting index of the binary representation of the integer.
+ * \param len Length of the binary representation of the integer. Default value is 64.
+ * \returns The integer value of the binary string of length len starting at position idx.
+ *
+ * \pre idx+len-1 in [0..size()-1]
+ * \pre len in [1..64]
+ */
+ uint64_t get_int(size_type idx, uint8_t len=64)const {
+ uint64_t res = 0;
+ size_type bb_idx = idx/block_size; // begin block index
+ size_type bb_off = idx%block_size; // begin block offset
+ uint16_t bt = m_bt[bb_idx];
+ size_type sample_pos = bb_idx/t_k;
+ size_type eb_idx = (idx+len-1)/block_size; // end block index
+ if (bb_idx == eb_idx) { // extract only in one block
+ if (bt == 0) { // all bits are zero
+ res = 0;
+ } else if (bt == block_size) { // all bits are zero
+ res = bits::lo_set[len];
+ } else {
+ size_type btnrp = m_btnrp[ sample_pos ];
+ for (size_type j = sample_pos*t_k; j < bb_idx; ++j) {
+ btnrp += bi_type::space_for_bt(m_bt[j]);
+ }
+ uint32_t btnr = m_btnr.get_int(btnrp, bi_type::space_for_bt(bt));
+ res = (bi_type::nr_to_bin(bt, btnr) >> bb_off) & bits::lo_set[len];
+ }
+ } else { // solve multiple block case by recursion
+ uint8_t b_len = block_size-bb_off;
+ uint8_t b_len_sum = 0;
+ do {
+ res |= get_int(idx, b_len) << b_len_sum;
+ idx += b_len;
+ b_len_sum += b_len;
+ len -= b_len;
+ b_len = block_size;
+ b_len = std::min(len, b_len);
+ } while (len > 0);
+ }
+ return res;
+ }
+
+
+ //! Assignment operator
+ rrr_vector& operator=(const rrr_vector& rrr) {
+ if (this != &rrr) {
+ copy(rrr);
+ }
+ return *this;
+ }
+
+ //! Move assignment
+ rrr_vector& operator=(rrr_vector&& rrr) {
+ swap(rrr);
+ return *this;
+ }
+
+ //! Returns the size of the original bit vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ size_type written_bytes = 0;
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += m_bt.serialize(out, child, "bt");
+ written_bytes += m_btnr.serialize(out, child, "btnr");
+ written_bytes += m_btnrp.serialize(out, child, "btnrp");
+ written_bytes += m_rank.serialize(out, child, "rank_samples");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ m_bt.load(in);
+ m_btnr.load(in);
+ m_btnrp.load(in);
+ m_rank.load(in);
+ }
+
+ iterator begin() const {
+ return iterator(this, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, size());
+ }
+};
+
+
+//! rank_support for the specialized rrr_vector class of block size 15.
+/*! The first template parameter is the bit pattern of size one.
+*/
+template<uint8_t t_b, class t_rac, uint16_t t_k>
+class rank_support_rrr<t_b, 15, t_rac, t_k>
+{
+ public:
+ typedef rrr_vector<15, t_rac, t_k> bit_vector_type;
+ typedef typename bit_vector_type::size_type size_type;
+ typedef typename bit_vector_type::bi_type bi_type;
+ enum { bit_pat = t_b };
+
+ private:
+ const bit_vector_type* m_v; //!< Pointer to the rank supported rrr_vector
+ // TODO cache for sequential ranks
+// mutable size_type m_last_bt;
+// mutable size_type m_last_w; // store the last decoded word
+// uint16_t m_space_for_bt[256];
+ public:
+ //! Standard constructor
+ /*! \param v Pointer to the rrr_vector, which should be supported
+ */
+ explicit rank_support_rrr(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Answers rank queries
+ /*! \param i Argument for the length of the prefix v[0..i-1], with \f$0\leq i \leq size()\f$.
+ \returns Number of 1-bits in the prefix [0..i-1] of the original bit_vector.
+ \par Time complexity
+ \f$ \Order{ sample\_rate of the rrr\_vector} \f$
+ */
+ const size_type rank(size_type i)const {
+ size_type bt_idx = i/bit_vector_type::block_size;
+ size_type sample_pos = bt_idx/t_k;
+ size_type btnrp = m_v->m_btnrp[ sample_pos ];
+ size_type rank = m_v->m_rank[ sample_pos ];
+ if (sample_pos+1 < m_v->m_rank.size()) {
+ size_type diff_rank = m_v->m_rank[ sample_pos+1 ] - rank;
+ if (diff_rank == 0) {
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank, i);
+ } else if (diff_rank == (size_type)bit_vector_type::block_size*t_k) {
+ return rank_support_rrr_trait<t_b>::adjust_rank(
+ rank + i - sample_pos*t_k*bit_vector_type::block_size, i);
+ }
+ }
+ uint8_t* bt = (uint8_t*)(m_v->m_bt.data());
+
+ uint8_t last_bt = *(bt + (bt_idx/2));
+ if (bt_idx%2 == 1) {
+ last_bt >>= 4;
+ } else {
+ last_bt &= 0x0F;
+ }
+ // if the final block type consists only of ones or zeros, we don't have to
+ // calculate the position pointer and can sum up rank in 64 bit chunks
+ if (last_bt == 0 or last_bt == 15) {
+ if (last_bt == 15)
+ rank += i % bit_vector_type::block_size;
+ size_type j = (sample_pos*t_k) << 2;
+ bt_idx = bt_idx << 2;
+ if (bt_idx == j)
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank, i);
+ // now j < bt_idx
+ const uint64_t* bt64 = m_v->m_bt.data() + (j >> 6); // get the word of the start
+ uint8_t bt64_off = j & 0x3F; // get the offset in the word of the start
+ const uint64_t* bt64_end = m_v->m_bt.data() + (bt_idx >> 6);
+ uint8_t bt64_end_off = bt_idx & 0x3F;
+ // Case (1)
+ if (bt64 == bt64_end) {
+ uint64_t w = ((*bt64) >> bt64_off) & bits::lo_set[bt64_end_off-bt64_off];
+ w = (w & 0x0f0f0f0f0f0f0f0full) + ((w >> 4) & 0x0f0f0f0f0f0f0f0full);
+ rank += ((0x0101010101010101ull*w) >> 56);
+ } else { // Case (2)
+ uint64_t w = ((*bt64) >> bt64_off);
+ w = (w & 0x0f0f0f0f0f0f0f0full) + ((w >> 4) & 0x0f0f0f0f0f0f0f0full);
+ rank += ((0x0101010101010101ull*w) >> 56);
+ while ((++bt64) != bt64_end) {
+ w = *bt64;
+ w = (w & 0x0f0f0f0f0f0f0f0full) + ((w >> 4) & 0x0f0f0f0f0f0f0f0full);
+ rank += ((0x0101010101010101ull*w) >> 56);
+ }
+ // now bt64 == bt64_end
+ if (bt64_end_off > 0) {
+ w = *bt64 << (64 - bt64_end_off);
+ w = (w & 0x0f0f0f0f0f0f0f0full) + ((w >> 4) & 0x0f0f0f0f0f0f0f0full);
+ rank += ((0x0101010101010101ull*w) >> 56);
+ }
+ }
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank, i); // necessary
+ }
+ size_type j = sample_pos*t_k;
+ bt += j/2;
+ if (j%2 == 1 and j < bt_idx) {
+ const uint8_t r = (*bt++)>>4;
+ rank += r;
+ btnrp += bi_type::space_for_bt(r);
+ ++j;
+ }
+ while (j+1 < bt_idx) {
+ const uint8_t r = *(bt++);
+ rank += (r>>4)+(r&0x0F);
+ btnrp += bi_type::space_for_bt_pair(r); // decode two entries at once
+ j+=2;
+ }
+ if (j < bt_idx) {
+ const uint8_t r = (*bt);
+ rank += r&0x0F;
+ btnrp += bi_type::space_for_bt(r&0x0F);
+ ++j;
+ }
+ uint8_t off = i % bit_vector_type::block_size; //i - bt_idx*bit_vector_type::block_size;
+ if (!off) { // needed for special case: if i=size() is a multiple of block_size
+ // the access to m_bt would cause a invalid memory access
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank, i);
+ }
+ uint32_t btnr = m_v->m_btnr.get_int(btnrp, bi_type::space_for_bt(last_bt));
+ return rank_support_rrr_trait<t_b>::adjust_rank(rank +
+ bits::cnt(((uint64_t)(bi_type::nr_to_bin(last_bt, btnr))) & bits::lo_set[off]), i);
+ }
+
+ //! Short hand for rank(i)
+ const size_type operator()(size_type i)const {
+ return rank(i);
+ }
+
+ //! Returns the size of the original vector
+ const size_type size()const {
+ return m_v->size();
+ }
+
+ //! Set the supported vector.
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ rank_support_rrr& operator=(const rank_support_rrr& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(rank_support_rrr&) { }
+
+ //! Load the data structure from a stream and set the supported vector.
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Serializes the data structure into a stream.
+ size_type serialize(std::ostream&, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ structure_tree::add_size(child, 0);
+ return 0;
+ }
+};
+
+
+//! Select support for the specialized rrr_vector class of block size 15.
+template<uint8_t t_b, class t_rac, uint16_t t_k>
+class select_support_rrr<t_b, 15, t_rac, t_k>
+{
+ public:
+ typedef rrr_vector<15, t_rac, t_k> bit_vector_type;
+ typedef typename bit_vector_type::size_type size_type;
+ typedef typename bit_vector_type::bi_type bi_type;
+ enum { bit_pat = t_b };
+ private:
+ const bit_vector_type* m_v; //!< Pointer to the rank supported rrr_vector
+
+ // TODO: hinted binary search
+ size_type select1(size_type i)const {
+ if (m_v->m_rank[m_v->m_rank.size()-1] < i)
+ return size();
+ // (1) binary search for the answer in the rank_samples
+ size_type begin=0, end=m_v->m_rank.size()-1; // min included, max excluded
+ size_type idx, rank;
+ // invariant: m_rank[end] >= i
+ // m_rank[begin] < i
+ while (end-begin > 1) {
+ idx = (begin+end) >> 1; // idx in [0..m_rank.size()-1]
+ rank = m_v->m_rank[idx];
+ if (rank >= i)
+ end = idx;
+ else { // rank < i
+ begin = idx;
+ }
+ }
+ // (2) linear search between the samples
+ rank = m_v->m_rank[begin]; // now i>rank
+ idx = begin * t_k; // initialize idx for select result
+ size_type diff_rank = m_v->m_rank[end] - rank;
+ if (diff_rank == (size_type)bit_vector_type::block_size*t_k) {// optimisation for select<1>
+ return idx*bit_vector_type::block_size + i-rank -1;
+ }
+ size_type btnrp = m_v->m_btnrp[ begin ];
+ uint8_t bt = 0, s = 0; // temp variables for block_type and space for block type
+ while (i > rank) {
+ bt = m_v->m_bt[idx++];
+ rank += bt;
+ btnrp += (s=bi_type::space_for_bt(bt));
+ }
+ rank -= bt;
+ uint32_t btnr = m_v->m_btnr.get_int(btnrp-s, s);
+ return (idx-1) * bit_vector_type::block_size + bits::sel(bi_type::nr_to_bin(bt, btnr), i-rank);
+ }
+
+ // TODO: hinted binary search
+ size_type select0(size_type i)const {
+ if ((size()-m_v->m_rank[m_v->m_rank.size()-1]) < i)
+ return size();
+ // (1) binary search for the answer in the rank_samples
+ size_type begin=0, end=m_v->m_rank.size()-1; // min included, max excluded
+ size_type idx, rank;
+ // invariant: m_rank[end] >= i
+ // m_rank[begin] < i
+ while (end-begin > 1) {
+ idx = (begin+end) >> 1; // idx in [0..m_rank.size()-1]
+ rank = idx*bit_vector_type::block_size*t_k - m_v->m_rank[idx];
+ if (rank >= i)
+ end = idx;
+ else { // rank < i
+ begin = idx;
+ }
+ }
+ // (2) linear search between the samples
+ rank = begin*bit_vector_type::block_size*t_k - m_v->m_rank[begin]; // now i>rank
+ idx = begin * t_k; // initialize idx for select result
+ if (m_v->m_rank[end] == m_v->m_rank[begin]) { // only for select<0>
+ return idx*bit_vector_type::block_size + i-rank -1;
+ }
+ size_type btnrp = m_v->m_btnrp[ begin ];
+ uint8_t bt = 0, s = 0; // temp variables for block_type and space for block type
+ while (i > rank) {
+ bt = m_v->m_bt[idx++];
+ rank += (bit_vector_type::block_size-bt);
+ btnrp += (s=bi_type::space_for_bt(bt));
+ }
+ rank -= (bit_vector_type::block_size-bt);
+ uint32_t btnr = m_v->m_btnr.get_int(btnrp-s, s);
+ return (idx-1) * bit_vector_type::block_size + bits::sel(~((uint64_t)bi_type::nr_to_bin(bt, btnr)), i-rank);
+ }
+
+
+
+ public:
+ select_support_rrr(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Answers select queries
+ size_type select(size_type i)const {
+ return t_b ? select1(i) : select0(i);
+ }
+
+
+ const size_type operator()(size_type i)const {
+ return select(i);
+ }
+
+ const size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ select_support_rrr& operator=(const select_support_rrr& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(select_support_rrr&) { }
+
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream&, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ structure_tree::add_size(child, 0);
+ return 0;
+ }
+};
+
+}// end namespace sdsl
+
+#endif
diff --git a/include/sdsl/sd_vector.hpp b/include/sdsl/sd_vector.hpp
new file mode 100644
index 0000000..8e6c14e
--- /dev/null
+++ b/include/sdsl/sd_vector.hpp
@@ -0,0 +1,677 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012-2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*!\file sd_vector.hpp
+ \brief sd_vector.hpp contains the sdsl::sd_vector class, and
+ classes which support rank and select for sd_vector.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SD_VECTOR
+#define INCLUDED_SDSL_SD_VECTOR
+
+#include "int_vector.hpp"
+#include "select_support_mcl.hpp"
+#include "util.hpp"
+#include "iterators.hpp"
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+
+// forward declaration needed for friend declaration
+template<uint8_t t_b = 1,
+ class t_hi_bit_vector= bit_vector,
+ class t_select_1 = typename t_hi_bit_vector::select_1_type,
+ class t_select_0 = typename t_hi_bit_vector::select_0_type>
+class rank_support_sd; // in sd_vector
+
+// forward declaration needed for friend declaration
+template<uint8_t t_b = 1,
+ class t_hi_bit_vector= bit_vector,
+ class t_select_1 = typename t_hi_bit_vector::select_1_type,
+ class t_select_0 = typename t_hi_bit_vector::select_0_type>
+class select_support_sd; // in sd_vector
+
+//! A bit vector which compresses very sparse populated bit vectors by
+// representing the positions of 1 by the Elias-Fano representation for non-decreasing sequences
+/*!
+ * \par Other implementations of this data structure:
+ * - the sdarray of Okanohara and Sadakane
+ * - Sebastiano Vigna implemented a elias_fano class in this sux library.
+ *
+ * \par References
+ * - P. Elias: ,,Efficient storage and retrieval by content and address of static files'',
+ * Journal of the ACM, 1974
+ * - R. Fano: ,,On the number of bits required to implement an associative memory''.
+ * Memorandum 61. Computer Structures Group, Project MAC, MIT, 1971
+ * - D. Okanohara, K. Sadakane: ,,Practical Entropy-Compressed Rank/Select Dictionary'',
+ * Proceedings of ALENEX 2007.
+ *
+ * \tparam t_hi_bit_vector Type of the bitvector used for the unary decoded differences of
+ * the high part of the positions of the 1s.
+ * \tparam t_select_1 Type of the select structure which is used to select ones in HI.
+ * \tparam t_select_0 Type of the select structure which is used to select zeros in HI.
+ */
+template<class t_hi_bit_vector = bit_vector,
+ class t_select_1 = typename t_hi_bit_vector::select_1_type,
+ class t_select_0 = typename t_hi_bit_vector::select_0_type>
+class sd_vector
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef size_type value_type;
+ typedef bit_vector::difference_type difference_type;
+ typedef random_access_const_iterator<sd_vector> iterator;
+ typedef bv_tag index_category;
+ typedef t_select_0 select_0_support_type;
+ typedef t_select_1 select_1_support_type;
+
+ typedef rank_support_sd<0, t_hi_bit_vector, select_1_support_type, select_0_support_type> rank_0_type;
+ typedef rank_support_sd<1, t_hi_bit_vector, select_1_support_type, select_0_support_type> rank_1_type;
+ typedef select_support_sd<0, t_hi_bit_vector, select_1_support_type, select_0_support_type> select_0_type;
+ typedef select_support_sd<1, t_hi_bit_vector, select_1_support_type, select_0_support_type> select_1_type;
+
+ typedef t_hi_bit_vector hi_bit_vector_type;
+ private:
+ // we need this variables to represent the m ones of the original bit vector of size n
+ size_type m_size = 0; // length of the original bit vector
+ uint8_t m_wl = 0; // log n - log m, where n is the length of the original bit vector
+ // and m is the number of ones in the bit vector, wl is the abbreviation
+ // for ,,width (of) low (part)''
+
+ int_vector<> m_low; // vector for the least significant bits of the positions of the m ones
+ hi_bit_vector_type m_high; // bit vector that represents the most significant bit in permuted order
+ select_1_support_type m_high_1_select; // select support for the ones in m_high
+ select_0_support_type m_high_0_select; // select support for the zeros in m_high
+
+ void copy(const sd_vector& v) {
+ m_size = v.m_size;
+ m_wl = v.m_wl;
+ m_low = v.m_low;
+ m_high = v.m_high;
+ m_high_1_select = v.m_high_1_select;
+ m_high_1_select.set_vector(&m_high);
+ m_high_0_select = v.m_high_0_select;
+ m_high_0_select.set_vector(&m_high);
+ }
+
+ public:
+ const uint8_t& wl = m_wl;
+ const hi_bit_vector_type& high = m_high;
+ const int_vector<>& low = m_low;
+ const select_1_support_type& high_1_select = m_high_1_select;
+ const select_0_support_type& high_0_select = m_high_0_select;
+
+ sd_vector() { }
+
+ sd_vector(const sd_vector& sd) {
+ copy(sd);
+ }
+
+ sd_vector(sd_vector&& sd) {
+ *this = std::move(sd);
+ }
+
+ sd_vector(const bit_vector& bv) {
+ m_size = bv.size();
+ size_type m = util::cnt_one_bits(bv);
+ uint8_t logm = bits::hi(m)+1;
+ uint8_t logn = bits::hi(m_size)+1;
+ if (logm == logn) {
+ --logm; // to ensure logn-logm > 0
+ }
+ m_wl = logn - logm;
+ m_low = int_vector<>(m, 0, m_wl);
+ bit_vector high = bit_vector(m + (1ULL<<logm), 0); //
+ const uint64_t* bvp = bv.data();
+ for (size_type i=0, mm=0,last_high=0,highpos=0; i < (bv.size()+63)/64; ++i, ++bvp) {
+ size_type position = 64*i;
+ uint64_t w = *bvp;
+ while (w) { // process bit_vector word by word
+ uint8_t offset = bits::lo(w);
+ w >>= offset; // note: w >>= (offset+1) can not be applied for offset=63!
+ position += offset;
+ if (position >= bv.size()) // check that we have not reached the end of the bitvector
+ break;
+ // (1) handle high part
+ size_type cur_high = position >> m_wl;
+ highpos += (cur_high - last_high); // write cur_high-last_high 0s
+ last_high = cur_high;
+ // (2) handle low part
+ m_low[mm++] = position; // int_vector truncates the most significant logm bits
+ high[highpos++] = 1; // write 1 for the entry
+ position += 1;
+ w >>= 1;
+ }
+ }
+ util::assign(m_high, high);
+ util::init_support(m_high_1_select, &m_high);
+ util::init_support(m_high_0_select, &m_high);
+ }
+
+ //! Accessing the i-th element of the original bit_vector
+ /*! \param i An index i with \f$ 0 \leq i < size() \f$.
+ * \return The i-th bit of the original bit_vector
+ * \par Time complexity
+ * \f$ \Order{t_{select0} + n/m} \f$, where m equals the number of zeros
+ * \par Remark
+ * The time complexity can be easily improved to
+ * \f$\Order{t_{select0}+\log(n/m)}\f$
+ * by using binary search in the second step.
+ */
+ value_type operator[](size_type i)const {
+ size_type high_val = (i >> (m_wl));
+ size_type sel_high = m_high_0_select(high_val + 1);
+ size_type rank_low = sel_high - high_val;
+ if (0 == rank_low)
+ return 0;
+ size_type val_low = i & bits::lo_set[ m_wl ]; // extract the low m_wl = log n -log m bits
+ --sel_high; --rank_low;
+ while (m_high[sel_high] and m_low[rank_low] > val_low) {
+ if (sel_high > 0) {
+ --sel_high; --rank_low;
+ } else
+ return 0;
+ }
+ return m_high[sel_high] and m_low[rank_low] == val_low;
+ }
+
+ //! Get the integer value of the binary string of length len starting at position idx.
+ /*! \param idx Starting index of the binary representation of the integer.
+ * \param len Length of the binary representation of the integer. Default value is 64.
+ * \returns The integer value of the binary string of length len starting at position idx.
+ *
+ * \pre idx+len-1 in [0..size()-1]
+ * \pre len in [1..64]
+ */
+ uint64_t get_int(size_type idx, const uint8_t len=64) const {
+ uint64_t i = idx+len-1;
+ uint64_t high_val = (i >> (m_wl));
+ uint64_t sel_high = m_high_0_select(high_val + 1);
+ uint64_t rank_low = sel_high - high_val;
+ if (0 == rank_low)
+ return 0;
+ size_type val_low = i & bits::lo_set[ m_wl ]; // extract the low m_wl = log n -log m bits
+ --sel_high; --rank_low;
+ while (m_high[sel_high] and m_low[rank_low] > val_low) {
+ if (sel_high > 0) {
+ --sel_high; --rank_low;
+ } else
+ return 0;
+ }
+ uint64_t res = 0;
+ while (true) {
+ while (!m_high[sel_high]) {
+ if (sel_high > 0 and(high_val << m_wl) >=idx) {
+ --sel_high; --high_val;
+ } else {
+ return res;
+ }
+ }
+ while (m_high[sel_high]) {
+ uint64_t val = (high_val << m_wl) + m_low[rank_low];
+ if (val >= idx) {
+ res |= 1ULL<<(val-idx);
+ } else {
+ return res;
+ }
+ if (sel_high > 0) {
+ --sel_high; --rank_low;
+ } else {
+ return res;
+ }
+ }
+ }
+ }
+
+ //! Swap method
+ void swap(sd_vector& v) {
+ if (this != &v) {
+ std::swap(m_size, v.m_size);
+ std::swap(m_wl, v.m_wl);
+ m_low.swap(v.m_low);
+ m_high.swap(v.m_high);
+ util::swap_support(m_high_1_select, v.m_high_1_select, &m_high, &v.m_high);
+ util::swap_support(m_high_0_select, v.m_high_0_select, &m_high, &v.m_high);
+ }
+ }
+
+ //! Returns the size of the original bit vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ sd_vector& operator=(const sd_vector& v) {
+ if (this != &v) {
+ copy(v);
+ }
+ return *this;
+ }
+
+ sd_vector& operator=(sd_vector&& v) {
+ if (this != &v) {
+ m_size = v.m_size;
+ m_wl = v.m_wl;
+ m_low = std::move(v.m_low);
+ m_high = std::move(v.m_high);
+ m_high_1_select = std::move(v.m_high_1_select);
+ m_high_1_select.set_vector(&m_high);
+ m_high_0_select = std::move(v.m_high_0_select);
+ m_high_0_select.set_vector(&m_high);
+ }
+ return *this;
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_wl, out, child, "wl");
+ written_bytes += m_low.serialize(out, child, "low");
+ written_bytes += m_high.serialize(out, child, "high");
+ written_bytes += m_high_1_select.serialize(out, child, "high_1_select");
+ written_bytes += m_high_0_select.serialize(out, child, "high_0_select");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_wl, in);
+ m_low.load(in);
+ m_high.load(in);
+ m_high_1_select.load(in, &m_high);
+ m_high_0_select.load(in, &m_high);
+ }
+
+ iterator begin() const {
+ return iterator(this, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, size());
+ }
+};
+
+template<uint8_t t_b>
+struct rank_support_sd_trait {
+ typedef bit_vector::size_type size_type;
+ static size_type adjust_rank(size_type r,size_type) {
+ return r;
+ }
+};
+
+template<>
+struct rank_support_sd_trait<0> {
+ typedef bit_vector::size_type size_type;
+ static size_type adjust_rank(size_type r, size_type n) {
+ return n - r;
+ }
+};
+
+//! Rank data structure for sd_vector
+/*! \tparam t_b Bit pattern.
+ * \tparam t_hi_bit_vector Type of the bitvector used for the unary decoded differences of
+ * the high part of the positions of the 1s.
+ * \tparam t_select_1 Type of the select structure which is used to select ones in HI.
+ * \tparam t_select_0 Type of the select structure which is used to select zeros in HI.
+ */
+template<uint8_t t_b, class t_hi_bit_vector, class t_select_1, class t_select_0>
+class rank_support_sd
+{
+ static_assert(t_b == 1u or t_b == 0u , "rank_support_sd: bit pattern must be `0` or `1`");
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef sd_vector<t_hi_bit_vector, t_select_1, t_select_0> bit_vector_type;
+ enum { bit_pat = t_b };
+ private:
+ const bit_vector_type* m_v;
+
+ public:
+
+ explicit rank_support_sd(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type rank(size_type i)const {
+ assert(m_v != nullptr);
+ assert(i <= m_v->size());
+ // split problem in two parts:
+ // (1) find >=
+ size_type high_val = (i >> (m_v->wl));
+ size_type sel_high = m_v->high_0_select(high_val + 1);
+ size_type rank_low = sel_high - high_val; //
+ if (0 == rank_low)
+ return rank_support_sd_trait<t_b>::adjust_rank(0, i);
+ size_type val_low = i & bits::lo_set[ m_v->wl ];
+ // now since rank_low > 0 => sel_high > 0
+ do {
+ if (!sel_high)
+ return rank_support_sd_trait<t_b>::adjust_rank(0, i);
+ --sel_high; --rank_low;
+ } while (m_v->high[sel_high] and m_v->low[rank_low] >= val_low);
+ return rank_support_sd_trait<t_b>::adjust_rank(rank_low+1, i);
+ }
+
+ size_type operator()(size_type i)const {
+ return rank(i);
+ }
+
+ size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ rank_support_sd& operator=(const rank_support_sd& rs) {
+ if (this != &rs) {
+ set_vector(rs.m_v);
+ }
+ return *this;
+ }
+
+ void swap(rank_support_sd&) { }
+
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return serialize_empty_object(out, v, name, this);
+ }
+};
+
+template<uint8_t t_b, class t_sd_vec>
+struct select_support_sd_trait {
+ typedef bit_vector::size_type size_type;
+ static size_type select(size_type i, const t_sd_vec* v) {
+ return v->low[i-1] + // lower part of the number
+ ((v->high_1_select(i) + 1 - i) << (v->wl)); // upper part
+ //^-number of 0 before the i-th 1-^ ^-shift by wl
+ }
+};
+
+template<class t_sd_vec>
+struct select_support_sd_trait<0, t_sd_vec> {
+ typedef bit_vector::size_type size_type;
+ static size_type select(size_type i, const t_sd_vec* v) {
+ auto ones = v->low.size();
+ assert(0 < i and i <= v->size() - ones);
+ size_type lb = 1, rb = ones+1;
+ size_type r0 = 0;
+ size_type pos = (size_type)-1;
+ // rb exclusive
+ // invariant: rank0(select_1(rb)) >= i
+ while (lb < rb) {
+ auto mid = lb + (rb-lb)/2;
+ auto x = select_support_sd_trait<1, t_sd_vec>::select(mid, v);
+ auto rank0 = x + 1 - mid;
+ if (rank0 >= i) {
+ rb = mid;
+ } else {
+ r0 = rank0;
+ pos = x;
+ lb = mid + 1;
+ }
+ }
+ return pos + i - r0;
+ }
+};
+
+//! Select data structure for sd_vector
+/*! \tparam t_b Bit pattern.
+ * \tparam t_hi_bit_vector Type of the bitvector used for the unary decoded differences of
+ * the high part of the positions of the 1s.
+ * \tparam t_select_1 Type of the select structure which is used to select ones in HI.
+ * \tparam t_select_0 Type of the select structure which is used to select zeros in HI.
+ */
+template<uint8_t t_b, class t_hi_bit_vector, class t_select_1, class t_select_0>
+class select_support_sd
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef sd_vector<t_hi_bit_vector, t_select_1, t_select_0> bit_vector_type;
+ enum { bit_pat = t_b };
+
+ private:
+ const bit_vector_type* m_v;
+ public:
+
+ explicit select_support_sd(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ //! Returns the position of the i-th occurrence in the bit vector.
+ size_type select(size_type i)const {
+ return select_support_sd_trait<t_b, bit_vector_type>::select(i, m_v);
+ }
+
+ size_type operator()(size_type i)const {
+ return select(i);
+ }
+
+ size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ select_support_sd& operator=(const select_support_sd& ss) {
+ if (this != &ss) {
+ set_vector(ss.m_v);
+ }
+ return *this;
+ }
+
+ void swap(select_support_sd&) { }
+
+ void load(std::istream&, const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return serialize_empty_object(out, v, name, this);
+ }
+};
+
+
+//! Select_0 data structure for sd_vector
+/*! \tparam t_sd_vector sd_vector type
+ * \tparam t_rank_1 Rank support for high part of sd_vector
+ */
+template<typename t_sd_vector=sd_vector<>>
+class select_0_support_sd
+{
+ public:
+ typedef bit_vector::size_type size_type;
+ typedef t_sd_vector bit_vector_type;
+ using rank_1 = typename t_sd_vector::rank_1_type;
+ using sel0_type = typename t_sd_vector::select_0_type;
+ typedef bit_vector y_high_type;
+ enum { bit_pat = 0 };
+
+ private:
+ const bit_vector_type* m_v;
+ int_vector<> m_pointer;
+ int_vector<> m_rank1;
+ public:
+
+ explicit select_0_support_sd(const bit_vector_type* v=nullptr) {
+ set_vector(v);
+ if (nullptr != m_v) {
+ size_type rank_0 = 0; // rank0 in H
+ const size_type bs = 1ULL << (m_v->wl);
+ size_type z = 0;
+ size_type rank1 = 0;// rank1 in H
+ size_type zeros = m_v->size() - rank_1(m_v)(m_v->size()); // zeros in B
+ m_pointer = int_vector<>(zeros/(64*bs)+1, 0, bits::hi(m_v->high.size()/64)+1);
+ m_rank1 = int_vector<>(m_pointer.size(), 0, bits::hi(m_v->high.size())+1);
+ uint64_t w=0;
+ for (size_type i=0, sel0=1; i < m_v->high.size(); i+=64) {
+ size_type old_rank1 = rank1;
+ w = m_v->high.get_int(i, 64);
+ rank1 += bits::cnt(w);
+ rank_0 = (i+64)-rank1;
+ if (rank1 > 0 and (w>>63)&1) {
+ uint64_t pos = rank_0*bs + m_v->low[rank1-1]; // pos of last one (of previous block in B
+ z = pos + 1 - rank1;
+ } else {
+ z = rank_0*bs - rank1;
+ }
+ while (sel0 <= z and sel0 <= zeros) {
+ m_pointer[(sel0-1)/(64*bs)] = i/64;
+ m_rank1[(sel0-1)/(64*bs)] = old_rank1;
+ sel0 += 64*bs;
+ }
+ }
+ }
+ }
+
+ //! Returns the position of the i-th occurrence in the bit vector.
+ size_type select(size_type i)const {
+ const size_type bs = 1ULL << (m_v->wl);
+ size_type j = m_pointer[(i-1)/(64*bs)]*64;// index into m_high
+ size_type rank1 = m_rank1[(i-1)/(64*bs)]; // rank_1(j*bs*64) in B
+ size_type pos = 0;
+ size_type rank0 = 0;
+
+ if (rank1 > 0 and (m_v->high[j-1])&1) {
+ pos = (j-rank1)*bs + m_v->low[rank1-1]; // starting position of current block
+ rank0 = pos+1-rank1;
+ } else {
+ pos = (j-rank1)*bs;// starting position of current block
+ rank0 = pos-rank1;
+ }
+ uint64_t w = m_v->high.get_int(j, 64);
+ do {
+ uint64_t _rank1 = rank1 + bits::cnt(w);
+ uint64_t _rank0 = 0;
+ if (_rank1 > 0 and (w>>63)&1) {
+ pos = (j+64-_rank1)*bs + m_v->low[_rank1-1];
+ _rank0 = pos+1-_rank1;
+ } else {
+ pos = (j+64-_rank1)*bs;
+ _rank0 = pos-_rank1;
+ }
+ if (_rank0 < i) {
+ j+=64;
+ w = m_v->high.get_int(j, 64);
+ rank1 = _rank1;
+ } else {
+ break;
+ }
+ } while (true);
+ // invariant i >zeros
+ do {
+ uint64_t _rank1 = rank1 + bits::lt_cnt[w&0xFFULL];
+ uint64_t _rank0 = 0;
+ if (_rank1 > 0 and (w>>7)&1) {
+ pos = (j+8-_rank1)*bs + m_v->low[_rank1-1];
+ _rank0 = pos+1-_rank1;
+ } else {
+ pos = (j+8-_rank1)*bs;
+ _rank0 = pos-_rank1;
+ }
+ if (_rank0 < i) {
+ j+=8;
+ w >>= 8;
+ rank1 = _rank1;
+ } else {
+ break;
+ }
+ } while (true);
+
+ do {
+ bool b = w&1ULL;
+ w >>= 1; // zeros are shifted in
+ ++j;
+ if (0 == b) {
+ pos = (j-rank1)*bs;
+ size_type zeros = pos-rank1;
+ if (zeros >= i) {
+ pos = pos - (zeros-i) - 1;
+ break;
+ }
+ } else {
+ pos = (j-1-rank1)*bs;
+ size_type one_pos = pos + m_v->low[rank1];
+ ++rank1;
+ size_type zeros = one_pos + 1 - rank1;
+ if (zeros >= i) {
+ pos = one_pos - (zeros-i) - 1;
+ break;
+ }
+ }
+ if (j%64==0) {
+ w = m_v->high.get_int(j,64);
+ }
+ } while (true);
+ return pos;
+ }
+
+ size_type operator()(size_type i)const {
+ return select(i);
+ }
+
+ size_type size()const {
+ return m_v->size();
+ }
+
+ void set_vector(const bit_vector_type* v=nullptr) {
+ m_v = v;
+ }
+
+ select_0_support_sd& operator=(const select_0_support_sd& ss) {
+ if (this != &ss) {
+ m_pointer = ss.m_pointer;
+ m_rank1 = ss.m_rank1;
+ set_vector(ss.m_v);
+ }
+ return *this;
+ }
+
+ void swap(select_0_support_sd& ss) {
+ m_pointer.swap(ss.m_pointer);
+ m_rank1.swap(ss.m_rank1);
+ }
+
+ void load(std::istream& in, const bit_vector_type* v=nullptr) {
+ m_pointer.load(in);
+ m_rank1.load(in);
+ set_vector(v);
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_pointer.serialize(out, child, "pointer");
+ written_bytes += m_rank1.serialize(out, child, "rank1");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+};
+
+
+
+} // end namespace
+#endif
diff --git a/include/sdsl/sdsl_concepts.hpp b/include/sdsl/sdsl_concepts.hpp
new file mode 100644
index 0000000..893c2bd
--- /dev/null
+++ b/include/sdsl/sdsl_concepts.hpp
@@ -0,0 +1,50 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file sdsl_concepts.hpp
+ \brief Contains declarations and definitions of data structure concepts.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_CONCEPTS
+#define INCLUDED_SDSL_CONCEPTS
+
+#include "uintx_t.hpp" // for uint8_t
+
+namespace sdsl
+{
+
+struct bv_tag {}; // bitvector tag
+struct iv_tag {}; // int_vector tag
+
+struct csa_tag {}; // compressed suffix array (CSAs) tag
+struct cst_tag {}; // compressed suffix tree (CST) tag
+struct wt_tag {}; // wavelet tree tag
+
+struct psi_tag {}; // tag for CSAs based on the psi function
+struct lf_tag {}; // tag for CSAs based on the LF function
+
+struct lcp_plain_tag {};
+struct lcp_permuted_tag {};
+struct lcp_tree_compressed_tag {};
+struct lcp_tree_and_lf_compressed_tag {};
+
+
+struct byte_alphabet_tag { static const uint8_t WIDTH=8; };
+struct int_alphabet_tag { static const uint8_t WIDTH=0; };
+
+} // end namespace sdsl
+
+#endif
diff --git a/include/sdsl/select_support.hpp b/include/sdsl/select_support.hpp
new file mode 100644
index 0000000..1d8f27d
--- /dev/null
+++ b/include/sdsl/select_support.hpp
@@ -0,0 +1,251 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file select_support.hpp
+ \brief select_support.hpp contains classes that support a sdsl::bit_vector with constant time select information.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SELECT_SUPPORT
+#define INCLUDED_SDSL_SELECT_SUPPORT
+
+/** \defgroup select_support_group Select Support (SCS)
+ * This group contains data structures which support an sdsl::bit_vector with the select method.
+ */
+
+#include "int_vector.hpp"
+#include "rank_support.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+//! The base class of classes supporting select queries for a sdsl::bit_vector in constant time.
+/*! Abstract base class for classes supporting select queries.
+ */
+class select_support
+{
+ protected:
+ const int_vector<1>* m_v; //!< Pointer to the select supported sdsl::bit_vector.
+ public:
+ typedef int_vector<1>::size_type size_type;
+ const bit_vector* v;
+
+ //! Constructor of select_support.
+ /*! \param v The bit_vector to support rank queries.
+ */
+ select_support(const int_vector<1>* f_v=nullptr):v(f_v) {
+ m_v = f_v;
+ }
+ //! Copy constructor
+ /*! Copy the whole select_support including the pointer
+ * to the supported bit_vector.
+ */
+ select_support(const select_support& f_v);
+ //! Destructor of select_support.
+ virtual ~select_support() {};
+
+ //! Select returns the index of the i-th 1-bit in the supported bit_vector.
+ /*! \param i Argument to calculate the index of the i-th 1-bit in the supported bit_vector.
+ \return The index \f$\in [0..v.size()-1]\f$ of the i-th 1-bit in the supported bit_vector.
+ Call init or load to initialize the data structure before the first call of this method.
+ \sa init, load.
+ */
+ virtual size_type select(size_type i) const = 0;
+
+ //! Alias for select
+ virtual size_type operator()(size_type i) const = 0;
+ //! Serialize the select_support to an out file stream.
+ virtual size_type serialize(std::ostream& out, structure_tree_node* v, std::string name)const = 0;
+ //! Load the select_support from an in file stream.
+ /*! Load an previously serialized select_support from a std::istream.
+ \param in The std::istream to load the select_support.
+ \param v The bit_vector to be supported.
+ \sa init, select.
+ */
+ virtual void load(std::istream& in, const int_vector<1>* v=nullptr) = 0;
+
+ //! This method sets the supported bit_vector
+ virtual void set_vector(const int_vector<1>* v=nullptr) = 0;
+};
+
+
+template<uint8_t bit_pattern, uint8_t pattern_len>
+struct select_support_trait {
+ typedef select_support::size_type size_type;
+
+ /* Count the number of arguments for the specific select support */
+ static size_type arg_cnt(const bit_vector&) {
+ return 0;
+ }
+
+ static size_type args_in_the_first_word(uint64_t, uint8_t, uint64_t) {
+ return 0;
+ }
+
+ static size_type ith_arg_pos_in_the_first_word(uint64_t, size_type, uint8_t, uint64_t) {
+ return 0;
+ }
+
+ static size_type args_in_the_word(uint64_t, uint64_t&) {
+ return 0;
+ }
+
+ static size_type ith_arg_pos_in_the_word(uint64_t, size_type, uint64_t) {
+ return 0;
+ }
+
+ static bool found_arg(size_type, const bit_vector&) {
+ return 0;
+ }
+
+ static uint64_t init_carry(const uint64_t*, size_type) {
+ return 0;
+ }
+
+ static uint64_t get_carry(uint64_t) {
+ return 0;
+ }
+};
+
+template<>
+struct select_support_trait<0,1> {
+ typedef select_support::size_type size_type;
+
+ static size_type arg_cnt(const bit_vector& v) {
+ return v.bit_size()-util::cnt_one_bits(v);
+ }
+ static size_type args_in_the_first_word(uint64_t w, uint8_t offset, uint64_t) {
+ return bits::cnt((~w)& bits::lo_unset[offset]);
+ }
+ static size_type ith_arg_pos_in_the_first_word(uint64_t w, size_type i, uint8_t offset, uint64_t) {
+ return bits::sel(~w & bits::lo_unset[offset], i);
+ }
+ static size_type args_in_the_word(uint64_t w, uint64_t&) {
+ return bits::cnt(~w);
+ }
+ static size_type ith_arg_pos_in_the_word(uint64_t w, size_type i, uint64_t) {
+ return bits::sel(~w, i);
+ }
+ static bool found_arg(size_type i, const bit_vector& v) {
+ return !v[i];
+ }
+ static uint64_t init_carry(const uint64_t*, size_type) {
+ return 0;
+ }
+ static uint64_t get_carry(uint64_t) {
+ return 0;
+ }
+};
+
+template<>
+struct select_support_trait<1,1> {
+ typedef select_support::size_type size_type;
+
+ static size_type arg_cnt(const bit_vector& v) {
+ return util::cnt_one_bits(v);
+ }
+ static size_type args_in_the_first_word(uint64_t w, uint8_t offset, uint64_t) {
+ return bits::cnt(w & bits::lo_unset[offset]);
+ }
+ static size_type ith_arg_pos_in_the_first_word(uint64_t w, size_type i, uint8_t offset, uint64_t) {
+ return bits::sel(w & bits::lo_unset[offset], i);
+ }
+ static size_type args_in_the_word(uint64_t w, uint64_t&) {
+ return bits::cnt(w);
+ }
+ static size_type ith_arg_pos_in_the_word(uint64_t w, size_type i, uint64_t) {
+ return bits::sel(w, i);
+ }
+ static bool found_arg(size_type i, const bit_vector& v) {
+ return v[i];
+ }
+ static uint64_t init_carry(const uint64_t*, size_type) {
+ return 0;
+ }
+ static uint64_t get_carry(uint64_t) {
+ return 0;
+ }
+};
+
+template<>
+struct select_support_trait<10,2> {
+ typedef select_support::size_type size_type;
+
+ static size_type arg_cnt(const bit_vector& v) {
+ return util::cnt_onezero_bits(v);
+ }
+ static size_type args_in_the_first_word(uint64_t w, uint8_t offset, uint64_t carry) {
+ return bits::cnt(bits::map10(w, carry) & bits::lo_unset[offset]);
+ }
+ static size_type ith_arg_pos_in_the_first_word(uint64_t w, size_type i, uint8_t offset, uint64_t carry) {
+ return bits::sel(bits::map10(w, carry) & bits::lo_unset[offset], i);
+ }
+ static size_type args_in_the_word(uint64_t w, uint64_t& carry) {
+ return bits::cnt10(w, carry);
+ }
+ static size_type ith_arg_pos_in_the_word(uint64_t w, size_type i, uint64_t carry) {
+ return bits::sel(bits::map10(w, carry), i);
+ }
+ static bool found_arg(size_type i, const bit_vector& v) {
+ if (i > 0 and v[i-1] and !v[i])
+ return true;
+ return false;
+ }
+ static uint64_t init_carry(const uint64_t* data, size_type word_pos) {
+ return word_pos ? (*(data-1)>>63) : 0;
+ }
+ static uint64_t get_carry(uint64_t w) {
+ return w>>63;
+ }
+};
+
+template<>
+struct select_support_trait<01,2> {
+ typedef select_support::size_type size_type;
+
+ static size_type arg_cnt(const bit_vector& v) {
+ return util::cnt_zeroone_bits(v);
+ }
+ static size_type args_in_the_first_word(uint64_t w, uint8_t offset, uint64_t carry) {
+ return bits::cnt(bits::map01(w, carry) & bits::lo_unset[offset]);
+ }
+ static size_type ith_arg_pos_in_the_first_word(uint64_t w, size_type i, uint8_t offset, uint64_t carry) {
+ return bits::sel(bits::map01(w, carry) & bits::lo_unset[offset], i);
+ }
+ static size_type args_in_the_word(uint64_t w, uint64_t& carry) {
+ return bits::cnt01(w, carry);
+ }
+ static size_type ith_arg_pos_in_the_word(uint64_t w, size_type i, uint64_t carry) {
+ return bits::sel(bits::map01(w, carry), i);
+ }
+ static bool found_arg(size_type i, const bit_vector& v) {
+ if (i > 0 and !v[i-1] and v[i])
+ return true;
+ return false;
+ }
+ static uint64_t init_carry(const uint64_t* data, size_type word_pos) {
+ return word_pos ? (*(data-1)>>63) : 1;
+ }
+ static uint64_t get_carry(uint64_t w) {
+ return w>>63;
+ }
+};
+
+} // end namespace sdsl
+
+#include "select_support_mcl.hpp"
+#include "select_support_scan.hpp"
+
+#endif
diff --git a/include/sdsl/select_support_mcl.hpp b/include/sdsl/select_support_mcl.hpp
new file mode 100644
index 0000000..573b989
--- /dev/null
+++ b/include/sdsl/select_support_mcl.hpp
@@ -0,0 +1,508 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file select_support_mcl.hpp
+ \brief select_support_mcl.hpp contains classes that support a sdsl::bit_vector with constant time select information.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SELECT_SUPPORT_MCL
+#define INCLUDED_SDSL_SELECT_SUPPORT_MCL
+
+#include "int_vector.hpp"
+#include "util.hpp"
+#include "select_support.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A class supporting constant time select queries.
+/*!
+ * \par Space usage
+ * The space usage of the data structure depends on the number of \f$ m \f$ of ones in the
+ * original bitvector $b$. We store the position of every $4096$th set bit
+ * (called L1-sampled bits) of $b$.
+ * This takes in the worst case \f$\frac{m}{4096} \log{n} \leq \frac{64}{n}\f$ bits.
+ * Next,
+ * (1) if the distance of two adjacent L1-sampled bits $b[i]$ and $b[j]$
+ * is greater or equal than $\log^4 n$, then
+ * we store each of the 4096 positions of the set $b$ in [i..j-1] with
+ * $\log{n}$ bits. This results in at most
+ * \$ \frac{4096\cdot \log n}{\log^4 n}=\frac{4096}{\log^3 n}\$ bits per bit.
+ * For a bitvector of 1GB, i.e. \f$ \log n = 35 \f$ we get about 0.01 bits per bit.
+ * If the $j-i+1 < \log^4 n$ then
+ * (2) we store the relative position of every $64$th set bit (called L2-sampled bits)
+ * in b[i..j-1] in at most $4\log\log n$ bits per L2-sampled bits.
+ * An pessimistic upper bound for the space would be
+ * \f$ \frac{4\log\log n}{64} \leq \frac{24}{64} = 0.375\f$ bit per
+ * bit (since $\log\log n\leq 6$. It is very pessimistic, since we store
+ * the relative position in $\log\log(j-i+1)\leq \log\log n$ bits.
+ *
+ * \tparam t_b Bit pattern `0`,`1`,`10`,`01` which should be ranked.
+ * \tparam t_pat_len Length of the bit pattern.
+ *
+ * The implementation is a practical variant of the following reference:
+ *
+ * \par Reference
+ * David Clark:
+ * PhD Thesis: Compact Pat Trees
+ * University of Waterloo, 1996 (Section 2.2.2).
+ * http://www.nlc-bnc.ca/obj/s4/f2/dsk3/ftp04/nq21335.pdf
+ *
+ * @ingroup select_support_group
+ */
+template<uint8_t t_b=1, uint8_t t_pat_len=1>
+class select_support_mcl : public select_support
+{
+ private:
+ static_assert(t_b == 1u or t_b == 0u or t_b == 10u , "select_support_mcl: bit pattern must be `0`,`1`,`10` or `01`");
+ static_assert(t_pat_len == 1u or t_pat_len == 2u , "select_support_mcl: bit pattern length must be 1 or 2");
+ public:
+ typedef bit_vector bit_vector_type;
+ enum { bit_pat = t_b };
+ private:
+ uint32_t m_logn = 0, // \f$ log(size) \f$
+ m_logn2 = 0, // \f$ log^2(size) \f$
+ m_logn4 = 0; // \f$ log^4(size) \f$
+ // entry i of m_superblock equals the answer to select_1(B,i*4096)
+ int_vector<0> m_superblock;
+ int_vector<0>* m_longsuperblock = nullptr;
+ int_vector<0>* m_miniblock = nullptr;
+ size_type m_arg_cnt = 0;
+ void copy(const select_support_mcl<t_b, t_pat_len>& ss);
+ void initData();
+ void init_fast(const bit_vector* v=nullptr);
+ public:
+ explicit select_support_mcl(const bit_vector* v=nullptr);
+ select_support_mcl(const select_support_mcl<t_b,t_pat_len>& ss);
+ select_support_mcl(select_support_mcl<t_b,t_pat_len>&& ss);
+ ~select_support_mcl();
+ void init_slow(const bit_vector* v=nullptr);
+ //! Select function
+ inline size_type select(size_type i) const;
+ //! Alias for select(i).
+ inline size_type operator()(size_type i)const;
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+ void load(std::istream& in, const bit_vector* v=nullptr);
+ void set_vector(const bit_vector* v=nullptr);
+ select_support_mcl<t_b, t_pat_len>& operator=(const select_support_mcl& ss);
+ select_support_mcl<t_b, t_pat_len>& operator=(select_support_mcl&&);
+ void swap(select_support_mcl<t_b, t_pat_len>& ss);
+};
+
+
+template<uint8_t t_b, uint8_t t_pat_len>
+select_support_mcl<t_b,t_pat_len>::select_support_mcl(const bit_vector* f_v):select_support(f_v)
+{
+ if (t_pat_len>1 or(v!=nullptr and v->size() < 100000))
+ init_slow(v);
+ else
+ init_fast(v);
+ return;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+select_support_mcl<t_b,t_pat_len>::select_support_mcl(const select_support_mcl& ss):select_support(ss.m_v)
+{
+ copy(ss);
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+select_support_mcl<t_b,t_pat_len>::select_support_mcl(select_support_mcl&& ss) : select_support(ss.m_v)
+{
+ *this = std::move(ss);
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+select_support_mcl<t_b, t_pat_len>& select_support_mcl<t_b,t_pat_len>::operator=(const select_support_mcl& ss)
+{
+ if (this != &ss) {
+ copy(ss);
+ }
+ return *this;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+select_support_mcl<t_b, t_pat_len>& select_support_mcl<t_b,t_pat_len>::operator=(select_support_mcl&& ss)
+{
+ if (this != &ss) {
+ m_logn = ss.m_logn; // copy log n
+ m_logn2 = ss.m_logn2; // copy (logn)^2
+ m_logn4 = ss.m_logn4; // copy (logn)^4
+ m_superblock = std::move(ss.m_superblock); // move long superblock
+ m_arg_cnt = ss.m_arg_cnt; // copy count of 1-bits
+ m_v = ss.m_v; // copy pointer to the supported bit vector
+
+ if (m_longsuperblock!=nullptr)
+ delete [] m_longsuperblock;
+ m_longsuperblock = ss.m_longsuperblock;
+ ss.m_longsuperblock = nullptr;
+
+ if (m_miniblock!=nullptr)
+ delete [] m_miniblock;
+ m_miniblock = ss.m_miniblock;
+ ss.m_miniblock = nullptr;
+ }
+ return *this;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::swap(select_support_mcl& ss)
+{
+ std::swap(m_logn, ss.m_logn);
+ std::swap(m_logn2, ss.m_logn2);
+ std::swap(m_logn4, ss.m_logn4);
+ m_superblock.swap(ss.m_superblock);
+ std::swap(m_longsuperblock, ss.m_longsuperblock);
+ std::swap(m_miniblock, ss.m_miniblock);
+ std::swap(m_arg_cnt, ss.m_arg_cnt);
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::copy(const select_support_mcl<t_b, t_pat_len>& ss)
+{
+ m_logn = ss.m_logn; // copy log n
+ m_logn2 = ss.m_logn2; // copy (logn)^2
+ m_logn4 = ss.m_logn4; // copy (logn)^4
+ m_superblock = ss.m_superblock; // copy long superblock
+ m_arg_cnt = ss.m_arg_cnt; // copy count of 1-bits
+ m_v = ss.m_v; // copy pointer to the supported bit vector
+ size_type sb = (m_arg_cnt+4095)>>12;
+ if (m_longsuperblock!=nullptr)
+ delete [] m_longsuperblock;
+ m_longsuperblock = nullptr;
+ if (ss.m_longsuperblock!=nullptr) {
+ m_longsuperblock = new int_vector<0>[sb]; //copy longsuperblocks
+ for (size_type i=0; i<sb; ++i) {
+ m_longsuperblock[i] = ss.m_longsuperblock[i];
+ }
+ }
+ if (m_miniblock!=nullptr)
+ delete [] m_miniblock;
+ m_miniblock = nullptr;
+ if (ss.m_miniblock!=nullptr) {
+ m_miniblock = new int_vector<0>[sb]; // copy miniblocks
+ for (size_type i=0; i<sb; ++i) {
+ m_miniblock[i] = ss.m_miniblock[i];
+ }
+ }
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+select_support_mcl<t_b,t_pat_len>::~select_support_mcl()
+{
+ if (m_longsuperblock!=nullptr)
+ delete[] m_longsuperblock;
+ if (m_miniblock!=nullptr)
+ delete[] m_miniblock;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::init_slow(const bit_vector* v)
+{
+ set_vector(v);
+ initData();
+ if (m_v==nullptr)
+ return;
+ // Count the number of arguments in the bit vector
+ m_arg_cnt = select_support_trait<t_b,t_pat_len>::arg_cnt(*v);
+
+ const size_type SUPER_BLOCK_SIZE = 4096;
+
+ if (m_arg_cnt==0) // if there are no arguments in the vector we are done...
+ return;
+
+ size_type sb = (m_arg_cnt+SUPER_BLOCK_SIZE-1)/SUPER_BLOCK_SIZE; // number of superblocks
+ if (m_miniblock != nullptr) delete [] m_miniblock;
+ m_miniblock = new int_vector<0>[sb];
+
+ m_superblock = int_vector<0>(sb, 0, m_logn);
+
+
+ size_type arg_position[SUPER_BLOCK_SIZE], arg_cnt=0;
+ size_type sb_cnt=0;
+ for (size_type i=0; i < v->size(); ++i) {
+ if (select_support_trait<t_b,t_pat_len>::found_arg(i, *v)) {
+ arg_position[ arg_cnt%SUPER_BLOCK_SIZE ] = i;
+ assert(arg_position[arg_cnt%SUPER_BLOCK_SIZE] == i);
+ ++arg_cnt;
+ if (arg_cnt % SUPER_BLOCK_SIZE == 0 or arg_cnt == m_arg_cnt) { //
+ assert(sb_cnt < sb);
+ m_superblock[sb_cnt] = arg_position[0];
+
+ size_type pos_diff = arg_position[(arg_cnt-1)%SUPER_BLOCK_SIZE]-arg_position[0];
+ if (pos_diff > m_logn4) { // longblock
+ if (m_longsuperblock == nullptr) m_longsuperblock = new int_vector<0>[sb]; // create longsuperblock
+ m_longsuperblock[sb_cnt] = int_vector<0>(SUPER_BLOCK_SIZE, 0, bits::hi(arg_position[(arg_cnt-1)%SUPER_BLOCK_SIZE]) + 1);
+
+ for (size_type j=0; j <= (arg_cnt-1)%SUPER_BLOCK_SIZE ; ++j) m_longsuperblock[sb_cnt][j] = arg_position[j]; // copy argument positions to longsuperblock
+ } else { // short block
+ m_miniblock[sb_cnt] = int_vector<0>(64, 0, bits::hi(pos_diff)+1);
+ for (size_type j=0; j <= (arg_cnt-1)%SUPER_BLOCK_SIZE; j+=64) {
+ m_miniblock[sb_cnt][j/64] = arg_position[j]-arg_position[0];
+ }
+ }
+ ++sb_cnt;
+ }
+ }
+ }
+}
+
+// TODO: find bug, detected by valgrind
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::init_fast(const bit_vector* v)
+{
+ set_vector(v);
+ initData();
+ if (m_v==nullptr)
+ return;
+ // Count the number of arguments in the bit vector
+ m_arg_cnt = select_support_trait<t_b,t_pat_len>::arg_cnt(*v);
+
+ const size_type SUPER_BLOCK_SIZE = 64*64;
+
+ if (m_arg_cnt==0) // if there are no arguments in the vector we are done...
+ return;
+
+// size_type sb = (m_arg_cnt+63+SUPER_BLOCK_SIZE-1)/SUPER_BLOCK_SIZE; // number of superblocks, add 63 as the last block could contain 63 uninitialized bits
+ size_type sb = (m_arg_cnt+SUPER_BLOCK_SIZE-1)/SUPER_BLOCK_SIZE; // number of superblocks
+ if (m_miniblock != nullptr) delete [] m_miniblock;
+ m_miniblock = new int_vector<0>[sb];
+
+ m_superblock = int_vector<0>(sb, 0, m_logn);// TODO: hier koennte man logn noch optimieren...s
+
+ bit_vector::size_type arg_position[SUPER_BLOCK_SIZE];
+ const uint64_t* data = v->data();
+ uint64_t carry_new=0;
+ size_type last_k64 = 1, sb_cnt=0;
+ for (size_type i=0, cnt_old=0, cnt_new=0, last_k64_sum=1; i < v->capacity(); i+=64, ++data) {
+ cnt_new += select_support_trait<t_b, t_pat_len>::args_in_the_word(*data, carry_new);
+ if (cnt_new >= last_k64_sum) {
+ arg_position[last_k64-1] = i + select_support_trait<t_b, t_pat_len>::ith_arg_pos_in_the_word(*data, last_k64_sum - cnt_old, carry_new);
+ last_k64 += 64;
+ last_k64_sum += 64;
+
+ if (last_k64 == SUPER_BLOCK_SIZE+1) {
+ m_superblock[sb_cnt] = arg_position[0];
+ size_type pos_of_last_arg_in_the_block = arg_position[last_k64-65];
+
+ for (size_type i=arg_position[last_k64-65]+1, j=last_k64-65; i < v->size() and j < SUPER_BLOCK_SIZE; ++i)
+ if (select_support_trait<t_b,t_pat_len>::found_arg(i, *v)) {
+ pos_of_last_arg_in_the_block = i;
+ ++j;
+ }
+ size_type pos_diff = pos_of_last_arg_in_the_block - arg_position[0];
+ if (pos_diff > m_logn4) { // long block
+ if (m_longsuperblock == nullptr) m_longsuperblock = new int_vector<0>[sb+1]; // create longsuperblock
+ // GEANDERT am 2010-07-17 +1 nach pos_of_last_arg..
+ m_longsuperblock[sb_cnt] = int_vector<0>(SUPER_BLOCK_SIZE, 0, bits::hi(pos_of_last_arg_in_the_block) + 1);
+ for (size_type j=arg_position[0], k=0; k < SUPER_BLOCK_SIZE and j <= pos_of_last_arg_in_the_block; ++j)
+ if (select_support_trait<t_b, t_pat_len>::found_arg(j, *v)) {
+ if (k>=SUPER_BLOCK_SIZE) {
+ for (size_type ii=0; ii < SUPER_BLOCK_SIZE; ++ii) {
+ std::cout<<"("<<ii<<","<<m_longsuperblock[sb_cnt][ii]<<") ";
+ }
+ std::cout << std::endl;
+ std::cout<<"k="<<k<<" SUPER_BLOCK_SIZE="<<SUPER_BLOCK_SIZE<<std::endl;
+ std::cout<<"pos_of_last_arg_in_the_block"<< pos_of_last_arg_in_the_block<<std::endl;
+ std::cout.flush();
+ }
+ m_longsuperblock[sb_cnt][k++] = j;
+ }
+ } else {
+ m_miniblock[sb_cnt] = int_vector<0>(64, 0, bits::hi(pos_diff)+1);
+ for (size_type j=0; j < SUPER_BLOCK_SIZE; j+=64) {
+ m_miniblock[sb_cnt][j/64] = arg_position[j]-arg_position[0];
+ }
+ }
+ ++sb_cnt;
+ last_k64 = 1;
+ }
+ }
+ cnt_old = cnt_new;
+ }
+ // handle last block: append long superblock
+ if (last_k64 > 1) {
+ if (m_longsuperblock == nullptr) m_longsuperblock = new int_vector<0>[sb+1]; // create longsuperblock
+ m_longsuperblock[sb_cnt] = int_vector<0>(SUPER_BLOCK_SIZE, 0, bits::hi(v->size()-1) + 1);
+ for (size_type i=arg_position[0],k=0; i < v->size(); ++i) {
+ if (select_support_trait<t_b, t_pat_len>::found_arg(i, *v)) {
+ m_longsuperblock[sb_cnt][k++] = i;
+ }
+ }
+ ++sb_cnt;
+ }
+}
+
+
+template<uint8_t t_b, uint8_t t_pat_len>
+inline auto select_support_mcl<t_b,t_pat_len>::select(size_type i)const -> size_type
+{
+ assert(i > 0 and i <= m_arg_cnt);
+
+ i = i-1;
+ size_type sb_idx = i>>12; // i/4096
+ size_type offset = i&0xFFF; // i%4096
+ if (m_longsuperblock!=nullptr and !m_longsuperblock[sb_idx].empty()) {
+ return m_longsuperblock[sb_idx][offset];
+ } else {
+ if ((offset&0x3F)==0) {
+ assert(sb_idx < m_superblock.size());
+ assert((offset>>6) < m_miniblock[sb_idx].size());
+ return m_superblock[sb_idx] + m_miniblock[sb_idx][offset>>6/*/64*/];
+ } else {
+ i = i-(sb_idx<<12)-((offset>>6)<<6);
+ // now i > 0 and i <= 64
+ assert(i > 0);
+ size_type pos = m_superblock[sb_idx] + m_miniblock[sb_idx][offset>>6] + 1;
+
+ // now pos is the position from where we search for the ith argument
+ size_type word_pos = pos>>6;
+ size_type word_off = pos&0x3F;
+ const uint64_t* data = m_v->data() + word_pos;
+ uint64_t carry = select_support_trait<t_b,t_pat_len>::init_carry(data, word_pos);
+ size_type args = select_support_trait<t_b,t_pat_len>::args_in_the_first_word(*data, word_off, carry);
+
+ if (args >= i) {
+ return (word_pos<<6)+select_support_trait<t_b,t_pat_len>::ith_arg_pos_in_the_first_word(*data, i, word_off, carry);
+ }
+ word_pos+=1;
+ size_type sum_args = args;
+ carry = select_support_trait<t_b,t_pat_len>::get_carry(*data);
+ uint64_t old_carry = carry;
+ args = select_support_trait<t_b,t_pat_len>::args_in_the_word(*(++data), carry);
+ while (sum_args + args < i) {
+ sum_args += args;
+ assert(data+1 < m_v->data() + (m_v->capacity()>>6));
+ old_carry = carry;
+ args = select_support_trait<t_b,t_pat_len>::args_in_the_word(*(++data), carry);
+ word_pos+=1;
+ }
+ return (word_pos<<6) +
+ select_support_trait<t_b,t_pat_len>::ith_arg_pos_in_the_word(*data, i-sum_args, old_carry);
+ }
+ }
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+inline auto select_support_mcl<t_b,t_pat_len>::operator()(size_type i)const -> size_type
+{
+ return select(i);
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::initData()
+{
+ m_arg_cnt = 0;
+ if (nullptr == m_v) {
+ m_logn = m_logn2 = m_logn4 = 0;
+ } else {
+ m_logn = bits::hi(m_v->capacity())+1; // TODO maybe it's better here to take a max(...,12)
+ m_logn2 = m_logn*m_logn;
+ m_logn4 = m_logn2*m_logn2;
+ }
+ if (nullptr != m_longsuperblock)
+ delete[] m_longsuperblock;
+ m_longsuperblock = nullptr;
+ if (nullptr != m_miniblock)
+ delete[] m_miniblock;
+ m_miniblock = nullptr;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::set_vector(const bit_vector* v)
+{
+ m_v = v;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+auto select_support_mcl<t_b,t_pat_len>::serialize(std::ostream& out, structure_tree_node* v, std::string name)const -> size_type
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ // write the number of 1-bits in the supported bit_vector
+ out.write((char*) &m_arg_cnt, sizeof(size_type)/sizeof(char));
+ written_bytes = sizeof(size_type)/sizeof(char);
+ // number of superblocks in the data structure
+ size_type sb = (m_arg_cnt+4095)>>12;
+
+ if (m_arg_cnt) { // if there exists 1-bits to be supported
+ written_bytes += m_superblock.serialize(out, child, "superblock"); // serialize superblocks
+ bit_vector mini_or_long;// Helper vector: mini or long block?
+ if (m_longsuperblock!=nullptr) {
+ mini_or_long.resize(sb); // resize indicator bit_vector to the number of superblocks
+ for (size_type i=0; i< sb; ++i)
+ mini_or_long[i] = !m_miniblock[i].empty();
+ }
+ written_bytes += mini_or_long.serialize(out, child, "mini_or_long");
+ size_type written_bytes_long = 0;
+ size_type written_bytes_mini = 0;
+ for (size_type i=0; i < sb; ++i)
+ if (!mini_or_long.empty() and !mini_or_long[i]) {
+ written_bytes_long += m_longsuperblock[i].serialize(out);
+ } else {
+ written_bytes_mini += m_miniblock[i].serialize(out);
+ }
+ written_bytes += written_bytes_long;
+ written_bytes += written_bytes_mini;
+ structure_tree_node* child_long = structure_tree::add_child(child, "longsuperblock", util::class_name(m_longsuperblock));
+ structure_tree::add_size(child_long, written_bytes_long);
+ structure_tree_node* child_mini = structure_tree::add_child(child, "minisuperblock", util::class_name(m_miniblock));
+ structure_tree::add_size(child_mini, written_bytes_mini);
+ }
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<uint8_t t_b, uint8_t t_pat_len>
+void select_support_mcl<t_b,t_pat_len>::load(std::istream& in, const bit_vector* v)
+{
+ set_vector(v);
+ initData();
+ // read the number of 1-bits in the supported bit_vector
+ in.read((char*) &m_arg_cnt, sizeof(size_type)/sizeof(char));
+ size_type sb = (m_arg_cnt+4095)>>12;
+
+ if (m_arg_cnt) { // if there exists 1-bits to be supported
+ m_superblock.load(in); // load superblocks
+
+ if (m_miniblock!=nullptr) {
+ delete[] m_miniblock;
+ m_miniblock = nullptr;
+ }
+ if (m_longsuperblock!=nullptr) {
+ delete[] m_longsuperblock;
+ m_longsuperblock = nullptr;
+ }
+
+ bit_vector mini_or_long;// Helper vector: mini or long block?
+ mini_or_long.load(in); // Load the helper vector
+ m_miniblock = new int_vector<0>[sb]; // Create miniblock int_vector<0>
+ if (!mini_or_long.empty())
+ m_longsuperblock = new int_vector<0>[sb]; // Create longsuperblock int_vector<0>
+
+ for (size_type i=0; i < sb; ++i)
+ if (!mini_or_long.empty() and not mini_or_long[i]) {
+ m_longsuperblock[i].load(in);
+ } else {
+ m_miniblock[i].load(in);
+ }
+ }
+}
+
+}
+
+#endif
diff --git a/include/sdsl/select_support_scan.hpp b/include/sdsl/select_support_scan.hpp
new file mode 100644
index 0000000..0540aed
--- /dev/null
+++ b/include/sdsl/select_support_scan.hpp
@@ -0,0 +1,104 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file select_support_scan.hpp
+ \brief select_support_scan.hpp contains classes that support a sdsl::bit_vector with linear time select.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SELECT_SUPPORT_SCAN
+#define INCLUDED_SDSL_SELECT_SUPPORT_SCAN
+
+#include "int_vector.hpp"
+#include "util.hpp"
+#include "select_support.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+
+//! A class supporting linear time select queries.
+/*! \par Space complexity
+ * Constant.
+ * \par Time complexity
+ * Linear in the size of the supported vector.
+ *
+ * \tparam t_b Bit pattern which should be supported. Either `0`,`1`,`10`,`01`.
+ * \tparam t_pat_len Length of the bit pattern.
+ * @ingroup select_support_group
+ */
+template<uint8_t t_b=1, uint8_t t_pat_len=1>
+class select_support_scan : public select_support
+{
+ private:
+ static_assert(t_b == 1u or t_b == 0u or t_b == 10u , "select_support_scan: bit pattern must be `0`,`1`,`10` or `01`");
+ static_assert(t_pat_len == 1u or t_pat_len == 2u , "select_support_scan: bit pattern length must be 1 or 2");
+ public:
+ typedef bit_vector bit_vector_type;
+ enum { bit_pat = t_b };
+ public:
+ explicit select_support_scan(const bit_vector* v=nullptr) : select_support(v) {}
+ select_support_scan(const select_support_scan<t_b,t_pat_len>& ss) : select_support(ss.m_v) {}
+
+ inline size_type select(size_type i) const;
+ inline size_type operator()(size_type i)const {
+ return select(i);
+ }
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ return serialize_empty_object(out, v, name, this);
+ }
+ void load(std::istream&, SDSL_UNUSED const bit_vector* v=nullptr) {
+ set_vector(v);
+ }
+
+ void set_vector(const bit_vector* v=nullptr) {
+ m_v = v;
+ }
+ select_support_scan<t_b, t_pat_len>& operator=(const select_support_scan& ss) {
+ set_vector(ss.m_v);
+ return *this;
+ }
+ void swap(select_support_scan<t_b, t_pat_len>&) {}
+};
+
+template<uint8_t t_b, uint8_t t_pat_len>
+inline typename select_support_scan<t_b,t_pat_len>::size_type select_support_scan<t_b,t_pat_len>::select(size_type i)const
+{
+ const uint64_t* data = m_v->data();
+ size_type word_pos = 0;
+ size_type word_off = 0;
+ uint64_t carry = select_support_trait<t_b,t_pat_len>::init_carry(data, word_pos);
+ size_type args = select_support_trait<t_b,t_pat_len>::args_in_the_first_word(*data, word_off, carry);
+ if (args >= i) {
+ return (word_pos<<6)+select_support_trait<t_b,t_pat_len>::ith_arg_pos_in_the_first_word(*data, i, word_off, carry);
+ }
+ word_pos+=1;
+ size_type sum_args = args;
+ carry = select_support_trait<t_b,t_pat_len>::get_carry(*data);
+ uint64_t old_carry = carry;
+ args = select_support_trait<t_b,t_pat_len>::args_in_the_word(*(++data), carry);
+ while (sum_args + args < i) {
+ sum_args += args;
+ assert(data+1 < m_v->data() + (m_v->capacity()>>6));
+ old_carry = carry;
+ args = select_support_trait<t_b,t_pat_len>::args_in_the_word(*(++data), carry);
+ word_pos+=1;
+ }
+ return (word_pos<<6) + select_support_trait<t_b,t_pat_len>::ith_arg_pos_in_the_word(*data, i-sum_args, old_carry);
+}
+
+} // end namespace
+#endif
diff --git a/include/sdsl/sfstream.hpp b/include/sdsl/sfstream.hpp
new file mode 100644
index 0000000..ceef470
--- /dev/null
+++ b/include/sdsl/sfstream.hpp
@@ -0,0 +1,79 @@
+/*!\file sfstream.hpp
+ \brief sfstream.hpp contains a two stream class which can be used to read/write from/to files or strings.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SFSTREAM
+#define INCLUDED_SDSL_SFSTREAM
+
+#include <fstream>
+#include <sstream>
+#include <string>
+#include "sdsl/ram_fs.hpp"
+#include "sdsl/ram_filebuf.hpp"
+
+namespace sdsl
+{
+
+class osfstream : public std::ostream
+{
+ public:
+ typedef std::streambuf* buf_ptr_type;
+ private:
+ buf_ptr_type m_streambuf = nullptr;
+ std::string m_file = "";
+ public:
+ typedef void* voidptr;
+ //! Standard constructor.
+ osfstream();
+ //! Constructor taking a file name and open mode.
+ osfstream(const std::string& file, std::ios_base::openmode mode = std::ios_base::out);
+ //! Open the stream.
+ buf_ptr_type
+ open(const std::string& file, std::ios_base::openmode mode = std::ios_base::out);
+ //! Is the stream close?
+ bool is_open();
+ //! Close the stream.
+ void close();
+ //! Standard destructor
+ ~osfstream();
+ //! Cast to void*
+ operator voidptr() const;
+
+ osfstream& seekp(pos_type pos);
+ osfstream& seekp(off_type off, ios_base::seekdir way);
+ std::streampos tellp();
+};
+
+
+class isfstream : public std::istream
+{
+ typedef std::streambuf* buf_ptr_type;
+ private:
+ buf_ptr_type m_streambuf = nullptr;
+ std::string m_file = "";
+ public:
+ typedef void* voidptr;
+ //! Standard constructor.
+ isfstream();
+ //! Constructor taking a file name and open mode.
+ isfstream(const std::string& file, std::ios_base::openmode mode = std::ios_base::in);
+ //! Open the stream.
+ buf_ptr_type
+ open(const std::string& file, std::ios_base::openmode mode = std::ios_base::in);
+ //! Is the stream close?
+ bool is_open();
+ //! Close the stream.
+ void close();
+ //! Standard destructor
+ ~isfstream();
+ //! Cast to void*
+ operator voidptr() const;
+
+ isfstream& seekg(pos_type pos);
+ isfstream& seekg(off_type off, ios_base::seekdir way);
+ std::streampos tellg();
+};
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/sorted_int_stack.hpp b/include/sdsl/sorted_int_stack.hpp
new file mode 100644
index 0000000..8b23a32
--- /dev/null
+++ b/include/sdsl/sorted_int_stack.hpp
@@ -0,0 +1,183 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file sorted_int_stack.hpp
+ \brief sorted_int_stack.hpp contains a data structure for a stack which can contain numbers in the range from \f$0\f$ to \f$n-1\f$ and the numbers on the stack are sorted in increasing order.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SORTED_INT_STACK
+#define INCLUDED_SDSL_SORTED_INT_STACK
+
+#include "int_vector.hpp"
+#include <vector>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A stack class which can contain integers from \f$0\f$ to \f$n-1\f$ in sorted order.
+/*! \par Space complexity
+ * \f$n\f$ bits
+ */
+class sorted_int_stack
+{
+ public:
+ typedef int_vector<64>::size_type size_type;
+ private:
+ size_type m_n; // maximal value which can be stored on the stack
+ size_type m_cnt; // counter for elements on the stack
+ size_type m_top; // top element of the stack
+ int_vector<64> m_stack; // memory for the stack
+ std::vector<size_type> m_overflow; // memory for the elements which are greater than n
+
+ inline size_type block_nr(size_type x) {
+ return x/63;
+ }; // maybe we can speed this up with bit hacks
+ inline size_type block_pos(size_type x) {
+ return x%63;
+ }; // maybe we can speed this up with bit hacks
+ public:
+ sorted_int_stack(size_type n);
+ sorted_int_stack(const sorted_int_stack&) = default;
+ sorted_int_stack(sorted_int_stack&&) = default;
+ sorted_int_stack& operator=(const sorted_int_stack&) = default;
+ sorted_int_stack& operator=(sorted_int_stack&&) = default;
+
+ /*! Returns if the stack is empty.
+ */
+ bool empty() const {
+ return 0==m_cnt;
+ };
+
+ /*! Returns the topmost element of the stack.
+ * \pre empty()==false
+ */
+ size_type top() const;
+
+ /*! Pop the topmost element of the stack.
+ */
+ void pop();
+
+ /*! Push value x on the stack.
+ * \par x Value which should be pushed onto the stack.
+ * \pre top() < x
+ */
+ void push(size_type x);
+
+ /*! Returns the number of element is the stack.
+ */
+ size_type size()const {
+ return m_cnt;
+ };
+
+ size_type
+ serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const;
+ void load(std::istream& in);
+
+};
+
+inline sorted_int_stack::sorted_int_stack(size_type n):m_n(n), m_cnt(0), m_top(0)
+{
+ m_stack = int_vector<64>(block_nr(n)+2, 0);
+ m_stack[0] = 1;
+}
+
+inline sorted_int_stack::size_type sorted_int_stack::top()const
+{
+ return m_top-63;
+}
+
+inline void sorted_int_stack::push(size_type x)
+{
+ x += 63;
+ assert(empty() || m_top < x);
+ ++m_cnt; //< increment counter
+ if (x > m_n+63) {
+ if (m_overflow.empty()) {
+ m_overflow.push_back(m_top);
+ }
+ m_overflow.push_back(x);
+ m_top = x;
+ } else {
+ size_type bn = block_nr(x);
+ m_stack[bn] ^= (1ULL << block_pos(x));
+ if (m_stack[bn-1] == 0) {
+ m_stack[bn-1] = 0x8000000000000000ULL | m_top;
+ }
+ m_top = x;
+ }
+}
+
+inline void sorted_int_stack::pop()
+{
+ if (!empty()) {
+ --m_cnt; //< decrement counter
+ if (m_top > m_n+63) {
+ m_overflow.pop_back();
+ m_top = m_overflow.back();
+ if (m_overflow.size()==1)
+ m_overflow.pop_back();
+ } else {
+ size_type bn = block_nr(m_top);
+ uint64_t w = m_stack[ bn ];
+ assert((w>>63) == 0); // highest bit is not set, as the block contains no pointer
+ w ^= (1ULL << block_pos(m_top));
+ m_stack[ bn ] = w;
+ if (w>0) {
+ m_top = bn*63 + bits::hi(w);
+ } else { // w==0 and cnt>0
+ assert(bn > 0);
+ w = m_stack[ bn-1 ];
+ if ((w>>63) == 0) { // highest bit is not set => the block contains no pointer
+ assert(w>0);
+ m_top = (bn-1)*63 + bits::hi(w);
+ } else { // block contains pointers
+ m_stack[bn-1] = 0;
+ m_top = w&0x7FFFFFFFFFFFFFFFULL;
+ }
+ }
+ }
+ }
+}
+
+inline sorted_int_stack::size_type
+sorted_int_stack::serialize(std::ostream& out, structure_tree_node* v,
+ std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_n, out);
+ written_bytes += write_member(m_top, out);
+ written_bytes += write_member(m_cnt, out);
+ written_bytes += m_stack.serialize(out);
+ written_bytes += sdsl::serialize(m_overflow, out, child, "overflow");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+inline void sorted_int_stack::load(std::istream& in)
+{
+ read_member(m_n, in);
+ read_member(m_top, in);
+ read_member(m_cnt, in);
+ m_stack.load(in);
+ sdsl::load(m_overflow, in);
+}
+
+}// end namespace sdsl
+
+#endif // end file
diff --git a/include/sdsl/sorted_multi_stack_support.hpp b/include/sdsl/sorted_multi_stack_support.hpp
new file mode 100644
index 0000000..83213b0
--- /dev/null
+++ b/include/sdsl/sorted_multi_stack_support.hpp
@@ -0,0 +1,190 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file sorted_multi_stack_support.hpp
+ \brief sorted_multi_stack_support.hpp contains a data structure for a stack which contains
+ elements from [0..n] in sorted order. Duplicates are possible.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SORTED_MULTI_STACK_SUPPORT
+#define INCLUDED_SDSL_SORTED_MULTI_STACK_SUPPORT
+
+#include "int_vector.hpp"
+
+namespace sdsl
+{
+
+//! Stack which contains elements from [0..n] in sorted order. Duplicates are possible.
+/*! \par Space complexity
+ * \f$2n\f$ bits
+ */
+class sorted_multi_stack_support
+{
+ public:
+ typedef int_vector<64>::size_type size_type;
+ private:
+ size_type m_n; // Size of the supported vector.
+ size_type m_cnt; // Counter for the indices on the stack.
+ size_type m_top; // Topmost index of the stack.
+ int_vector<64> m_stack; // Memory for the stack.
+ int_vector<64> m_duplication_stack; // Memory for the duplications
+
+ inline size_type block_nr(size_type x) {
+ return x/63;
+ }; // maybe we can speed this up with bit hacks
+ inline size_type block_pos(size_type x) {
+ return x%63;
+ }; // maybe we can speed this up with bit hacks
+ public:
+ //! Constructor
+ /*! \param n Maximum that can be pushed onto the stack
+ */
+ sorted_multi_stack_support(size_type n);
+ sorted_multi_stack_support(const sorted_multi_stack_support&) = default;
+ sorted_multi_stack_support(sorted_multi_stack_support&&) = default;
+ sorted_multi_stack_support& operator=(const sorted_multi_stack_support&) = default;
+ sorted_multi_stack_support& operator=(sorted_multi_stack_support&&) = default;
+
+ /*! Returns if the stack is empty.
+ */
+ bool empty() const {
+ return 0==m_cnt;
+ };
+
+ /*! Returns the topmost index on the stack.
+ * \pre empty()==false
+ */
+ size_type top() const;
+
+ /*! Pop the topmost index of the stack.
+ * \return True if there the value of the top element after the execution of pop()
+ * is not equal to the value of the top element before the execution of pop(). False otherwise.
+ */
+ bool pop();
+
+ /*! Push the index x of vector vec onto the stack.
+ * \par x value which should be pushed onto the stack.
+ * \return True if the value on the top of the stack is smaller than x. False if the value is equal.
+ * \pre top() <= x
+ */
+ bool push(size_type x);
+
+ /*! Returns the number of element is the stack.
+ */
+ size_type size()const {
+ return m_cnt;
+ };
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const;
+ void load(std::istream& in);
+
+};
+
+inline sorted_multi_stack_support::sorted_multi_stack_support(size_type n):m_n(n), m_cnt(0), m_top(0), m_stack(), m_duplication_stack()
+{
+ m_stack = int_vector<64>(block_nr(m_n+1)+1, 0);
+ m_stack[0] = 1;
+ m_duplication_stack = int_vector<64>((m_n>>6)+1, 0);
+}
+
+
+inline sorted_multi_stack_support::size_type sorted_multi_stack_support::top()const
+{
+ return m_top-1;
+}
+
+inline bool sorted_multi_stack_support::push(size_type x)
+{
+ x += 1;
+ size_type bn = block_nr(x);
+ if (0 == ((m_stack[bn] >> block_pos(x))&1)) { // check if x is not already on the stack
+ m_stack[bn] ^= (1ULL << block_pos(x));
+ if (bn > 0 and m_stack[bn-1] == 0) {
+ m_stack[bn-1] = 0x8000000000000000ULL | m_top;
+ }
+ m_top = x;
+ // write a 0 to the duplication stack
+ // do nothing as stack is initialized with zeros
+ ++m_cnt; //< increment counter
+ return true;
+ } else { // if the element is already on the stack
+ // write a 1 to the duplication stack
+ m_duplication_stack[m_cnt>>6] ^= (1ULL << (m_cnt&0x3F));
+ ++m_cnt; //< increment counter
+ return false;
+ }
+}
+
+inline bool sorted_multi_stack_support::pop()
+{
+ if (m_cnt) {
+ --m_cnt; //< decrement counter
+ if ((m_duplication_stack[m_cnt>>6]>>(m_cnt&0x3F))&1) { // if it's a duplication
+ m_duplication_stack[m_cnt>>6] ^= (1ULL << (m_cnt&0x3F)); // delete 1
+ return false;
+ } else {
+ size_type bn = block_nr(m_top);
+ uint64_t w = m_stack[ bn ];
+ assert((w>>63) == 0); // highest bit is not set, as the block contains no pointer
+ w ^= (1ULL << block_pos(m_top));
+ m_stack[ bn ] = w;
+ if (w>0) {
+ m_top = bn*63 + bits::hi(w);
+ } else { // w==0 and cnt>0
+ assert(bn > 0);
+ w = m_stack[ bn-1 ];
+ if ((w>>63) == 0) { // highest bit is not set => the block contains no pointer
+ assert(w>0);
+ m_top = (bn-1)*63 + bits::hi(w);
+ } else { // block contains pointers
+ m_stack[bn-1] = 0;
+ m_top = w&0x7FFFFFFFFFFFFFFFULL;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+inline sorted_multi_stack_support::size_type
+sorted_multi_stack_support::serialize(std::ostream& out,
+ structure_tree_node* v, std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_n, out);
+ written_bytes += write_member(m_top, out);
+ written_bytes += write_member(m_cnt, out);
+ written_bytes += m_stack.serialize(out);
+ written_bytes += m_duplication_stack.serialize(out);
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+inline void sorted_multi_stack_support::load(std::istream& in)
+{
+ read_member(m_n, in);
+ read_member(m_top, in);
+ read_member(m_cnt, in);
+ m_stack.load(in);
+ m_duplication_stack.load(in);
+}
+
+}// end namespace sdsl
+
+#endif // end file
diff --git a/include/sdsl/sorted_stack_support.hpp b/include/sdsl/sorted_stack_support.hpp
new file mode 100644
index 0000000..8ef06f3
--- /dev/null
+++ b/include/sdsl/sorted_stack_support.hpp
@@ -0,0 +1,171 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file sorted_stack_support.hpp
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SORTED_STACK_SUPPORT
+#define INCLUDED_SDSL_SORTED_STACK_SUPPORT
+
+#include "int_vector.hpp"
+
+namespace sdsl
+{
+
+//! A stack which contains strictly increasing pointer to strictly increasing elements in an array.
+/*!
+ * \par Reference
+ * Johannes Fischer:
+ * Optimal Succinctness for Range Minimum Queries
+ * LATIN 2010
+ *
+ * \par Space complexity
+ * \f$n\f$ bits
+ */
+class sorted_stack_support
+{
+ public:
+ typedef int_vector<64>::size_type size_type;
+ private:
+ size_type m_n; // Size of the supported vector.
+ size_type m_cnt; // Counter for the indices on the stack.
+ size_type m_top; // Topmost index of the stack.
+ int_vector<64> m_stack; // Memory for the stack.
+
+ inline size_type block_nr(size_type x) {
+ return x/63;
+ }; // TODO: maybe we can speed this up with bit hacks
+ inline size_type block_pos(size_type x) {
+ return x%63;
+ }; // TODO: maybe we can speed this up with bit hacks
+ public:
+ //! Constructor
+ /*! \param n Maximum that can be pushed onto the stack
+ */
+ sorted_stack_support(size_type n);
+
+ sorted_stack_support(const sorted_stack_support&) = default;
+ sorted_stack_support(sorted_stack_support&&) = default;
+ sorted_stack_support& operator=(const sorted_stack_support&) = default;
+ sorted_stack_support& operator=(sorted_stack_support&&) = default;
+
+ /*! Returns if the stack is empty.
+ */
+ bool empty() const {
+ return 0==m_cnt;
+ };
+
+ /*! Returns the topmost index on the stack.
+ * \pre empty()==false
+ */
+ size_type top() const;
+
+ /*! Pop the topmost index of the stack.
+ */
+ void pop();
+
+ /*! Push the index x of vector vec onto the stack.
+ * \par x Index of the value in vec which should be pushed onto the stack.
+ * \pre top() < x
+ */
+ void push(size_type x);
+
+ /*! Returns the number of element is the stack.
+ */
+ size_type size()const {
+ return m_cnt;
+ };
+
+ size_type
+ serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const;
+ void load(std::istream& in);
+
+};
+
+inline sorted_stack_support::sorted_stack_support(size_type n):m_n(n), m_cnt(0), m_top(0), m_stack()
+{
+ m_stack = int_vector<64>(block_nr(m_n+1)+1, 0);
+ m_stack[0] = 1;
+}
+
+inline sorted_stack_support::size_type sorted_stack_support::top()const
+{
+ return m_top-1;
+}
+
+inline void sorted_stack_support::push(size_type x)
+{
+ x += 1;
+ ++m_cnt; //< increment counter
+ size_type bn = block_nr(x);
+ m_stack[bn] ^= (1ULL << block_pos(x));
+ if (bn > 0 and m_stack[bn-1] == 0) {
+ m_stack[bn-1] = 0x8000000000000000ULL | m_top;
+ }
+ m_top = x;
+}
+
+inline void sorted_stack_support::pop()
+{
+ if (!empty()) {
+ --m_cnt; //< decrement counter
+ size_type bn = block_nr(m_top);
+ uint64_t w = m_stack[ bn ];
+ assert((w>>63) == 0); // highest bit is not set, as the block contains no pointer
+ w ^= (1ULL << block_pos(m_top));
+ m_stack[ bn ] = w;
+ if (w>0) {
+ m_top = bn*63 + bits::hi(w);
+ } else { // w==0 and cnt>0
+ assert(bn > 0);
+ w = m_stack[ bn-1 ];
+ if ((w>>63) == 0) { // highest bit is not set => the block contains no pointer
+ assert(w>0);
+ m_top = (bn-1)*63 + bits::hi(w);
+ } else { // block contains pointers
+ m_stack[bn-1] = 0;
+ m_top = w&0x7FFFFFFFFFFFFFFFULL;
+ }
+ }
+ }
+}
+
+inline sorted_stack_support::size_type
+sorted_stack_support::serialize(std::ostream& out, structure_tree_node* v,
+ std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_n, out);
+ written_bytes += write_member(m_top, out);
+ written_bytes += write_member(m_cnt, out);
+ written_bytes += m_stack.serialize(out);
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+inline void sorted_stack_support::load(std::istream& in)
+{
+ read_member(m_n, in);
+ read_member(m_top, in);
+ read_member(m_cnt, in);
+ m_stack.load(in);
+}
+
+}// end namespace sdsl
+
+#endif // end file
diff --git a/include/sdsl/structure_tree.hpp b/include/sdsl/structure_tree.hpp
new file mode 100644
index 0000000..e9a94f5
--- /dev/null
+++ b/include/sdsl/structure_tree.hpp
@@ -0,0 +1,66 @@
+/*!\file structure_tree.hpp
+ \brief structure_tree.hpp contains a helper class which can represent the memory structure of a class.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_STRUCTURE_TREE
+#define INCLUDED_SDSL_STRUCTURE_TREE
+
+#include "uintx_t.hpp"
+#include <unordered_map>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <memory>
+#include "config.hpp"
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+
+class structure_tree_node
+{
+ private:
+ using map_type = std::unordered_map<std::string,std::unique_ptr<structure_tree_node>>;
+ map_type m_children;
+ public:
+ const map_type& children = m_children;
+ size_t size = 0;
+ std::string name;
+ std::string type;
+ public:
+ structure_tree_node(const std::string& n, const std::string& t) : name(n) , type(t) {}
+ structure_tree_node* add_child(const std::string& n, const std::string& t) {
+ auto hash = n+t;
+ auto child_itr = m_children.find(hash);
+ if (child_itr == m_children.end()) {
+ // add new child as we don't have one of this type yet
+ structure_tree_node* new_node = new structure_tree_node(n,t);
+ m_children[hash] = std::unique_ptr<structure_tree_node>(new_node);
+ return new_node;
+ } else {
+ // child of same type and name exists
+ return (*child_itr).second.get();
+ }
+ }
+ void add_size(size_t s) { size += s; }
+};
+
+class structure_tree
+{
+ public:
+ static structure_tree_node* add_child(structure_tree_node* v, const std::string& name, const std::string& type) {
+ if (v) return v->add_child(name,type);
+ return nullptr;
+ };
+ static void add_size(structure_tree_node* v, uint64_t value) {
+ if (v) v->add_size(value);
+ };
+};
+
+
+template<format_type F>
+void write_structure_tree(const structure_tree_node* v, std::ostream& out, size_t level = 0);
+
+
+}
+#endif
diff --git a/include/sdsl/suffix_array_algorithm.hpp b/include/sdsl/suffix_array_algorithm.hpp
new file mode 100644
index 0000000..8c06648
--- /dev/null
+++ b/include/sdsl/suffix_array_algorithm.hpp
@@ -0,0 +1,517 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file suffix_array_algorithm.hpp
+ \brief suffix_array_algorithm.hpp contains algorithms on CSAs
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SUFFIX_ARRAY_ALGORITHM
+#define INCLUDED_SDSL_SUFFIX_ARRAY_ALGORITHM
+
+#include <iterator>
+#include "suffix_array_helper.hpp"
+
+namespace sdsl
+{
+
+//! Backward search for a character c in an \f$\omega\f$-interval \f$[\ell..r]\f$ in the CSA.
+/*!
+ * \tparam t_csa CSA type.
+ *
+ * \param csa The CSA object.
+ * \param l Left border of the interval \f$ [\ell..r]\f$.
+ * \param r Right border of the interval \f$ [\ell..r]\f$.
+ * \param c Character to be prepended to \f$\omega\f$.
+ * \param l_res New left border.
+ * \param r_res Right border.
+ * \return The size of the new interval [\ell_{new}..r_{new}].
+ * Equals zero, if no match is found.
+ *
+ * \pre \f$ 0 \leq \ell \leq r < csa.size() \f$
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{rank\_bwt} } \f$
+ * \par Reference
+ * Paolo Ferragina, Giovanni Manzini:
+ * Opportunistic Data Structures with Applications.
+ * FOCS 2000: 390-398
+ */
+template<class t_csa>
+typename t_csa::size_type backward_search(
+ const t_csa& csa,
+ typename t_csa::size_type l,
+ typename t_csa::size_type r,
+ typename t_csa::char_type c,
+ typename t_csa::size_type& l_res,
+ typename t_csa::size_type& r_res,
+ SDSL_UNUSED typename std::enable_if<std::is_same<csa_tag, typename t_csa::index_category>::value, csa_tag>::type x = csa_tag()
+)
+{
+ assert(l <= r); assert(r < csa.size());
+ typename t_csa::size_type c_begin = csa.C[csa.char2comp[c]];
+ l_res = c_begin + csa.bwt.rank(l, c); // count c in bwt[0..l-1]
+ r_res = c_begin + csa.bwt.rank(r+1, c) - 1; // count c in bwt[0..r]
+ assert(r_res+1-l_res >= 0);
+ return r_res+1-l_res;
+}
+
+
+//! Backward search for a pattern in an \f$\omega\f$-interval \f$[\ell..r]\f$ in the CSA.
+/*!
+ * \tparam t_csa A CSA type.
+ * \tparam t_pat_iter Pattern iterator type.
+ *
+ * \param csa The CSA object.
+ * \param l Left border of the lcp-interval \f$ [\ell..r]\f$.
+ * \param r Right border of the lcp-interval \f$ [\ell..r]\f$.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \param l_res New left border.
+ * \param r_res New right border.
+ * \return The size of the new interval [\ell_{new}..r_{new}].
+ * Equals zero, if no match is found.
+ *
+ * \pre \f$ 0 \leq \ell \leq r < csa.size() \f$
+ *
+ * \par Time complexity
+ * \f$ \Order{ len \cdot t_{rank\_bwt} } \f$
+ * \par Reference
+ * Paolo Ferragina, Giovanni Manzini:
+ * Opportunistic Data Structures with Applications.
+ * FOCS 2000: 390-398
+ */
+template<class t_csa, class t_pat_iter>
+typename t_csa::size_type
+backward_search(
+ const t_csa& csa,
+ typename t_csa::size_type l,
+ typename t_csa::size_type r,
+ t_pat_iter begin,
+ t_pat_iter end,
+ typename t_csa::size_type& l_res,
+ typename t_csa::size_type& r_res,
+ SDSL_UNUSED typename std::enable_if<std::is_same<csa_tag, typename t_csa::index_category>::value, csa_tag>::type x = csa_tag()
+)
+{
+ t_pat_iter it = end;
+ while (begin < it and r+1-l > 0) {
+ --it;
+ backward_search(csa, l, r, (typename t_csa::char_type)*it, l, r);
+ }
+ l_res = l;
+ r_res = r;
+ return r+1-l;
+}
+
+//! Bidirectional search for a character c on an interval \f$[l_fwd..r_fwd]\f$ of the suffix array.
+/*!
+ * \param csa_fwd The CSA object of the forward text in which the backward_search should be done.
+ * \param l_fwd Left border of the lcp-interval \f$ [l_fwd..r_fwd]\f$ in suffix array of the forward text.
+ * \param r_fwd Right border of the lcp-interval \f$ [l_fwd..r_fwd]\f$ in suffix array of the forward text.
+ * \param l_bwd Left border of the lcp-interval \f$ [l_bwd..r_bwd]\f$ in suffix array of the backward text.
+ * \param r_bwd Right border of the lcp-interval \f$ [l_bwd..r_bwd]\f$ in suffix array of the backward text.
+ * \param c The character c which is the starting character of the suffixes in the resulting interval \f$ [l_fwd_res..r_fwd_res] \f$ .
+ * \param l_fwd_res Reference to the resulting left border in suffix array of the forward text.
+ * \param r_fwd_res Reference to the resulting right border in suffix array of the forward text.
+ * \param l_bwd_res Reference to the resulting left border in suffix array of the backward text.
+ * \param r_bwd_res Reference to the resulting right border in suffix array of the backward text.
+ * \return The size of the new interval [l_fwd_res..r_fwd_res].
+ * \pre \f$ 0 \leq \ell \leq r_fwd < csa_fwd.size() \f$
+ * \par Reference
+ * Thomas Schnattinger, Enno Ohlebusch, Simon Gog:
+ * Bidirectional search in a string with wavelet trees and bidirectional matching statistics.
+ * Inf. Comput. 213: 13-22
+ */
+template<class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+typename csa_wt<t_wt>::size_type bidirectional_search(
+ const csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa_fwd,
+ typename csa_wt<>::size_type l_fwd,
+ typename csa_wt<>::size_type r_fwd,
+ typename csa_wt<>::size_type l_bwd,
+ typename csa_wt<>::size_type r_bwd,
+ typename csa_wt<>::char_type c,
+ typename csa_wt<>::size_type& l_fwd_res,
+ typename csa_wt<>::size_type& r_fwd_res,
+ typename csa_wt<>::size_type& l_bwd_res,
+ typename csa_wt<>::size_type& r_bwd_res,
+ SDSL_UNUSED typename std::enable_if< t_wt::lex_ordered, csa_tag>::type x = csa_tag()
+)
+{
+ assert(l_fwd <= r_fwd); assert(r_fwd < csa_fwd.size());
+ typedef typename csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>::size_type size_type;
+ size_type c_begin = csa_fwd.C[csa_fwd.char2comp[c]];
+ auto r_s_b = csa_fwd.wavelet_tree.lex_count(l_fwd, r_fwd+1, c);
+ size_type rank_l = std::get<0>(r_s_b);
+ size_type s = std::get<1>(r_s_b), b = std::get<2>(r_s_b);
+ size_type rank_r = r_fwd - l_fwd - s - b + rank_l;
+ l_fwd_res = c_begin + rank_l;
+ r_fwd_res = c_begin + rank_r;
+ assert(r_fwd_res+1 >= l_fwd_res);
+ l_bwd_res = l_bwd + s;
+ r_bwd_res = r_bwd - b;
+ assert(r_bwd_res-l_bwd_res == r_fwd_res-l_fwd_res);
+ return r_fwd_res+1-l_fwd_res;
+}
+
+//! Bidirectional search in backward direction.
+/*!
+ * The function requires a pattern \f$p\f$, an \f$\omega\f$-interval \f$[l_fwd..r_fwd]\f$ in the CSA object
+ * of the forward text and an \f$\omega^{rev}\f$-interval \f$[l_bwd..r_bwd]\f$ in the CSA object of the backward text.
+ * The function returns the \f$p\omega\f$-interval in the CSA object of the forward text and
+ * the \f$\omega^{rev}p^{rev}\f$-interval in the CSA object of the backward text.
+ *
+ * \tparam t_pat_iter Pattern iterator type.
+ *
+ * \param csa_fwd The CSA object of the forward text.
+ * \param csa_bwd The CSA object of the backward text.
+ * \param l_fwd Left border of the lcp-interval \f$ [l_fwd..r_fwd]\f$ in suffix array of the forward text.
+ * \param r_fwd Right border of the lcp-interval \f$ [l_fwd..r_fwd]\f$ in suffix array of the forward text.
+ * \param l_bwd Left border of the lcp-interval \f$ [l_bwd..r_bwd]\f$ in suffix array of the backward text.
+ * \param r_bwd Right border of the lcp-interval \f$ [l_bwd..r_bwd]\f$ in suffix array of the backward text.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \param l_fwd_res Reference to the resulting left border in suffix array of the forward text.
+ * \param r_fwd_res Reference to the resulting right border in suffix array of the forward text.
+ * \param l_bwd_res Reference to the resulting left border in suffix array of the backward text.
+ * \param r_bwd_res Reference to the resulting right border in suffix array of the backward text.
+ * \return The size of the new interval [l_fwd_res..r_fwd_res].
+ * Equals zero, if no match is found.
+ *
+ * \pre \f$ 0 \leq \ell \leq r_fwd < csa_fwd.size() \f$
+ * \par Reference
+ * Thomas Schnattinger, Enno Ohlebusch, Simon Gog:
+ * Bidirectional search in a string with wavelet trees and bidirectional matching statistics.
+ * Inf. Comput. 213: 13-22
+ */
+template<class t_pat_iter, class t_wt, uint32_t t_dens, uint32_t t_inv_dens, class t_sa_sample_strat, class t_isa, class t_alphabet_strat>
+typename csa_wt<>::size_type bidirectional_search_backward(
+ const csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa_fwd,
+ SDSL_UNUSED const csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa_bwd,
+ typename csa_wt<>::size_type l_fwd,
+ typename csa_wt<>::size_type r_fwd,
+ typename csa_wt<>::size_type l_bwd,
+ typename csa_wt<>::size_type r_bwd,
+ t_pat_iter begin,
+ t_pat_iter end,
+ typename csa_wt<>::size_type& l_fwd_res,
+ typename csa_wt<>::size_type& r_fwd_res,
+ typename csa_wt<>::size_type& l_bwd_res,
+ typename csa_wt<>::size_type& r_bwd_res,
+ SDSL_UNUSED typename std::enable_if< t_wt::lex_ordered, csa_tag>::type x = csa_tag()
+)
+{
+ t_pat_iter it = end;
+ while (begin < it and r_fwd+1-l_fwd > 0) {
+ --it;
+ bidirectional_search(csa_fwd, l_fwd, r_fwd, l_bwd, r_bwd, (typename csa_wt<>::char_type)*it, l_fwd, r_fwd, l_bwd, r_bwd);
+ }
+ l_fwd_res = l_fwd;
+ r_fwd_res = r_fwd;
+ l_bwd_res = l_bwd;
+ r_bwd_res = r_bwd;
+ return r_fwd+1-l_fwd;
+}
+
+//! Bidirectional search in forward direction.
+/*!
+ * The function requires a pattern \f$p\f$, an \f$\omega\f$-interval \f$[l_fwd..r_fwd]\f$ in the CSA object
+ * of the forward text and an \f$\omega^{rev}\f$-interval \f$[l_bwd..r_bwd]\f$ in the CSA object of the backward text.
+ * The function returns the \f$\omega p\f$-interval in the CSA object of the forward text and
+ * the \f$\p^{rev}omega^{rev}\f$-interval in the CSA object of the backward text.
+ *
+ * \tparam t_pat_iter Pattern iterator type.
+ *
+ * \param csa_fwd The CSA object of the forward text.
+ * \param csa_bwd The CSA object of the backward text.
+ * \param l_fwd Left border of the lcp-interval \f$ [l_fwd..r_fwd]\f$ in suffix array of the forward text.
+ * \param r_fwd Right border of the lcp-interval \f$ [l_fwd..r_fwd]\f$ in suffix array of the forward text.
+ * \param l_bwd Left border of the lcp-interval \f$ [l_bwd..r_bwd]\f$ in suffix array of the backward text.
+ * \param r_bwd Right border of the lcp-interval \f$ [l_bwd..r_bwd]\f$ in suffix array of the backward text.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \param l_fwd_res Reference to the resulting left border in suffix array of the forward text.
+ * \param r_fwd_res Reference to the resulting right border in suffix array of the forward text.
+ * \param l_bwd_res Reference to the resulting left border in suffix array of the backward text.
+ * \param r_bwd_res Reference to the resulting right border in suffix array of the backward text.
+ * \return The size of the new interval [l_fwd_res..r_fwd_res].
+ * Equals zero, if no match is found.
+ *
+ * \pre \f$ 0 \leq \ell \leq r_fwd < csa_fwd.size() \f$
+ * \par Reference
+ * Thomas Schnattinger, Enno Ohlebusch, Simon Gog:
+ * Bidirectional search in a string with wavelet trees and bidirectional matching statistics.
+ * Inf. Comput. 213: 13-22
+ */
+template<class t_pat_iter,
+ class t_wt,
+ uint32_t t_dens,
+ uint32_t t_inv_dens,
+ class t_sa_sample_strat,
+ class t_isa,
+ class t_alphabet_strat>
+typename csa_wt<t_wt>::size_type
+bidirectional_search_forward(
+ SDSL_UNUSED const csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa_fwd,
+ const csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, t_alphabet_strat>& csa_bwd,
+ typename csa_wt<>::size_type l_fwd,
+ typename csa_wt<>::size_type r_fwd,
+ typename csa_wt<>::size_type l_bwd,
+ typename csa_wt<>::size_type r_bwd,
+ t_pat_iter begin,
+ t_pat_iter end,
+ typename csa_wt<>::size_type& l_fwd_res,
+ typename csa_wt<>::size_type& r_fwd_res,
+ typename csa_wt<>::size_type& l_bwd_res,
+ typename csa_wt<>::size_type& r_bwd_res,
+ SDSL_UNUSED typename std::enable_if< t_wt::lex_ordered, csa_tag>::type x = csa_tag()
+)
+{
+ t_pat_iter it = begin;
+ while (it < end and r_fwd+1-l_fwd > 0) {
+ bidirectional_search(csa_bwd, l_bwd, r_bwd, l_fwd, r_fwd, (typename csa_wt<>::char_type)*it, l_bwd, r_bwd, l_fwd, r_fwd);
+ ++it;
+ }
+ l_fwd_res = l_fwd;
+ r_fwd_res = r_fwd;
+ l_bwd_res = l_bwd;
+ r_bwd_res = r_bwd;
+ return r_fwd+1-l_fwd;
+}
+
+//! Counts the number of occurrences of a pattern in a CSA.
+/*!
+ * \tparam t_csa CSA type.
+ * \tparam t_pat_iter Pattern iterator type.
+ *
+ * \param csa The CSA object.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \return The number of occurrences of the pattern in the CSA.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{backward\_search} } \f$
+ */
+template<class t_csa, class t_pat_iter>
+typename t_csa::size_type count(
+ const t_csa& csa,
+ t_pat_iter begin,
+ t_pat_iter end,
+ csa_tag
+)
+{
+ if (end - begin > (typename std::iterator_traits<t_pat_iter>::difference_type)csa.size())
+ return 0;
+ typename t_csa::size_type t=0; // dummy variable for the backward_search call
+ typename t_csa::size_type result = backward_search(csa, 0, csa.size()-1, begin, end, t, t);
+ return result;
+}
+
+
+template<class t_csx, class t_pat_iter>
+typename t_csx::size_type count(
+ const t_csx& csx,
+ t_pat_iter begin,
+ t_pat_iter end
+)
+{
+ typename t_csx::index_category tag;
+ return count(csx, begin, end, tag);
+}
+
+//! Counts the number of occurrences of a pattern in a CSA.
+/*!
+ * \tparam t_csa CSA type.
+ *
+ * \param csa The CSA object.
+ * \param pat The pattern.
+ * \return The number of occurrences of the pattern in the CSA.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{backward\_search} } \f$
+ */
+
+template<class t_csx>
+typename t_csx::size_type count(
+ const t_csx& csx,
+ const typename t_csx::string_type& pat
+)
+{
+ typename t_csx::index_category tag;
+ return count(csx, pat.begin(), pat.end(), tag);
+}
+
+//! Calculates all occurrences of a pattern pat in a CSA.
+/*!
+ * \tparam t_csa CSA type.
+ * \tparam t_pat_iter Pattern iterator type.
+ * \tparam t_rac Resizeable random access container.
+ *
+ * \param csa The CSA object.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \return A vector containing the occurrences of the pattern in the CSA.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{backward\_search} + z \cdot t_{SA} } \f$, where \f$z\f$ is the number of
+ * occurrences of pattern in the CSA.
+ */
+template<class t_csa, class t_pat_iter, class t_rac=int_vector<64>>
+ t_rac locate(
+ const t_csa& csa,
+ t_pat_iter begin,
+ t_pat_iter end,
+ SDSL_UNUSED typename std::enable_if<std::is_same<csa_tag, typename t_csa::index_category>::value, csa_tag>::type x = csa_tag()
+ )
+{
+ typename t_csa::size_type occ_begin, occ_end, occs;
+ occs = backward_search(csa, 0, csa.size()-1, begin, end, occ_begin, occ_end);
+ t_rac occ(occs);
+ for (typename t_csa::size_type i=0; i < occs; ++i) {
+ occ[i] = csa[occ_begin+i];
+ }
+ return occ;
+}
+
+//! Calculates all occurrences of a pattern pat in a CSA/CST.
+/*!
+ * \tparam t_csa CSA/CST type.
+ * \tparam t_rac Resizeable random access container.
+ *
+ * \param csa The CSA/CST object.
+ * \param pat The pattern.
+ * \return A vector containing the occurrences of the pattern in the CSA.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{backward\_search} + z \cdot t_{SA} } \f$, where \f$z\f$ is the number of
+ * occurrences of pattern in the CSA.
+ */
+template<class t_csx, class t_rac=int_vector<64>>
+t_rac locate(
+ const t_csx& csx,
+ const typename t_csx::string_type& pat
+)
+{
+ typename t_csx::index_category tag;
+ return locate<t_csx, decltype(pat.begin()), t_rac>(csx, pat.begin(), pat.end(), tag);
+}
+
+
+//! Writes the substring T[begin..end] of the original text T to text[0..end-begin+1].
+/*!
+ * \tparam t_csa CSA type.
+ * \tparam t_text_iter Random access iterator type.
+ *
+ * \param csa The CSA object.
+ * \param begin Position of the first character which should be extracted (inclusive).
+ * \param end Position of the last character which should be extracted (inclusive).
+ * \param text Random access iterator pointing to the start of an container, which can hold at least (end-begin+1) character.
+ * \returns The length of the extracted text.
+ * \pre \f$begin <= end\f$ and \f$ end < csa.size() \f$
+ * \par Time complexity
+ * \f$ \Order{ (end-begin+1) \cdot t_{\Psi} + t_{SA^{-1}} } \f$
+ */
+template<class t_csa, class t_text_iter>
+typename t_csa::size_type extract(
+ const t_csa& csa,
+ typename t_csa::size_type begin,
+ typename t_csa::size_type end,
+ t_text_iter text,
+ SDSL_UNUSED typename std::enable_if<std::is_same<csa_tag, typename t_csa::index_category>::value, csa_tag>::type x = csa_tag()
+)
+{
+ typename t_csa::extract_category extract_tag;
+ return extract(csa, begin, end, text, extract_tag);
+}
+
+//! Specialization of extract for LF-function based CSAs
+template<class t_csa, class t_text_iter>
+typename t_csa::size_type extract(
+ const t_csa& csa,
+ typename t_csa::size_type begin,
+ typename t_csa::size_type end,
+ t_text_iter text,
+ lf_tag
+)
+{
+ assert(end < csa.size());
+ assert(begin <= end);
+ auto steps = end-begin+1;
+ if (steps > 0) {
+ auto order = csa.isa[end];
+ text[--steps] = first_row_symbol(order, csa);
+ while (steps != 0) {
+ auto rc = csa.wavelet_tree.inverse_select(order);
+ auto j = rc.first;
+ auto c = rc.second;
+ order = csa.C[ csa.char2comp[c] ] + j;
+ text[--steps] = c;
+ }
+ }
+ return end-begin+1;
+}
+
+//! Specialization of extract for \f$\Psi\f$-function based CSAs
+template<class t_csa, class t_text_iter>
+typename t_csa::size_type extract(
+ const t_csa& csa,
+ typename t_csa::size_type begin,
+ typename t_csa::size_type end,
+ t_text_iter text,
+ psi_tag
+)
+{
+ assert(end < csa.size());
+ assert(begin <= end);
+ typename t_csa::size_type steps = end-begin+1;
+ for (typename t_csa::size_type i=0, order = csa.isa[begin]; steps != 0; --steps, ++i) {
+ text[i] = first_row_symbol(order, csa);
+ if (steps != 0) order = csa.psi[order];
+ }
+ return end-begin+1;
+}
+
+//! Reconstructs the substring T[begin..end] of the original text T to text[0..end-begin+1].
+/*!
+ * \tparam t_rac Random access container which should hold the result.
+ * \tparam t_csa CSA type.
+ *
+ * \param csa The CSA object.
+ * \param begin Position of the first character which should be extracted (inclusive).
+ * \param end Position of the last character which should be extracted (inclusive).
+ * \return A t_rac object holding the extracted text.
+ * \pre \f$begin <= end\f$ and \f$ end < csa.size() \f$
+ * \par Time complexity
+ * \f$ \Order{ (end-begin+1) \cdot t_{\Psi} + t_{SA^{-1}} } \f$
+ */
+template<class t_csa>
+typename t_csa::string_type extract(
+ const t_csa& csa,
+ typename t_csa::size_type begin,
+ typename t_csa::size_type end,
+ SDSL_UNUSED typename std::enable_if<std::is_same<csa_tag, typename t_csa::index_category>::value, csa_tag>::type x = csa_tag()
+)
+{
+ assert(end <= csa.size());
+ assert(begin <= end);
+ typedef typename t_csa::string_type string_type;
+ string_type result(end-begin+1, (typename string_type::value_type)0);
+ extract(csa, begin, end, result.begin());
+ return result;
+}
+
+
+} // end namespace
+#endif
diff --git a/include/sdsl/suffix_array_helper.hpp b/include/sdsl/suffix_array_helper.hpp
new file mode 100644
index 0000000..7902d61
--- /dev/null
+++ b/include/sdsl/suffix_array_helper.hpp
@@ -0,0 +1,653 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file suffix_array_helper.hpp
+ \brief suffix_array_helper.hpp contains some helper classes for CSTs
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SUFFIX_ARRAY_HELPER
+#define INCLUDED_SDSL_SUFFIX_ARRAY_HELPER
+
+#include <stdint.h>
+#include <cstdlib>
+#include <cassert>
+#include "iterators.hpp"
+
+namespace sdsl
+{
+
+//! Get the symbol at position i in the first row of the sorted suffixes of CSA
+/*
+ * \param i Position in the first row.
+ * \param csa CSA
+ * \par Time complexity
+ * \f$ \Order{\log \sigma} \f$
+ * TODO: add hinted binary search? Two way binary search?
+*/
+template <class t_csa>
+typename t_csa::char_type first_row_symbol(const typename t_csa::size_type i, const t_csa& csa)
+{
+ assert(i < csa.size());
+ if (csa.sigma < 16) { //<- if sigma is small search linear
+ typename t_csa::size_type res=1;
+ while (res < csa.sigma and csa.C[res] <= i)
+ ++res;
+ return csa.comp2char[res-1];
+ } else {
+ // binary search the character with C
+ typename t_csa::size_type upper_c = csa.sigma, lower_c = 0; // lower_c inclusive, upper_c exclusive
+ typename t_csa::size_type res=0;
+ do {
+ res = (upper_c+lower_c)/2;
+ if (i < csa.C[res]) {
+ upper_c = res;
+ } else if (i >= csa.C[res+1]) {
+ lower_c = res+1;
+ }
+ } while (i < csa.C[res] or i >= csa.C[res+1]); // i is not in the interval
+ return csa.comp2char[res];
+ }
+
+}
+
+// psi[] trait
+template<class t_csa, bool t_direction>
+struct traverse_csa_psi_trait {
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ static value_type access(const t_csa& csa,size_type i) {
+ return csa.psi[i];
+ }
+};
+
+// lf[] trait
+template<class t_csa>
+struct traverse_csa_psi_trait<t_csa,false> {
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ static value_type access(const t_csa& csa,size_type i) {
+ // TODO: in case of a very sparse sampling of SA it may be faster to
+ // use \sigma binary searches on PSI function to determine the
+ // LF values.
+ return csa.isa[(csa[i]+csa.size()-1) % csa.size()];
+ }
+};
+
+template<class t_csa,bool t_direction>
+class traverse_csa_psi
+{
+ public:
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<traverse_csa_psi> const_iterator;
+
+ private:
+ const t_csa& m_csa;
+ public:
+ //! Constructor
+ traverse_csa_psi(const t_csa& csa_psi) : m_csa(csa_psi) { }
+ //! Copy constructor
+ traverse_csa_psi(const traverse_csa_psi& tcsa) : m_csa(tcsa.m_csa) { }
+
+ //! Calculate the \f$\Psi\f$ or \f$\LF\f$ value at position i.
+ /*! \param i The index for which the \f$\Psi\f$ or \f$\LF\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ return traverse_csa_psi_trait<t_csa,t_direction>::access(m_csa,i);
+ }
+
+ //! Returns the size of the \f$\Psi\f$ function.
+ size_type size() const {
+ return m_csa.size();
+ }
+
+ //! Returns if the \f$\Psi\f$ function is empty.
+ size_type empty() const {
+ return m_csa.empty();
+ }
+
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+// psi[] trait
+template<class t_csa,bool t_direction>
+struct traverse_csa_saisa_trait {
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ static value_type access(const t_csa& csa,size_type i) {
+ // \f$\Psi[i] = SA^{-1}[SA[i]+1 \mod n]\f$, where \f$n\f$ is the length of the suffix array SA
+ return csa.isa[(csa[i]+1) % csa.size() ];
+ }
+};
+
+// lf[] trait
+template<class t_csa>
+struct traverse_csa_saisa_trait<t_csa,false> {
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ static value_type access(const t_csa& csa,size_type i) {
+ // TODO: in case of a very sparse sampling of SA it may be faster to
+ // use \sigma binary searches on PSI function to determine the
+ // LF values.
+ return csa.isa[(csa[i]+csa.size()-1) % csa.size()];
+ }
+};
+
+//! A helper class for the \f$\Psi\f$ function for (compressed) suffix arrays which provide also the inverse suffix array values (like sdsl::csa_bitcompressed).
+template<class t_csa,bool t_direction>
+class traverse_csa_saisa
+{
+ public:
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<traverse_csa_saisa> const_iterator;// STL Container requirement
+ private:
+ const t_csa& m_csa;
+ public:
+ //! Constructor
+ traverse_csa_saisa(const t_csa& csa) : m_csa(csa) {}
+
+ // Copy constructor
+ traverse_csa_saisa(const traverse_csa_saisa& tcsa) : m_csa(tcsa.m_csa) {}
+
+ //! Calculate the \f$\Psi\f$ value at position i.
+ /*! \param i The index for which the \f$\Psi\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\saaccess+\isaaccess} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i<size());
+ return traverse_csa_saisa_trait<t_csa,t_direction>::access(m_csa,i);
+ }
+
+ //! Returns the size of the \f$\Psi\f$ function.
+ size_type size()const {
+ return m_csa.size();
+ }
+
+ //! Returns if the \f$\Psi\f$ function is empty.
+ size_type empty()const {
+ return m_csa,empty();
+ }
+
+ //! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+//! A wrapper for the bwt of a compressed suffix array that is based on the \f$\psi\f$ function.
+template<class t_csa>
+class bwt_of_csa_psi
+{
+ public:
+ typedef typename t_csa::char_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<bwt_of_csa_psi> const_iterator;
+ private:
+ const t_csa& m_csa; //<- pointer to the (compressed) suffix array that is based on the \f$\Psi\f$ function.
+ public:
+
+ //! Constructor
+ bwt_of_csa_psi(const t_csa& csa) : m_csa(csa) { }
+
+ //! Calculate the Burrows Wheeler Transform (BWT) at position i.
+ /*! \param i The index for which the BWT value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ size_type pos = m_csa.lf[i];
+ return first_row_symbol(pos,m_csa);
+ }
+
+ //! Calculates how many symbols c are in the prefix [0..i-1]
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in [0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1].
+ * \par Time complexity
+ * \f$ \Order{\log n t_{\Psi}} \f$
+ */
+ size_type rank(size_type i, const char_type c)const {
+ return m_csa.rank_bwt(i,c);
+ }
+
+ //! Calculates the position of the i-th c.
+ /*!
+ * \param i The i-th occurrence. \f$i\in [1..rank(size(),c)]\f$.
+ * \param c Symbol c.
+ * \returns The position of the i-th c or size() if c does occur less then i times.
+ * \par Time complexity
+ * \f$ \Order{t_{\Psi}} \f$
+ */
+ size_type select(size_type i, const char_type c)const {
+ return m_csa.select_bwt(i, c);
+ }
+
+ //! Returns the size of the \f$\Psi\f$ function.
+ size_type size()const {
+ return m_csa.size();
+ }
+
+ //! Returns if the bwt is empty.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+
+ //! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+// psi[] trait
+template<class t_csa,bool t_direction>
+struct traverse_csa_wt_traits {
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::size_type size_type;
+ static value_type access(const t_csa& csa,size_type i) {
+ char_type c = csa.F[i];
+ return csa.wavelet_tree.select(i - csa.C[csa.char2comp[c]] + 1 , c);
+ }
+};
+
+// lf[] trait
+template<class t_csa>
+struct traverse_csa_wt_traits<t_csa,false> {
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::size_type size_type;
+ static value_type access(const t_csa& csa,size_type i) {
+ typename t_csa::char_type c;
+ auto rc = csa.wavelet_tree.inverse_select(i);
+ size_type j = rc.first;
+ c = rc.second;
+ return csa.C[ csa.char2comp[c] ] + j;
+ }
+};
+
+
+//! A wrapper class for the \f$\Psi\f$ and LF function for (compressed) suffix arrays that are based on a wavelet tree (like sdsl::csa_wt).
+template<class t_csa,bool t_direction>
+class traverse_csa_wt
+{
+ public:
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<traverse_csa_wt> const_iterator;
+ private:
+ const t_csa& m_csa; //<- pointer to the (compressed) suffix array that is based on a wavelet tree
+ traverse_csa_wt() {}; // disable default constructor
+ public:
+ //! Constructor
+ traverse_csa_wt(const t_csa& csa_wt) : m_csa(csa_wt) {}
+ //! Calculate the \f$\Psi\f$ value at position i.
+ /*! \param i The index for which the \f$\Psi\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ value_type operator[](size_type i) const {
+ assert(i < m_csa.size());
+ return traverse_csa_wt_traits<t_csa,t_direction>::access(m_csa,i);
+ }
+
+ //! Returns the size of the \f$\Psi\f$ function.
+ size_type size()const {
+ return m_csa.size();
+ }
+ //! Returns if the \f$\Psi\f$ function is empty.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+template<class t_csa>
+class bwt_of_csa_wt
+{
+ public:
+ typedef const typename t_csa::char_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::char_type char_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<bwt_of_csa_wt> const_iterator;
+ private:
+ const t_csa& m_csa; //<- pointer to the (compressed) suffix array that is based on a wavelet tree
+ bwt_of_csa_wt() {}; // disable default constructor
+ public:
+ //! Constructor
+ bwt_of_csa_wt(const t_csa& csa_wt) : m_csa(csa_wt) {}
+ //! Calculate the Burrows Wheeler Transform (BWT) at position i.
+ /*! \param i The index for which the \f$\Psi\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ return m_csa.wavelet_tree[i];
+ }
+ //! Returns the size of the BWT function.
+ size_type size()const {
+ return m_csa.size();
+ }
+
+ //! Calculates how many symbols c are in the prefix [0..i-1].
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in [0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1].
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ size_type rank(size_type i, const char_type c)const {
+ return m_csa.rank_bwt(i, c);
+ }
+
+ //! Calculates the position of the i-th c.
+ /*!
+ * \param i The i-th occurrence. \f$i\in [1..rank(size(),c)]\f$.
+ * \param c Symbol c.
+ * \returns The position of the i-th c or size() if c does occur less then i times.
+ * \par Time complexity
+ * \f$ \Order{t_{\Psi}} \f$
+ */
+ size_type select(size_type i, const char_type c)const {
+ return m_csa.select(i, c);
+ }
+
+
+ //! Returns if the BWT function is empty.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+template<class t_csa>
+class isa_of_csa_wt
+{
+ public:
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<isa_of_csa_wt> const_iterator;
+ private:
+ const t_csa& m_csa; //<- pointer to the (compressed) suffix array that is based on a wavelet tree
+ isa_of_csa_wt() {}; // disable default constructor
+ public:
+ //! Constructor
+ isa_of_csa_wt(const t_csa& csa_wt) : m_csa(csa_wt) {}
+ //! Calculate the Burrows Wheeler Transform (BWT) at position i.
+ /*! \param i The index for which the \f$\Psi\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ size_type ii;
+ // get the leftmost sampled isa value to the right of i
+ value_type result = m_csa.isa_sample[ ii = ((i+m_csa.isa_sample_dens-1)/m_csa.isa_sample_dens) ];
+ ii *= m_csa.isa_sample_dens;
+ if (ii >= m_csa.size()) {
+ i = m_csa.size() - 1 - i;
+ } else {
+ i = ii - i;
+ }
+ while (i--) {
+ result = m_csa.lf[result];
+ }
+ return result;
+ }
+ //! Returns the size of the BWT function.
+ size_type size()const {
+ return m_csa.size();
+ }
+ //! Returns if the BWT function is empty.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+template<class t_csa>
+class isa_of_csa_psi
+{
+ public:
+ typedef typename t_csa::value_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<isa_of_csa_psi> const_iterator;
+ private:
+ const t_csa& m_csa; //<- pointer to the (compressed) suffix array that is based on a wavelet tree
+ isa_of_csa_psi() {}; // disable default constructor
+ public:
+ //! Constructor
+ isa_of_csa_psi(const t_csa& csa_wt) : m_csa(csa_wt) {}
+ //! Calculate the Burrows Wheeler Transform (BWT) at position i.
+ /*! \param i The index for which the \f$\Psi\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ // get the rightmost sampled isa value
+ value_type result = m_csa.isa_sample[i/m_csa.isa_sample_dens];
+ i = i % m_csa.isa_sample_dens;
+ while (i--) {
+ result = m_csa.psi[result];
+ }
+ return result;
+ }
+ //! Returns the size of the BWT function.
+ size_type size()const {
+ return m_csa.size();
+ }
+ //! Returns if the BWT function is empty.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+template<class t_csa>
+class first_row_of_csa
+{
+ public:
+ typedef const typename t_csa::char_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<first_row_of_csa> const_iterator;
+ private:
+ const t_csa& m_csa;
+ public:
+ //! Constructor
+ first_row_of_csa(const t_csa& csa) : m_csa(csa) {}
+ //! Calculate F[i]
+ /*! \param i The index for which the \f$\F\f$ value should be calculated, \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ return first_row_symbol(i,m_csa);
+ }
+ //! Returns the size of the F column.
+ size_type size()const {
+ return m_csa.size();
+ }
+ //! Returns if the F column is empty.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+
+template<class t_csa>
+class text_of_csa
+{
+ public:
+ typedef typename t_csa::char_type value_type;
+ typedef typename t_csa::size_type size_type;
+ typedef typename t_csa::difference_type difference_type;
+ typedef random_access_const_iterator<text_of_csa> const_iterator;
+ private:
+ const t_csa& m_csa;
+ text_of_csa() {}
+ public:
+
+ //! Constructor
+ text_of_csa(const t_csa& csa) : m_csa(csa) { }
+
+ //! Character at index \f$i\f$ of the original text.
+ /*! \param i Text position , \f$i\in [0..size()-1]\f$.
+ * \par Time complexity
+ * \f$ t_{ISA} \log\sigma \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ return first_row_symbol(m_csa.isa[i],m_csa);
+ }
+
+ //! Returns the size of the original text.
+ size_type size()const {
+ return m_csa.size();
+ }
+
+ //! Returns if text text has size 0.
+ size_type empty()const {
+ return m_csa.empty();
+ }
+
+ //! Returns a const_iterator to the first element.
+ /*! Required for the STL Container Concept.
+ * \sa end
+ */
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ /*! Required for the STL Container Concept.
+ * \sa begin.
+ */
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+};
+
+template<class t_csa, uint8_t int_width>
+void set_isa_samples(int_vector_buffer<int_width>& sa_buf, typename t_csa::isa_sample_type& isa_sample)
+{
+ typedef typename t_csa::size_type size_type;
+ auto n = sa_buf.size();
+ isa_sample.width(bits::hi(n)+1);
+ if (n >= 1) { // so n+t_csa::isa_sample_dens >= 2
+ isa_sample.resize((n-1+t_csa::isa_sample_dens-1)/t_csa::isa_sample_dens + 1);
+ }
+ util::set_to_value(isa_sample, 0);
+
+ for (size_type i=0; i < n; ++i) {
+ size_type sa = sa_buf[i];
+ if ((sa % t_csa::isa_sample_dens) == 0) {
+ isa_sample[sa/t_csa::isa_sample_dens] = i;
+ } else if (sa+1 == n) {
+ isa_sample[(sa+t_csa::isa_sample_dens-1)/t_csa::isa_sample_dens] = i;
+ }
+ }
+}
+
+
+}
+
+#endif
diff --git a/include/sdsl/suffix_arrays.hpp b/include/sdsl/suffix_arrays.hpp
new file mode 100644
index 0000000..5623d52
--- /dev/null
+++ b/include/sdsl/suffix_arrays.hpp
@@ -0,0 +1,57 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file suffix_arrays.hpp
+ \brief suffix_arrays.hpp contains generic classes for different suffix array classes.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SUFFIX_ARRAYS
+#define INCLUDED_SDSL_SUFFIX_ARRAYS
+
+#include "sdsl_concepts.hpp"
+
+/** \defgroup csa Compressed Suffix Arrays (CSA) */
+
+#include "csa_bitcompressed.hpp"
+#include "csa_wt.hpp"
+#include "csa_sada.hpp"
+#include "wavelet_trees.hpp"
+#include "construct.hpp"
+#include "suffix_array_algorithm.hpp"
+
+namespace sdsl
+{
+
+//! Typedef for convenient usage of std integer alphabet strategy
+template<class t_wt = wt_int<>,
+ uint32_t t_dens = 32,
+ uint32_t t_inv_dens = 64,
+ class t_sa_sample_strat = sa_order_sa_sampling<>,
+ class t_isa = int_vector<>
+ >
+using csa_wt_int = csa_wt<t_wt, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, int_alphabet<>>;
+
+template<class t_enc_vec = enc_vector<>, // Vector type used to store the Psi-function
+ uint32_t t_dens = 32, // Sample density for suffix array (SA) values
+ uint32_t t_inv_dens = 64, // Sample density for inverse suffix array (ISA) values
+ class t_sa_sample_strat = sa_order_sa_sampling<>,// Policy class for the SA sampling. Alternative text_order_sa_sampling.
+ class t_isa = int_vector<> // Container for the ISA samples.
+ >
+using csa_sada_int = csa_sada<t_enc_vec, t_dens, t_inv_dens, t_sa_sample_strat, t_isa, int_alphabet<>>;
+
+}
+
+#endif
diff --git a/include/sdsl/suffix_tree_algorithm.hpp b/include/sdsl/suffix_tree_algorithm.hpp
new file mode 100644
index 0000000..7ca5d42
--- /dev/null
+++ b/include/sdsl/suffix_tree_algorithm.hpp
@@ -0,0 +1,279 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file suffix_tree_algorithm.hpp
+ \brief suffix_tree_algorithm.hpp contains algorithms on CSTs
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SUFFIX_TREE_ALGORITHM
+#define INCLUDED_SDSL_SUFFIX_TREE_ALGORITHM
+
+#include <iterator>
+#include "suffix_array_algorithm.hpp"
+
+namespace sdsl
+{
+
+//! Forward search for a character c on the path on depth \f$d\f$ to node \f$v\f$.
+/*!
+ * \param cst The CST object
+ * \param v The node at the endpoint of the current edge.
+ * \param d The current depth of the path starting with 0.
+ * \param c The character c which should be matched with pathlabel_{root()..v}[d]
+ * \param char_pos T[char_pos-d+1..char_pos] matches with the already matched pattern P[0..d-1] or
+ * d=0 => char_pos=0.
+ * \return The number of the matching substrings in T.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{\Psi} } \f$ or \f$ \Order{t_{cst.child}} \f$
+ */
+template<class t_cst>
+typename t_cst::size_type
+forward_search(
+ const t_cst& cst,
+ typename t_cst::node_type& v,
+ const typename t_cst::size_type d,
+ const typename t_cst::char_type c,
+ typename t_cst::size_type& char_pos,
+ SDSL_UNUSED typename std::enable_if<std::is_same<cst_tag, typename t_cst::index_category>::value, cst_tag>::type x = cst_tag()
+)
+{
+ unsigned char cc = cst.csa.char2comp[c]; // check if c occurs in the text of the csa
+ if (cc==0 and cc!=c) // " " " " " " " " " "
+ return 0;
+ typename t_cst::size_type depth_node = cst.depth(v);
+ if (d < depth_node) { // in an edge, no branching
+ char_pos = cst.csa.psi[char_pos];
+ if (char_pos < cst.csa.C[cc] or char_pos >= cst.csa.C[cc+1])
+ return 0;
+ return cst.size(v);
+ } else if (d == depth_node) { // at a node, branching
+ v = cst.child(v, c, char_pos);
+ if (v == cst.root())
+ return 0;
+ else
+ return cst.size(v);
+ } else {
+ return 0;
+ }
+}
+
+//! Forward search for a pattern pat on the path on depth \f$d\f$ to node \f$v\f$.
+/*!
+ * \param cst The compressed suffix tree.
+ * \param v The node at the endpoint of the current edge.
+ * \param d The current depth of the path. 0 = first character on each edge of the root node.
+ * \param pat The character c which should be matched at the path on depth \f$d\f$ to node \f$v\f$.
+ * \param char_pos One position in the text, which corresponds to the text that is already matched. If v=cst.root() and d=0 => char_pos=0.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{\Psi} } \f$ or \f$ \Order{t_{cst.child}} \f$
+ */
+template<class t_cst, class t_pat_iter>
+typename t_cst::size_type
+forward_search(const t_cst& cst,
+ typename t_cst::node_type& v,
+ typename t_cst::size_type d,
+ t_pat_iter begin,
+ t_pat_iter end,
+ typename t_cst::size_type& char_pos,
+ SDSL_UNUSED typename std::enable_if<std::is_same<cst_tag, typename t_cst::index_category>::value, cst_tag>::type x = cst_tag()
+ )
+{
+ if (begin==end)
+ return cst.size(v);
+ typename t_cst::size_type size=0;
+ t_pat_iter it = begin;
+ while (it != end and (size=forward_search(cst, v, d, *it, char_pos))) {
+ ++d;
+ ++it;
+ }
+ return size;
+}
+
+//! Counts the number of occurrences of a pattern in a CST.
+/*!
+ * \tparam t_cst CST type.
+ * \tparam t_pat_iter Pattern iterator type.
+ *
+ * \param cst The CST object.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \return The number of occurrences of the pattern in the CSA.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{backward\_search} } \f$
+ */
+template<class t_cst, class t_pat_iter>
+typename t_cst::size_type count(
+ const t_cst& cst,
+ t_pat_iter begin,
+ t_pat_iter end,
+ cst_tag
+)
+{
+ return count(cst.csa, begin, end);
+}
+
+
+//! Calculates all occurrences of a pattern pat in a CST.
+/*!
+ * \tparam t_cst CST type.
+ * \tparam t_pat_iter Pattern iterator type.
+ * \tparam t_rac Resizeable random access container.
+ *
+ * \param cst The CST object.
+ * \param begin Iterator to the begin of the pattern (inclusive).
+ * \param end Iterator to the end of the pattern (exclusive).
+ * \return A vector containing the occurrences of the pattern in the CST.
+ *
+ * \par Time complexity
+ * \f$ \Order{ t_{backward\_search} + z \cdot t_{SA} } \f$, where \f$z\f$ is the number of
+ * occurrences of pattern in the CST.
+ */
+template<class t_cst, class t_pat_iter, class t_rac=int_vector<64>>
+t_rac locate(
+ const t_cst& cst,
+ t_pat_iter begin,
+ t_pat_iter end,
+ SDSL_UNUSED typename std::enable_if<std::is_same<cst_tag, typename t_cst::index_category>::value, cst_tag>::type x = cst_tag()
+)
+{
+ return locate(cst.csa, begin, end);
+}
+
+//! Calculate the concatenation of edge labels from the root to the node v of a CST.
+/*!
+ * \tparam t_cst CST type.
+ * \tparam t_text_iter Random access iterator type.
+ *
+ * \param cst The CST object.
+ * \param v The node where the concatenation of the edge label ends.
+ * \param text Random access iterator pointing to the start of an container, which can hold at least (end-begin+1) character.
+ * \returns The length of the extracted edge label.
+ * \pre text has to be initialized with enough memory (\f$ cst.depth(v)+1\f$ bytes) to hold the extracted text.
+ */
+template<class t_cst, class t_text_iter>
+typename t_cst::size_type extract(
+ const t_cst& cst,
+ const typename t_cst::node_type& v,
+ t_text_iter text,
+ SDSL_UNUSED typename std::enable_if<std::is_same<cst_tag, typename t_cst::index_category>::value, cst_tag>::type x = cst_tag()
+)
+{
+ if (v == cst.root()) {
+ text[0] = 0;
+ return 0;
+ }
+ // first get the suffix array entry of the leftmost leaf in the subtree rooted at v
+ typename t_cst::size_type begin = cst.csa[cst.lb(v)];
+ // then call the extract method on the compressed suffix array
+ extract(cst.csa, begin, begin + cst.depth(v) - 1, text);
+}
+
+//! Calculate the concatenation of edge labels from the root to the node v of of c CST.
+/*!
+ * \tparam t_rac Random access container which should hold the result.
+ * \tparam t_cst CSA type.
+
+ * \param cst The CST object.
+ * \return A t_rac object holding the extracted edge label.
+ * \return The string of the concatenated edge labels from the root to the node v.
+ */
+template<class t_cst>
+typename t_cst::csa_type::string_type
+extract(
+ const t_cst& cst,
+ const typename t_cst::node_type& v,
+ SDSL_UNUSED typename std::enable_if<std::is_same<cst_tag, typename t_cst::index_category>::value, cst_tag>::type x = cst_tag()
+)
+{
+ typedef typename t_cst::csa_type::string_type t_rac;
+ if (v==cst.root()) {
+ return t_rac(0);
+ }
+ // first get the suffix array entry of the leftmost leaf in the subtree rooted at v
+ typename t_cst::size_type begin = cst.csa[cst.lb(v)];
+ // then call the extract method on the compressed suffix array
+ return extract(cst.csa, begin, begin + cst.depth(v) - 1);
+}
+
+
+
+//! Calculate the zeroth order entropy of the text that follows a certain substring s
+/*!
+ * \param v A suffix tree node v. The label of the path from the root to v is s.
+ * \param cst The suffix tree of v.
+ * \return The zeroth order entropy of the concatenation of all characters that follow
+ s in the original text.
+ */
+template<class t_cst>
+double H0(const typename t_cst::node_type& v, const t_cst& cst)
+{
+ if (cst.is_leaf(v)) {
+ return 0;
+ } else {
+ double h0=0;
+ auto n = cst.size(v);
+ for (const auto& child : cst.children(v)) {
+ double p = ((double)cst.size(child))/n;
+ h0 -= p*log2(p);
+ }
+ return h0;
+ }
+}
+
+//! Calculate the k-th order entropy of a text
+/*!
+ * \param cst The suffix tree.
+ * \param k Parameter k for which H_k should be calculated.
+ * \return H_k and the number of contexts.
+ */
+template<class t_cst>
+std::pair<double,size_t> Hk(const t_cst& cst, typename t_cst::size_type k)
+{
+ double hk = 0;
+ size_t context = 0;
+ std::set<typename t_cst::size_type> leafs_with_d_smaller_k;
+ for (typename t_cst::size_type d = 1; d < k; ++d) {
+ leafs_with_d_smaller_k.insert(cst.csa.isa[cst.csa.size()-d]);
+ }
+ for (typename t_cst::const_iterator it = cst.begin(), end=cst.end(); it != end; ++it) {
+ if (it.visit() == 1) {
+ if (!cst.is_leaf(*it)) {
+ typename t_cst::size_type d = cst.depth(*it);
+ if (d >= k) {
+ if (d == k) {
+ hk += cst.size(*it) * H0(*it, cst);
+ }
+ ++context;
+ it.skip_subtree();
+ }
+ } else {
+ // if d of leaf is >= k, add context
+ if (leafs_with_d_smaller_k.find(cst.lb(*it)) == leafs_with_d_smaller_k.end()) {
+ ++context;
+ }
+ }
+ }
+ }
+ hk /= cst.size();
+ return {hk,context};
+}
+
+
+} // end namespace
+#endif
diff --git a/include/sdsl/suffix_tree_helper.hpp b/include/sdsl/suffix_tree_helper.hpp
new file mode 100644
index 0000000..8850052
--- /dev/null
+++ b/include/sdsl/suffix_tree_helper.hpp
@@ -0,0 +1,288 @@
+#ifndef INCLUDED_SDSL_SUFFIX_TREE_HELPER
+#define INCLUDED_SDSL_SUFFIX_TREE_HELPER
+
+#include <stdint.h>
+#include <cstdlib>
+#include <cassert>
+#include <stack>
+#include "sorted_multi_stack_support.hpp"
+#include "sorted_stack_support.hpp"
+#include "iterators.hpp"
+
+namespace sdsl
+{
+
+
+template <class t_cst>
+class cst_node_child_proxy_iterator : public std::iterator<std::forward_iterator_tag, typename t_cst::node_type>
+{
+ public:
+ using node_type = typename t_cst::node_type;
+ using value_type = node_type;
+ using const_reference = const node_type;
+ using iterator_type = cst_node_child_proxy_iterator<t_cst>;
+ private:
+ const t_cst* m_cst;
+ node_type m_cur_node;
+ public:
+ cst_node_child_proxy_iterator() : m_cst(nullptr) {};
+ cst_node_child_proxy_iterator(const t_cst* cst,const node_type& v) : m_cst(cst) , m_cur_node(v) {}
+ cst_node_child_proxy_iterator(const iterator_type& it): m_cst(it.m_cst), m_cur_node(it.m_cur_node) {}
+ public:
+ const_reference operator*() const {
+ return m_cur_node;
+ }
+ iterator_type& operator++() {
+ m_cur_node = m_cst->sibling(m_cur_node);
+ return *this;
+ }
+ iterator_type& operator++(int) {
+ iterator_type it = *this;
+ ++(*this);
+ return it;
+ }
+ bool operator==(const iterator_type& it)const {
+ return it.m_cur_node == m_cur_node;
+ }
+ bool operator!=(const iterator_type& it)const {
+ return !(*this==it);
+ }
+};
+
+template <class t_cst>
+class cst_node_child_proxy
+{
+ public: // types
+ using iterator_type = cst_node_child_proxy_iterator<t_cst>;
+ using node_type = typename t_cst::node_type;
+ using size_type = typename t_cst::size_type;
+ private: // data
+ const node_type& m_parent;
+ const t_cst* m_cst;
+ public: // constructors
+ cst_node_child_proxy() = delete;
+ explicit cst_node_child_proxy(const t_cst* cst,const node_type& v) : m_parent(v) , m_cst(cst) {};
+ cst_node_child_proxy(const cst_node_child_proxy& p) : m_parent(p.m_parent) , m_cst(p.m_cst) {};
+ public: // methods
+ node_type operator[](size_type i) const { return m_cst->select_child(m_parent,i+1); } // enumeration starts with 1 not 0
+ size_type size() { return m_cst->degree(m_parent); }
+ iterator_type begin() const { return iterator_type(m_cst,m_cst->select_child(m_parent,1)); }
+ iterator_type end() const { return iterator_type(m_cst,m_cst->root()); }
+};
+
+//! Calculate the balanced parentheses of the Super-Cartesian tree, described in Ohlebusch and Gog (SPIRE 2009).
+/*! \param vec Random access container for which the Super-Cartesian tree representation should be calculated.
+ * The value_type of vec should be an unsigned integer type.
+ * \param bp Reference to the balanced parentheses sequence which represents the Super-Cartesian tree.
+ * \param minimum Specifies if the higher levels contains minima or maxima. Default is maxima.
+ * \par Time complexity
+ * \f$ \Order{2n} \f$, where \f$ n=\f$vec.size()
+ * \par Space complexity
+ * \f$ \Order{n \cdot \log n } \f$ bits.
+ */
+template<class t_rac>
+void construct_supercartesian_tree_bp(const t_rac& vec, bit_vector& bp, const bool minimum=true)
+{
+ typedef typename t_rac::size_type size_type;
+ bp.resize(2*vec.size()); // resize bit vector for balanaced parantheses to 2 n bits
+ util::set_to_value(bp, 0);
+ std::stack<typename t_rac::value_type> vec_stack;
+
+ size_type k=0;
+ for (size_type i=0; i < vec.size(); ++i) {
+ typename t_rac::value_type l = vec[i];
+ if (minimum) {
+ while (vec_stack.size() > 0 and l < vec_stack.top()) {
+ vec_stack.pop(); ++k; /*bp[k++] = 0; bp is already initialized to zero*/ // writing a closing parenthesis
+ }
+
+ } else {
+ while (vec_stack.size() > 0 and l > vec_stack.top()) {
+ vec_stack.pop(); ++k; /*bp[k++] = 0; bp is already initialized to zero*/ // writing a closing parenthesis
+ }
+ }
+ vec_stack.push(l);
+ bp[k++] = 1; // writing an opening parenthesis
+ }
+ while (vec_stack.size() > 0) {
+ vec_stack.pop();
+ bp[k++] = 0; // writing a closing parenthesis
+ }
+ assert(k == 2*vec.size());
+}
+
+//! Calculate the balanced parentheses of the Super-Cartesian tree, described in Ohlebusch and Gog (SPIRE 2009).
+/*! \param vec Random access container for which the Super-Cartesian tree representation should be calculated.
+ * The value_type of vec should be an unsigned integer type.
+ * \param minimum Specifies if the higher levels contains minima or maxima. Default is maxima.
+ * \return The balanced parentheses sequence representing the Super-Cartesian tree.
+ * \par Time complexity
+ * \f$ \Order{2n} \f$, where \f$ n=\f$vec.size()
+ * \par Space complexity
+ * \f$\Order{n}\f$ bits
+ */
+template<class t_rac>
+bit_vector
+construct_supercartesian_tree_bp_succinct(const t_rac& vec, const bool minimum=true)
+{
+ typedef typename t_rac::size_type size_type;
+ bit_vector bp(2*vec.size(), 0); // initialize result
+ if (vec.size() > 0) {
+ sorted_stack_support vec_stack(vec.size());
+
+ size_type k=0;
+ if (minimum) {
+ bp[k++] = 1;
+ for (size_type i=1; i < vec.size(); ++i) {
+ if (vec[i] < vec[i-1]) {
+ ++k;
+ while (vec_stack.size() > 0 and vec[i] < vec[vec_stack.top()]) {
+ vec_stack.pop(); ++k; // writing a closing parenthesis, bp is already initialized to zero
+ }
+ } else {
+ vec_stack.push(i-1); // "lazy stack" trick: speed-up approx. 25%
+ }
+ bp[k++] = 1; // writing an opening parenthesis
+ }
+ } else {
+ // no "lazy stack" trick used here
+ for (size_type i=0; i < vec.size(); ++i) {
+ while (vec_stack.size() > 0 and vec[i] > vec[vec_stack.top()]) {
+ vec_stack.pop(); ++k; /*bp[k++] = 0; bp is already initialized to zero*/ // writing a closing parenthesis
+ }
+ vec_stack.push(i);
+ bp[k++] = 1; // writing an opening parenthesis
+ }
+ }
+ }
+ return bp;
+}
+
+//! Calculate the balanced parentheses of the Super-Cartesian tree, described in Ohlebusch and Gog (SPIRE 2009).
+/*! \param lcp_buf int_vector_buffer of the LCP Array for which the Super-Cartesian tree representation should be calculated.
+ * The value_type of vec should be an unsigned integer type.
+ * \param minimum Specifies if the higher levels contains minima or maxima. Default is maxima.
+ * \return The balanced parentheses sequence representing the Super-Cartesian tree.
+ * \par Time complexity
+ * \f$ \Order{2n} \f$, where \f$ n=\f$vec.size()
+ * \par Space complexity
+ * \f$\Order{2n}\f$ bits, by the multi_stack_support
+ * \pre
+ * The largest value in lcp_buf has to be smaller than lcp_buf.size().
+ */
+template<uint8_t t_width>
+bit_vector
+construct_supercartesian_tree_bp_succinct(int_vector_buffer<t_width>& lcp_buf, const bool minimum=true)
+{
+ typedef bit_vector::size_type size_type;
+ bit_vector bp(2*lcp_buf.size(), 0); // initialize result
+ if (lcp_buf.size() > 0) {
+ sorted_multi_stack_support vec_stack(lcp_buf.size());
+
+ size_type k=0;
+ if (minimum) {
+ bp[k++] = 1;
+ size_type last = lcp_buf[0];
+ for (size_type i=1, x; i < lcp_buf.size(); ++i) {
+ x = lcp_buf[i];
+ if (x < last) {
+ ++k; // writing a closing parenthesis for last
+ while (!vec_stack.empty() and x < vec_stack.top()) {
+ vec_stack.pop(); ++k; // writing a closing parenthesis, bp is already initialized to zeros
+ }
+ } else {
+ vec_stack.push(last); // "lazy stack" trick: speed-up about 25 %
+ }
+ bp[k++] = 1; // writing an opening parenthesis
+ last = x;
+ }
+ } else {
+ // no "lazy stack" trick use here
+ for (size_type i=0, x; i < lcp_buf.size(); ++i) {
+ x = lcp_buf[i];
+ while (!vec_stack.empty() and x > vec_stack.top()) {
+ vec_stack.pop(); ++k; // writing a closing parenthesis, bp is already initialized to zeros
+ }
+ vec_stack.push(x);
+ bp[k++] = 1; // writing an opening parenthesis
+ }
+ }
+ }
+ return bp;
+}
+
+//! Calculate the balanced parentheses of the Super-Cartesian tree, described in Ohlebusch and Gog (SPIRE 2009) and the first_child bit_vector
+/*! \param lcp_buf int_vector_buffer for the lcp array for which the Super-Cartesian tree representation should be calculated.
+ * The value_type of vec should be an unsigned integer type.
+ * \param bp Reference to the balanced parentheses sequence which represents the Super-Cartesian tree.
+ * \param bp_fc Reference to the first child bit_vector of bp.
+ * \param minimum Specifies if the higher levels contains minima or maxima. Default is maxima.
+ * \par Time complexity
+ * \f$ \Order{2n} \f$, where \f$ n=\f$vec.size()
+ * \par Space complexity
+ * \f$\Order{2n}\f$ bits, by the multi_stack_support
+ */
+template<uint8_t t_width>
+bit_vector::size_type
+construct_supercartesian_tree_bp_succinct_and_first_child(int_vector_buffer<t_width>& lcp_buf, bit_vector& bp, bit_vector& bp_fc, const bool minimum=true)
+{
+ typedef bit_vector::size_type size_type;
+ size_type n = lcp_buf.size();
+ bp.resize(2*n); // resize bit vector for balanced parentheses to 2 n bits
+ bp_fc.resize(n);
+ if (n == 0) // if n == 0 we are done
+ return 0;
+ size_type fc_cnt=0; // first child counter
+ util::set_to_value(bp, 0);
+ util::set_to_value(bp_fc, 0);
+ sorted_multi_stack_support vec_stack(n);
+
+ size_type k=0;
+ size_type k_fc=0; // first child index
+ if (minimum) {
+ // no "lazy stack" trick used here
+ for (size_type i=0, x; i < n; ++i) {
+ x = lcp_buf[i];
+ while (!vec_stack.empty() and x < vec_stack.top()) {
+ if (vec_stack.pop()) {
+ bp_fc[k_fc] = 1;
+ ++fc_cnt;
+ }
+ ++k; // writing a closing parenthesis, bp is already initialized to zeros
+ ++k_fc; // write a bit in first_child
+ }
+ vec_stack.push(x);
+ bp[k++] = 1; // writing an opening parenthesis
+ }
+
+ } else {
+ // no "lazy stack" trick used here
+ for (size_type i=0, x; i < n; ++i) {
+ x = lcp_buf[i];
+ while (!vec_stack.empty() and x > vec_stack.top()) {
+ if (vec_stack.pop()) {
+ bp_fc[k_fc] = 1;
+ ++fc_cnt;
+ }
+ ++k; // writing a closing parenthesis, bp is already initialized to zeros
+ ++k_fc; // write a bit in first_child
+ }
+ vec_stack.push(x);
+ bp[k++] = 1; // writing an opening parenthesis
+ }
+ }
+ while (!vec_stack.empty()) {
+ if (vec_stack.pop()) {
+ bp_fc[k_fc] = 1;
+ ++fc_cnt;
+ }
+ // writing a closing parenthesis in bp, not necessary as bp is initialized with zeros
+ ++k;
+ ++k_fc;
+ }
+ return fc_cnt;
+}
+
+}
+
+#endif
diff --git a/include/sdsl/suffix_trees.hpp b/include/sdsl/suffix_trees.hpp
new file mode 100644
index 0000000..6e47031
--- /dev/null
+++ b/include/sdsl/suffix_trees.hpp
@@ -0,0 +1,81 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file suffix_trees.hpp
+ \brief suffix_trees.hpp contains generic classes for different suffix tree classes.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_SUFFIX_TREES
+#define INCLUDED_SDSL_SUFFIX_TREES
+
+#include "sdsl_concepts.hpp"
+#include "suffix_arrays.hpp"
+#include "suffix_tree_algorithm.hpp"
+#include "construct.hpp"
+#include "util.hpp"
+#include <iostream>
+#include <cmath>
+#include <set>
+
+using std::cout;
+using std::endl;
+
+namespace sdsl
+{
+
+// Gets ISA[SA[idx]+d]
+// d = depth of the character 0 = first position
+template<class t_csa>
+typename t_csa::size_type get_char_pos(typename t_csa::size_type idx, typename t_csa::size_type d, const t_csa& csa)
+{
+ if (d == 0)
+ return idx;
+ // if we have to apply \f$\LF\f$ or \f$\Phi\f$ more
+ // than 2*d times to calc csa(csa[idx]+d), we opt to
+ // apply \f$ \Phi \f$ d times
+ if (csa.sa_sample_dens + csa.isa_sample_dens > 2*d+2) {
+ for (typename t_csa::size_type i=0; i < d; ++i)
+ idx = csa.psi[idx];
+ return idx;
+ }
+ return csa.isa[csa[idx] + d];
+}
+
+}
+
+/** \defgroup cst Compressed Suffix Trees (CST)
+ * This group contains data structures for compressed suffix trees. The following methods are supported:
+ * - root()
+ * - child(v,c)
+ * - select_child(v)
+ * - select_leaf(i)
+ * - parent(v)
+ * - sl(v)
+ * - lca(v,w)
+ * - ..
+ */
+
+#include "suffix_tree_helper.hpp"
+#include "cst_sct3.hpp"
+#include "cst_sada.hpp"
+
+#include "csa_bitcompressed.hpp"
+#include "int_vector.hpp"
+
+#include <iostream>
+#include <string>
+
+#endif
diff --git a/include/sdsl/uint128_t.hpp b/include/sdsl/uint128_t.hpp
new file mode 100644
index 0000000..855dd20
--- /dev/null
+++ b/include/sdsl/uint128_t.hpp
@@ -0,0 +1,36 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog, Matthias Petri
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file uint128_t.hpp
+ \brief uint128_t.hpp contains contains the definition of a 128-bit unsigned integer type.
+ \author Simon Gog, Matthias Petri
+*/
+#ifndef INCLUDED_SDSL_UINT128
+#define INCLUDED_SDSL_UINT128
+
+#include <iostream>
+#include "bits.hpp"
+
+namespace sdsl
+{
+
+typedef unsigned int uint128_t __attribute__((mode(TI)));
+
+std::ostream& operator<<(std::ostream& os, const uint128_t& x);
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/uint256_t.hpp b/include/sdsl/uint256_t.hpp
new file mode 100644
index 0000000..b93a42e
--- /dev/null
+++ b/include/sdsl/uint256_t.hpp
@@ -0,0 +1,255 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file uint256_t.hpp
+ \brief uint256_t.hpp contains a class for 256-bit unsigned integers.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_UINT256
+#define INCLUDED_SDSL_UINT256
+
+#include <iostream>
+#include "bits.hpp"
+#include "uint128_t.hpp"
+
+namespace sdsl
+{
+
+class uint256_t
+{
+ public:
+ friend std::ostream& operator << (std::ostream&, const uint256_t&);
+ private:
+ uint64_t m_lo;
+ uint64_t m_mid;
+ uint128_t m_high;
+
+ public:
+ inline uint256_t(uint64_t lo=0, uint64_t mid=0, uint128_t high=0):m_lo(lo),
+ m_mid(mid), m_high(high) {}
+
+ inline uint256_t(const uint256_t& x):m_lo(x.m_lo), m_mid(x.m_mid),
+ m_high(x.m_high) {}
+
+ inline uint256_t(uint256_t&& x):m_lo(std::move(x.m_lo)),
+ m_mid(std::move(x.m_mid)), m_high(std::move(x.m_high)) {}
+
+ uint256_t& operator=(const uint256_t& x) {
+ m_lo = x.m_lo;
+ m_mid = x.m_mid;
+ m_high = x.m_high;
+ return *this;
+ }
+
+ uint256_t& operator=(uint256_t&& x) {
+ m_lo = std::move(x.m_lo);
+ m_mid = std::move(x.m_mid);
+ m_high = std::move(x.m_high);
+ return *this;
+ }
+
+ inline uint16_t popcount() {
+ return ((uint16_t)bits::cnt(m_lo)) + bits::cnt(m_mid)
+ + bits::cnt(m_high>>64) + bits::cnt(m_high);
+ }
+
+ inline uint16_t hi() {
+ if (m_high == 0) {
+ if (m_mid) {
+ return bits::hi(m_mid) + 64;
+ } else {
+ return bits::hi(m_lo);
+ }
+ } else {
+ uint64_t hh = (m_high >> 64);
+ if (hh) {
+ return bits::hi(hh) + 192;
+ } else {
+ return bits::hi(m_high) + 128;
+ }
+ }
+ }
+
+ inline uint16_t select(uint32_t i) {
+ uint16_t x = 0;
+ if ((x=bits::cnt(m_lo)) >= i) {
+ return bits::sel(m_lo, i);
+ }
+ i -= x;
+ if ((x=bits::cnt(m_mid)) >= i) {
+ return bits::sel(m_mid, i) + 64;
+ }
+ i -= x;
+ uint64_t hh = m_high >> 64;
+ uint64_t lh = m_high;
+ if ((x=bits::cnt(lh)) >= i) {
+ return bits::sel(lh, i) + 128;
+ }
+ i -= x;
+ return bits::sel(hh, i) + 192;
+ }
+
+ inline uint256_t& operator+=(const uint256_t& x) {
+ uint128_t lo = (uint128_t)m_lo + x.m_lo;
+ uint128_t mid = (uint128_t)m_mid + x.m_mid + (lo >> 64);
+ m_lo = lo; m_mid = mid;
+ m_high += x.m_high + (mid >> 64);
+ return *this;
+// return uint256_t(lo, mid, m_high + x.m_high + (mid >> 64));
+ }
+
+ inline uint256_t operator+(const uint256_t& x) {
+ uint128_t lo = ((uint128_t)m_lo) + x.m_lo;
+ uint128_t mid = (uint128_t)m_mid + x.m_mid + (lo >> 64);
+ return uint256_t(lo, mid, m_high + x.m_high + (mid >> 64));
+ }
+
+ inline uint256_t operator-(const uint256_t& x) {
+// add two's complement of x
+ uint128_t lo = (uint128_t)m_lo + (~x.m_lo) + 1;
+ uint128_t mid = (uint128_t)m_mid + (~x.m_mid) + (lo >> 64);
+ return uint256_t(lo, mid, m_high + (~x.m_high) + (mid >> 64));
+ }
+
+ inline uint256_t& operator-=(const uint256_t& x) {
+// add two's complement of x
+ uint128_t lo = (uint128_t)m_lo + (~x.m_lo) + 1;
+ uint128_t mid = (uint128_t)m_mid + (~x.m_mid) + (lo >> 64);
+ m_lo = lo;
+ m_mid = mid;
+ m_high += (~x.m_high) + (mid >> 64);
+ return *this;
+ }
+
+
+ inline uint256_t operator|(const uint256_t& x) {
+ return uint256_t(m_lo|x.m_lo, m_mid|x.m_mid, m_high|x.m_high);
+ }
+
+ inline uint256_t& operator|=(const uint256_t& x) {
+ m_lo |= x.m_lo; m_mid |= x.m_mid; m_high |= x.m_high;
+ return *this;
+ }
+
+ inline uint256_t operator&(const uint256_t& x) {
+ return uint256_t(m_lo&x.m_lo, m_mid&x.m_mid, m_high&x.m_high);
+ }
+ /* // is not needed since we can convert uint256_t to uint64_t
+ uint64_t operator&(uint64_t x){
+ return m_lo & x;
+ }
+ */
+
+ inline uint256_t operator<<(int x) {
+ if (x < 128) {
+ uint128_t high = m_high << x;
+ uint128_t low = (((uint128_t)m_mid<<64) | m_lo);
+ high |= (low >> (128-x));
+ low = low << x;
+ return uint256_t(low, low>>64, high);
+ } else { // x >= 128
+ uint128_t high = (((uint128_t)m_mid<<64) | m_lo) << (x-128); // TODO: check x==128
+ return uint256_t(0, 0, high);
+ }
+ }
+
+ inline uint256_t operator>>(int x) {
+ if (x < 128) {
+ uint128_t low = (((uint128_t)m_mid<<64) | m_lo) >> x;
+ low |= ((m_high << (127-x))<<1);
+ return uint256_t(low, low>>64, m_high>>x);
+ } else { // x >= 128
+ uint128_t low = (m_high >> (x-128)); // TODO: check x=128
+ return uint256_t(low, low>>64, 0);
+ }
+ }
+
+ inline uint256_t& operator=(const uint64_t& x) {
+ m_high = 0;
+ m_mid = 0;
+ m_lo = x;
+ return *this;
+ }
+
+ inline bool operator==(const uint256_t& x) const {
+ return (m_lo == x.m_lo) and (m_mid == x.m_mid) and (m_high == x.m_high);
+ }
+
+ inline bool operator!=(const uint256_t& x) const {
+ return !(*this == x);
+ }
+
+ inline bool operator>=(const uint256_t& x) const {
+ if (m_high != x.m_high) {
+ return m_high > x.m_high;
+ }
+ if (m_mid != x.m_mid) {
+ return m_mid > x.m_mid;
+ } else {
+ return m_lo >= x.m_lo;
+ }
+ }
+
+ inline bool operator<=(const uint256_t& x) const {
+ if (m_high != x.m_high) {
+ return m_high < x.m_high;
+ }
+ if (m_mid != x.m_mid) {
+ return m_mid < x.m_mid;
+ } else {
+ return m_lo <= x.m_lo;
+ }
+ }
+
+ inline bool operator>(const uint256_t& x) const {
+ if (m_high != x.m_high) {
+ return m_high > x.m_high;
+ }
+ if (m_mid != x.m_mid) {
+ return m_mid > x.m_mid;
+ } else {
+ return m_lo > x.m_lo;
+ }
+ }
+
+ inline bool operator>(const uint64_t& x) const {
+ if (m_high > 0 or m_mid > 0) {
+ return true;
+ }
+ return m_lo > x;
+ }
+
+ inline bool operator<(const uint256_t& x) const {
+ if (m_high != x.m_high) {
+ return m_high < x.m_high;
+ }
+ if (m_mid != x.m_mid) {
+ return m_mid < x.m_mid;
+ } else {
+ return m_lo < x.m_lo;
+ }
+ }
+
+ inline operator uint64_t() {
+ return m_lo;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const uint256_t& x);
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/uintx_t.hpp b/include/sdsl/uintx_t.hpp
new file mode 100644
index 0000000..af3c653
--- /dev/null
+++ b/include/sdsl/uintx_t.hpp
@@ -0,0 +1,16 @@
+#ifndef INCLUDED_SDSL_UINTX_T
+#define INCLUDED_SDSL_UINTX_T
+
+#include <cstdint>
+
+using std::int8_t;
+using std::int16_t;
+using std::int32_t;
+using std::int64_t;
+
+using std::uint8_t;
+using std::uint16_t;
+using std::uint32_t;
+using std::uint64_t;
+
+#endif
diff --git a/include/sdsl/util.hpp b/include/sdsl/util.hpp
new file mode 100644
index 0000000..cdda357
--- /dev/null
+++ b/include/sdsl/util.hpp
@@ -0,0 +1,609 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file util.hpp
+ \brief util.hpp contains some helper methods for int_vector and other stuff like demangle class names.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_UTIL
+#define INCLUDED_SDSL_UTIL
+
+#include "bits.hpp"
+#include "sfstream.hpp"
+#include "ram_fs.hpp"
+#include "config.hpp" // for constants
+#include <iosfwd> // forward declaration of ostream
+#include <stdint.h> // for uint64_t uint32_t declaration
+#include <cassert>
+#include <ctime> // for rand initialization
+#include <string>
+#include <functional> // for class_to_hash
+#include <string.h> // for strlen and strdup
+#include <libgen.h> // for basename
+#include <cstdlib>
+#include <unistd.h> // for getpid, file_size, clock_gettime
+#include <sstream> // for to_string method
+#include <stdexcept> // for std::logic_error
+#include <typeinfo> // for typeid
+#include <sys/time.h> // for struct timeval
+#include <sys/resource.h> // for struct rusage
+#include <iomanip>
+#include <numeric>
+#include <random>
+#include <chrono>
+#include <atomic>
+#include <mutex>
+#include <algorithm>
+
+// macros to transform a defined name to a string
+#define SDSL_STR(x) #x
+#define SDSL_XSTR(s) SDSL_STR(s)
+
+#define SDSL_UNUSED __attribute__ ((unused))
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+template<uint8_t>
+class int_vector; // forward declaration
+
+
+
+//! A namespace for helper functions
+namespace util
+{
+
+//============= Debug information =========================
+
+SDSL_UNUSED static bool verbose = false;
+
+void set_verbose();
+
+//============ Manipulating int_vectors ===================
+
+
+//! Sets all bits of the int_vector to pseudo-random bits.
+/*! \param v The int_vector whose bits should be set to random bits
+ * \param seed If seed = 0, the time is used to initialize the
+ * pseudo random number generator, otherwise the seed
+ * parameter is used.
+ */
+template<class t_int_vec>
+void set_random_bits(t_int_vec& v, int seed=0);
+//! Sets all bits of the int_vector to 0-bits.
+template<class t_int_vec>
+void _set_zero_bits(t_int_vec& v);
+//! Sets all bits of the int_vector to 1-bits.
+template<class t_int_vec>
+void _set_one_bits(t_int_vec& v);
+
+//! Bit compress the int_vector
+/*! Determine the biggest value X and then set the
+ * int_width to the smallest possible so that we
+ * still can represent X
+ */
+template<class t_int_vec>
+void bit_compress(t_int_vec& v);
+
+//! Expands the integer width to new_width >= v.width()
+template<class t_int_vec>
+void expand_width(t_int_vec& v, uint8_t new_width);
+
+//! All elements of v modulo m
+template<class t_int_vec>
+void mod(t_int_vec& v, typename t_int_vec::size_type m);
+
+
+//! Set all entries of int_vector to value k
+/*! \param v The int_vector which should be set
+ * \param k The value which should be inserted into v.
+ * \par Details
+ * This method pre-calculates the content of at most 64
+ * words and then repeatedly inserts these words into v.
+ */
+template<class t_int_vec>
+void set_to_value(t_int_vec& v, uint64_t k);
+
+//! Sets each entry of the numerical vector v at position \$fi\f$ to value \$fi\$f
+template<class t_int_vec>
+void set_to_id(t_int_vec& v);
+
+//! Number of set bits in v.
+/*! \param v int_vector object.
+ \return The number of 1-bits in v.
+ */
+template<class t_int_vec>
+typename t_int_vec::size_type cnt_one_bits(const t_int_vec& v);
+
+//! Number of occurrences of bit pattern `10` in v.
+/*! \sa getOneBits, getOneZeroBits
+ */
+template<class t_int_vec>
+typename t_int_vec::size_type cnt_onezero_bits(const t_int_vec& v);
+
+//! Number of occurrences of bit pattern `01` in v.
+/*! \sa getOneBits, getZeroOneBits
+ */
+template <class t_int_vec>
+typename t_int_vec::size_type cnt_zeroone_bits(const t_int_vec& v);
+
+//! Get the smallest position \f$i\geq idx\f$ where a bit is set
+/*! \param v The int_vector in which the bit is searched
+ * \param idx The start position for the search \f$ 0\leq idx < v.bit_size()\f$
+ * \return The smallest position greater or equal to idx, where corresponding bit is 1 or v.bit_size() if no such position exists
+ * \par Time complexity
+ * \f$ \Order{n} \f$
+ */
+template <class t_int_vec>
+typename t_int_vec::size_type next_bit(const t_int_vec& v, uint64_t idx);
+
+//! Get the greatest position \f$i\leq idx\f$ where a bit is set
+/*! \param v The int_vector in which the bit is searched
+ * \param idx The start position for the search \f$ 0\leq idx < v.bit_size()\f$
+ * \return The greatest position smaller or equal to idx, where corresponding bit is 1 or v.bit_size() if no such position exists
+ * \par Time complexity
+ * \f$ \Order{n} \f$
+*/
+template <class t_int_vec>
+typename t_int_vec::size_type prev_bit(const t_int_vec& v, uint64_t idx);
+
+
+//============= Handling files =============================
+
+//! Get the size of a file in bytes
+/*! \param file Path to a file.
+ * \returns Size of the specified file in bytes.
+ */
+off_t file_size(const std::string& file);
+
+//! Returns the basename of a file
+/*! \param file Path to a file.
+ * \returns Basename of the specified file.
+ */
+std::string basename(std::string file);
+
+//! Returns the directory of a file. A trailing `/` will be removed.
+/*! \param file Path to a file.
+ * \returns Directory name part of the specified path.
+ */
+std::string dirname(std::string file);
+
+//! Demangle the class name of typeid(...).name()
+/*!
+ * \param name A pointer to the result of typeid(...).name()
+ */
+std::string demangle(const std::string& name);
+
+//! Demangle the class name of typeid(...).name() and remove the "sdsl::"-prefix, "unsigned int",...
+std::string demangle2(const std::string& name);
+
+//! Convert type to string
+template<typename T>
+std::string to_string(const T& t, int w=1);
+
+
+//! Transforms the demangled class name of an object to a hash value.
+template<class T>
+uint64_t hashvalue_of_classname(const T&)
+{
+ std::hash<std::string> str_hash;
+ return str_hash(sdsl::util::demangle2(typeid(T).name()));
+}
+
+//! Transforms the demangled class name of an object to a hash value.
+template<class T>
+std::string class_to_hash(const T& t)
+{
+ return to_string(hashvalue_of_classname(t));
+}
+
+template<class T>
+std::string class_name(const T& t)
+{
+ std::string result = demangle2(typeid(t).name());
+ size_t template_pos = result.find("<");
+ if (template_pos != std::string::npos) {
+ result = result.erase(template_pos);
+ }
+ return result;
+}
+
+//! Get the process id of the current process
+uint64_t pid();
+
+class _id_helper
+{
+ private:
+ static uint64_t id;
+ public:
+ static uint64_t getId() {
+ return id++;
+ }
+};
+
+
+//! Get a unique id inside the process
+uint64_t id();
+
+template<typename T>
+std::string to_latex_string(const T& t);
+
+std::string to_latex_string(unsigned char c);
+
+//! Delete all files of the file_map.
+void delete_all_files(tMSS& file_map);
+
+// thanks to Stefan Arnold for the assign functions
+//! Assigns the value x of type T to the value of y of type U.
+/*!
+ * \param x The assigned variable.
+ * \param y The variable which provides the value that is assigned to x.
+ */
+template<class T, class U>
+void assign(T& x, const U& y)
+{
+ x = T(y);
+}
+
+//! Swaps variables x and y.
+/*!
+ * \param x Reference to the first variable.
+ * \param y Reference to the second variable.
+ */
+template<class T>
+void assign(T& x, T& y)
+{
+ x.swap(y);
+}
+
+//! clear the space used by x
+/*!
+ * \param x Reference to the data structure.
+ */
+template<class T>
+void clear(T& x)
+{
+ T y;
+ x.swap(y);
+}
+
+//! Swap support data structure and assign to new vector
+/*! \param s1 First support structure.
+ * \param s2 Second support structure.
+ * \param p1 First supported structure.
+ * \param p2 Second supported structure.
+ * s1 is swapped with s2 and after the execution s1 supports p1 and s2 supports
+ * p2. I.e. if p1 and p2 are members of a complex data structure, we have to
+ * swap p1 and p2 before we use this method.
+ */
+template<class S, class P>
+void swap_support(S& s1, S& s2, const P* p1, const P* p2)
+{
+ s1.swap(s2);
+ s1.set_vector(p1);
+ s2.set_vector(p2);
+}
+
+//! Initialise support data structure with
+/*! \param s Support structure which should be initialized
+ * \param x Pointer to the data structure which should be supported.
+ */
+template<class S, class X>
+void init_support(S& s, const X* x)
+{
+ S temp(x); // generate a temporary support object
+ s.swap(temp); // swap its content with the target object
+ s.set_vector(x); // set the support object's pointer to x
+}
+
+class spin_lock
+{
+ private:
+ std::atomic_flag m_slock = ATOMIC_FLAG_INIT;
+ public:
+ void lock() {
+ while (m_slock.test_and_set(std::memory_order_acquire)) {
+ /* spin */
+ }
+ };
+ void unlock() {
+ m_slock.clear(std::memory_order_release);
+ };
+};
+
+//! Create 2^{log_s} random integers mod m with seed x
+/*
+ */
+template<class t_int_vec>
+t_int_vec rnd_positions(uint8_t log_s, uint64_t& mask, uint64_t mod=0, uint64_t seed=17)
+{
+ mask = (1<<log_s)-1;
+ t_int_vec rands(1<<log_s ,0);
+ set_random_bits(rands, seed);
+ if (mod > 0) {
+ util::mod(rands, mod);
+ }
+ return rands;
+}
+
+//! Checks at compile time whether type is regular or not
+/* static_assert(is_regular<YOUR_TYPE>::value);
+ * Code is from a talk of Aerix Consulting
+ */
+template<typename T>
+struct is_regular : std::integral_constant< bool,
+ std::is_default_constructible<T>::value&&
+ std::is_copy_constructible<T>::value&&
+ std::is_move_constructible<T>::value&&
+ std::is_copy_assignable<T>::value&&
+ std::is_move_assignable<T>::value > {};
+
+} // end namespace util
+
+//==================== Template functions ====================
+
+template<class t_int_vec>
+void util::set_random_bits(t_int_vec& v, int seed)
+{
+ std::mt19937_64 rng;
+ if (0 == seed) {
+ rng.seed(std::chrono::system_clock::now().time_since_epoch().count() + util::id());
+ } else
+ rng.seed(seed);
+
+ uint64_t* data = v.data();
+ if (v.empty())
+ return;
+ *data = rng();
+ for (typename t_int_vec::size_type i=1; i < (v.capacity()>>6); ++i) {
+ *(++data) = rng();
+ }
+}
+
+// all elements of vector v modulo m
+template<class t_int_vec>
+void util::mod(t_int_vec& v, typename t_int_vec::size_type m)
+{
+ for (typename t_int_vec::size_type i=0; i < v.size(); ++i) {
+ v[i] = v[i] % m;
+ }
+}
+
+template<class t_int_vec>
+void util::bit_compress(t_int_vec& v)
+{
+ auto max_elem = std::max_element(v.begin(),v.end());
+ uint64_t max = 0;
+ if (max_elem != v.end()) {
+ max = *max_elem;
+ }
+ uint8_t min_width = bits::hi(max)+1;
+ uint8_t old_width = v.width();
+ if (old_width > min_width) {
+ const uint64_t* read_data = v.data();
+ uint64_t* write_data = v.data();
+ uint8_t read_offset = 0;
+ uint8_t write_offset = 0;
+ for (typename t_int_vec::size_type i=0; i < v.size(); ++i) {
+ uint64_t x = bits::read_int_and_move(read_data, read_offset, old_width);
+ bits::write_int_and_move(write_data, x, write_offset, min_width);
+ }
+ v.bit_resize(v.size()*min_width);
+ v.width(min_width);
+ }
+}
+
+template<class t_int_vec>
+void util::expand_width(t_int_vec& v, uint8_t new_width)
+{
+ uint8_t old_width = v.width();
+ typename t_int_vec::size_type n = v.size();
+ if (new_width > old_width and n > 0) {
+ typename t_int_vec::size_type i, old_pos, new_pos;
+ new_pos = (n-1)*new_width;
+ old_pos = (n-1)*old_width;
+ v.bit_resize(v.size()*new_width);
+ for (i=0; i < n; ++i, new_pos-=new_width, old_pos-=old_width) {
+ v.set_int(new_pos, v.get_int(old_pos, old_width), new_width);
+ }
+ v.width(new_width);
+ }
+}
+
+template<class t_int_vec>
+void util::_set_zero_bits(t_int_vec& v)
+{
+ uint64_t* data = v.data();
+ if (v.empty())
+ return;
+ // TODO: replace by memset() but take care of size_t in the argument!
+ *data = 0ULL;
+ for (typename t_int_vec::size_type i=1; i < (v.capacity()>>6); ++i) {
+ *(++data) = 0ULL;
+ }
+}
+
+template<class t_int_vec>
+void util::_set_one_bits(t_int_vec& v)
+{
+ uint64_t* data = v.data();
+ if (v.empty())
+ return;
+ *data = 0xFFFFFFFFFFFFFFFFULL;
+ for (typename t_int_vec::size_type i=1; i < (v.capacity()>>6); ++i) {
+ *(++data) = 0xFFFFFFFFFFFFFFFFULL;
+ }
+}
+
+template<class t_int_vec>
+void util::set_to_value(t_int_vec& v, uint64_t k)
+{
+ uint64_t* data = v.data();
+ if (v.empty())
+ return;
+ uint8_t int_width = v.width();
+ if (int_width == 0) {
+ throw std::logic_error("util::set_to_value can not be performed with int_width=0!");
+ }
+ if (0 == k) {
+ _set_zero_bits(v);
+ return;
+ }
+ if (bits::lo_set[int_width] == k) {
+ _set_one_bits(v);
+ return;
+ }
+ k = k & (0xFFFFFFFFFFFFFFFFULL >> (64-int_width));
+ uint64_t vec[67] = {0}; // allocate memory for the mask and initialize with zeros
+ vec[0] = 0;
+ uint8_t offset = 0;
+ uint64_t n=0, vals=0;
+ do { // loop terminates after at most 64 iterations
+ vec[n] = vec[n] | (k << offset);
+ offset += int_width;
+ vals++;
+ if (offset >= 64) {
+ vec[n+1] = 0;
+ vec[++n] = k >> (int_width-(offset-64));
+ offset -= 64;
+ }
+ } while (offset != 0);
+
+ typename t_int_vec::size_type n64 = v.capacity()/64;
+ for (typename t_int_vec::size_type i=0; i < n64;) {
+ for (uint64_t ii=0; ii < n and i < n64; ++ii,++i) {
+ *(data++) = vec[ii];
+ }
+ }
+}
+
+//! Set v[i] = i for i=[0..v.size()-1]
+template<class t_int_vec>
+void util::set_to_id(t_int_vec& v)
+{
+ std::iota(v.begin(), v.end(), 0ULL);
+}
+
+template<class t_int_vec>
+typename t_int_vec::size_type util::cnt_one_bits(const t_int_vec& v)
+{
+ const uint64_t* data = v.data();
+ if (v.empty())
+ return 0;
+ typename t_int_vec::size_type result = bits::cnt(*data);
+ for (typename t_int_vec::size_type i=1; i < (v.capacity()>>6); ++i) {
+ result += bits::cnt(*(++data));
+ }
+ if (v.bit_size()&0x3F) {
+ result -= bits::cnt((*data) & (~bits::lo_set[v.bit_size()&0x3F]));
+ }
+ return result;
+}
+
+
+template<class t_int_vec>
+typename t_int_vec::size_type util::cnt_onezero_bits(const t_int_vec& v)
+{
+ const uint64_t* data = v.data();
+ if (v.empty())
+ return 0;
+ uint64_t carry = 0, oldcarry=0;
+ typename t_int_vec::size_type result = bits::cnt10(*data, carry);
+ for (typename t_int_vec::size_type i=1; i < (v.capacity()>>6); ++i) {
+ oldcarry = carry;
+ result += bits::cnt10(*(++data), carry);
+ }
+ if (v.bit_size()&0x3F) {// if bit_size is not a multiple of 64, subtract the counts of the additional bits
+ result -= bits::cnt(bits::map10(*data, oldcarry) & bits::lo_unset[v.bit_size()&0x3F]);
+ }
+ return result;
+}
+
+template<class t_int_vec>
+typename t_int_vec::size_type util::cnt_zeroone_bits(const t_int_vec& v)
+{
+ const uint64_t* data = v.data();
+ if (v.empty())
+ return 0;
+ uint64_t carry = 1, oldcarry = 1;
+ typename t_int_vec::size_type result = bits::cnt01(*data, carry);
+ for (typename t_int_vec::size_type i=1; i < (v.capacity()>>6); ++i) {
+ oldcarry = carry;
+ result += bits::cnt01(*(++data), carry);
+ }
+ if (v.bit_size()&0x3F) {// if bit_size is not a multiple of 64, subtract the counts of the additional bits
+ result -= bits::cnt(bits::map01(*data, oldcarry) & bits::lo_unset[v.bit_size()&0x3F]);
+ }
+ return result;
+}
+
+template <class t_int_vec>
+typename t_int_vec::size_type util::next_bit(const t_int_vec& v, uint64_t idx)
+{
+ uint64_t pos = idx>>6;
+ uint64_t node = v.data()[pos];
+ node >>= (idx&0x3F);
+ if (node) {
+ return idx+bits::lo(node);
+ } else {
+ ++pos;
+ while ((pos<<6) < v.bit_size()) {
+ if (v.data()[pos]) {
+ return (pos<<6)|bits::lo(v.data()[pos]);
+ }
+ ++pos;
+ }
+ return v.bit_size();
+ }
+}
+
+template <class t_int_vec>
+typename t_int_vec::size_type util::prev_bit(const t_int_vec& v, uint64_t idx)
+{
+ uint64_t pos = idx>>6;
+ uint64_t node = v.data()[pos];
+ node <<= 63-(idx&0x3F);
+ if (node) {
+ return bits::hi(node)+(pos<<6)-(63-(idx&0x3F));
+ } else {
+ --pos;
+ while ((pos<<6) < v.bit_size()) {
+ if (v.data()[pos]) {
+ return (pos<<6)|bits::hi(v.data()[pos]);
+ }
+ --pos;
+ }
+ return v.bit_size();
+ }
+}
+
+template<typename T>
+std::string util::to_string(const T& t, int w)
+{
+ std::stringstream ss;
+ ss<<std::setw(w)<<t;
+ return ss.str();
+}
+
+template<typename T>
+std::string util::to_latex_string(const T& t)
+{
+ return to_string(t);
+}
+
+}// end namespace sdsl
+#endif
diff --git a/include/sdsl/vectors.hpp b/include/sdsl/vectors.hpp
new file mode 100644
index 0000000..955e991
--- /dev/null
+++ b/include/sdsl/vectors.hpp
@@ -0,0 +1,10 @@
+/** \defgroup int_vector int_vector */
+#ifndef SDSL_INCLUDED_VECTORS
+#define SDSL_INCLUDED_VECTORS
+
+#include "int_vector.hpp"
+#include "enc_vector.hpp"
+#include "vlc_vector.hpp"
+#include "dac_vector.hpp"
+
+#endif
diff --git a/include/sdsl/vlc_vector.hpp b/include/sdsl/vlc_vector.hpp
new file mode 100644
index 0000000..ef20e2e
--- /dev/null
+++ b/include/sdsl/vlc_vector.hpp
@@ -0,0 +1,281 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file vlc_vector.hpp
+ \brief vlc_vector.hpp contains a vector which stores the values with variable length codes.
+ \author Simon Gog
+*/
+#ifndef SDSL_VLC_VECTOR
+#define SDSL_VLC_VECTOR
+
+#include "int_vector.hpp"
+#include "coder_elias_delta.hpp"
+#include "iterators.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+template<uint8_t t_width>
+struct vlc_vector_trait {
+ typedef int_vector<0> int_vector_type;
+};
+
+template<>
+struct vlc_vector_trait<32> {
+ typedef int_vector<32> int_vector_type;
+};
+
+//! A generic immutable space-saving vector class for unsigned integers.
+/*! The values of a vlc_vector are immutable after the constructor call. The class
+ * could be parametrized with a self-delimiting code t_coder and the sample density.
+ * \tparam t_coder Type of self-delimiting coder.
+ * \tparam t_dens Sampling density of pointers into the stream of self-delimiting coded numbers.
+ * \tparam t_width Width of the underlying int_vector for the pointers.
+ */
+template<class t_coder = coder::elias_delta,
+ uint32_t t_dens = 128,
+ uint8_t t_width = 0>
+class vlc_vector
+{
+ private:
+ static_assert(t_dens > 1 , "vlc_vector: Sampling density must be larger than 1");
+ public:
+ typedef uint64_t value_type;
+ typedef random_access_const_iterator<vlc_vector> iterator;
+ typedef iterator const_iterator;
+ typedef const value_type reference;
+ typedef const value_type const_reference;
+ typedef const value_type* const_pointer;
+ typedef ptrdiff_t difference_type;
+ typedef int_vector<>::size_type size_type;
+ typedef t_coder coder;
+ typedef iv_tag index_category;
+ typedef typename
+ vlc_vector_trait<t_width>::int_vector_type int_vector_type;
+
+ static const uint32_t sample_dens = t_dens;
+ bit_vector m_z; // compressed bit stream
+ private:
+ int_vector_type m_sample_pointer;
+ size_type m_size = 0; // number of elements
+ uint32_t m_sample_dens = t_dens;
+
+ void copy(const vlc_vector& v);
+
+ void clear() {
+ m_z.resize(0);
+ m_size = 0;
+ m_sample_pointer.resize(0);
+ }
+
+ public:
+ vlc_vector() = default;
+ vlc_vector(const vlc_vector&) = default;
+ vlc_vector(vlc_vector&&) = default;
+ vlc_vector& operator=(const vlc_vector&) = default;
+ vlc_vector& operator=(vlc_vector&&) = default;
+
+ //! Constructor for a Container of unsigned integers.
+ /*! \param c A container of unsigned integers.
+ \pre No two adjacent values should be equal.
+ */
+ template<class Container>
+ vlc_vector(const Container& c);
+
+ //! Constructor for an int_vector_buffer of unsigned integers.
+ template<uint8_t int_width>
+ vlc_vector(int_vector_buffer<int_width>& v_buf);
+
+ //! The number of elements in the vlc_vector.
+ size_type size()const {
+ return m_size;
+ }
+ //! Return the largest size that this container can ever have.
+ static size_type max_size() {
+ return int_vector<>::max_size()/2;
+ }
+
+ //! Returns if the vlc_vector is empty.
+ bool empty() const {
+ return 0 == m_size;
+ }
+
+ //! Swap method for vlc_vector
+ void swap(vlc_vector& v);
+
+ //! Iterator that points to the first element of the vlc_vector.
+ const const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+
+ //! Iterator that points to the position after the last element of the vlc_vector.
+ const const_iterator end()const {
+ return const_iterator(this, this->m_size);
+ }
+
+ //! []-operator
+ value_type operator[](size_type i)const;
+
+ //! Serializes the vlc_vector to a stream.
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const;
+
+ //! Load the vlc_vector from a stream.
+ void load(std::istream& in);
+
+ //! Returns the ith sample of vlc_vector
+ value_type sample(const size_type i) const;
+
+ uint32_t get_sample_dens() const;
+ void set_sample_dens(const uint32_t sample_dens);
+};
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+inline uint32_t vlc_vector<t_coder, t_dens, t_width>::get_sample_dens() const
+{
+ if (t_dens == 0)
+ return m_sample_dens;
+ else
+ return t_dens;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+inline void vlc_vector<t_coder, t_dens, t_width>::set_sample_dens(const uint32_t sample_dens)
+{
+ m_sample_dens = sample_dens;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+inline typename vlc_vector<t_coder, t_dens,t_width>::value_type vlc_vector<t_coder, t_dens,t_width>::operator[](const size_type i)const
+{
+ assert(i+1 != 0);
+ assert(i < m_size);
+ size_type idx = i/get_sample_dens();
+ return (t_coder::template decode<false, false, int*>(m_z.data(), m_sample_pointer[idx], i-t_dens*idx+1)) - 1;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+void vlc_vector<t_coder, t_dens,t_width>::swap(vlc_vector<t_coder, t_dens,t_width>& v)
+{
+ if (this != &v) { // if v and _this_ are not the same object
+ m_z.swap(v.m_z); // swap compressed bit streams
+ m_sample_pointer.swap(v.m_sample_pointer);
+ std::swap(m_size, v.m_size);// swap the number of elements
+ }
+}
+
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+template<class Container>
+vlc_vector<t_coder, t_dens, t_width>::vlc_vector(const Container& c)
+{
+ clear(); // clear bit_vectors
+
+ if (c.empty()) // if c is empty there is nothing to do...
+ return;
+ size_type samples = 0, z_size = 0;
+// (1) Calculate size of z
+ for (size_type i=0; i < c.size(); ++i) {
+ if (c[i]+1<1) {
+ throw std::logic_error("vlc_vector cannot decode values smaller than 1!");
+ }
+ z_size += t_coder::encoding_length(c[i]+1);
+ }
+ samples = (c.size()+get_sample_dens()-1)/get_sample_dens();
+// (2) Write z
+ m_sample_pointer = int_vector<>(samples+1, 0, bits::hi(z_size+1)+1);
+
+ m_z.bit_resize(z_size);
+ z_size = 0;
+ uint64_t* z_data = t_coder::raw_data(m_z);
+ uint8_t offset = 0;
+ size_type no_sample = 0;
+ for (size_type i=0, sample_cnt=0; i < c.size(); ++i, --no_sample) {
+ if (!no_sample) { // add a sample pointer
+ no_sample = get_sample_dens();
+ m_sample_pointer[sample_cnt++] = z_size;
+ }
+ t_coder::encode(c[i]+1, z_data, offset);
+ z_size += t_coder::encoding_length(c[i]+1);
+ }
+ m_size = c.size();
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+template<uint8_t int_width>
+vlc_vector<t_coder, t_dens, t_width>::vlc_vector(int_vector_buffer<int_width>& v_buf)
+{
+ clear(); // clear bit_vectors
+ size_type n = v_buf.size();
+ if (n == 0) // if c is empty there is nothing to do...
+ return;
+ size_type samples=0, z_size=0;
+// (1) Calculate size of z
+ for (size_type i=0; i < n; ++i) {
+ size_type x = v_buf[i]+1;
+ if (x < 1) {
+ throw std::logic_error("vlc_vector cannot decode values smaller than 1!");
+ }
+ z_size += t_coder::encoding_length(x);
+ }
+ samples = (n+get_sample_dens()-1)/get_sample_dens();
+// (2) Write z
+
+ m_sample_pointer = int_vector<>(samples+1, 0, bits::hi(z_size+1)+1); // add 1 for last entry
+
+// (b) Initilize bit_vector for encoded data
+ m_z.bit_resize(z_size);
+ z_size = 0;
+ uint64_t* z_data = t_coder::raw_data(m_z);
+ uint8_t offset = 0;
+
+// (c) Write sample values and deltas
+ size_type no_sample = 0;
+ for (size_type i=0, sample_cnt = 0; i < n; ++i, --no_sample) {
+ if (!no_sample) { // add a sample pointer
+ no_sample = get_sample_dens();
+ m_sample_pointer[sample_cnt++] = z_size;
+ }
+ size_type x = v_buf[i]+1;
+ t_coder::encode(x, z_data, offset); // write encoded values
+ z_size += t_coder::encoding_length(x);
+ }
+ m_size = n;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+vlc_vector<>::size_type vlc_vector<t_coder, t_dens,t_width>::serialize(std::ostream& out, structure_tree_node* v, std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "m_size");
+ written_bytes += m_z.serialize(out, child, "m_z");
+ written_bytes += m_sample_pointer.serialize(out, child, "m_sample_pointer");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+template<class t_coder, uint32_t t_dens, uint8_t t_width>
+void vlc_vector<t_coder, t_dens,t_width>::load(std::istream& in)
+{
+ read_member(m_size, in);
+ m_z.load(in);
+ m_sample_pointer.load(in);
+}
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/wavelet_trees.hpp b/include/sdsl/wavelet_trees.hpp
new file mode 100644
index 0000000..8b93ef8
--- /dev/null
+++ b/include/sdsl/wavelet_trees.hpp
@@ -0,0 +1,81 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wavelet_trees.hpp
+ \brief wavelet_trees.hpp contains wavelet tree implementations.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_WAVELET_TREES
+#define INCLUDED_SDSL_WAVELET_TREES
+
+/** \defgroup wt Wavelet Trees (WT)
+ * This group contains data structures for wavelet trees. The following methods are supported:
+ * - []-operator
+ * - rank(i, c)
+ * - select(i, c)
+ * - inverse_select(i)
+ */
+
+#include "wt_pc.hpp"
+#include "wt_blcd.hpp"
+#include "wt_gmr.hpp"
+#include "wt_huff.hpp"
+#include "wt_hutu.hpp"
+#include "wt_int.hpp"
+#include "wm_int.hpp"
+#include "wt_rlmn.hpp"
+#include "construct.hpp"
+#include "wt_algorithm.hpp"
+
+namespace sdsl
+{
+
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type
+ >
+using wt_hutu_int = wt_pc<hutu_shape,
+ t_bitvector,
+ t_rank,
+ t_select,
+ t_select_zero,
+ int_tree<>>;
+
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type>
+using wt_huff_int = wt_pc<huff_shape,
+ t_bitvector,
+ t_rank,
+ t_select,
+ t_select_zero,
+ int_tree<>>;
+
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select_one = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type>
+using wt_blcd_int = wt_pc<balanced_shape,
+ t_bitvector,
+ t_rank,
+ t_select_one,
+ t_select_zero,
+ int_tree<>>;
+}
+
+#endif
diff --git a/include/sdsl/wm_int.hpp b/include/sdsl/wm_int.hpp
new file mode 100644
index 0000000..7dfc816
--- /dev/null
+++ b/include/sdsl/wm_int.hpp
@@ -0,0 +1,724 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wm_int.hpp
+ \brief wm_int.hpp contains a specialized class for a wavelet tree for
+ sequences over large alphabets.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_WM_INT
+#define INCLUDED_SDSL_WM_INT
+
+#include "sdsl_concepts.hpp"
+#include "int_vector.hpp"
+#include "rank_support_v.hpp"
+#include "select_support_mcl.hpp"
+#include "wt_helper.hpp"
+#include "util.hpp"
+#include <set> // for calculating the alphabet size
+#include <map> // for mapping a symbol to its lexicographical index
+#include <algorithm> // for std::swap
+#include <stdexcept>
+#include <vector>
+#include <queue>
+#include <utility>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A wavelet tree class for integer sequences.
+/*!
+ * \tparam t_bitvector Type of the bitvector used for representing the wavelet tree.
+ * \tparam t_rank Type of the support structure for rank on pattern `1`.
+ * \tparam t_select Type of the support structure for select on pattern `1`.
+ * \tparam t_select_zero Type of the support structure for select on pattern `0`.
+ *
+ * This wavelet tree variant does not store the two children of a node v aligned
+ * with v; it is also known as wavelet matrix.
+ *
+ * \par References
+ * [1] F. Claude, G. Navarro: ,,The Wavelet Matrix'', Proceedings of
+ * SPIRE 2012.
+ *
+ * @ingroup wt
+ */
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type>
+class wm_int
+{
+ public:
+
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<>::value_type value_type;
+ typedef typename t_bitvector::difference_type difference_type;
+ typedef random_access_const_iterator<wm_int> const_iterator;
+ typedef const_iterator iterator;
+ typedef t_bitvector bit_vector_type;
+ typedef t_rank rank_1_type;
+ typedef t_select select_1_type;
+ typedef t_select_zero select_0_type;
+ typedef wt_tag index_category;
+ typedef int_alphabet_tag alphabet_category;
+ enum {lex_ordered=0};
+
+ typedef std::pair<value_type, size_type> point_type;
+ typedef std::vector<point_type> point_vec_type;
+ typedef std::pair<size_type, point_vec_type> r2d_res_type;
+
+ struct node_type;
+
+
+ protected:
+
+ size_type m_size = 0;
+ size_type m_sigma = 0; //<- \f$ |\Sigma| \f$
+ bit_vector_type m_tree; // bit vector to store the wavelet tree
+ rank_1_type m_tree_rank; // rank support for the wavelet tree bit vector
+ select_1_type m_tree_select1; // select support for the wavelet tree bit vector
+ select_0_type m_tree_select0;
+ uint32_t m_max_level = 0;
+ int_vector<64> m_zero_cnt; // m_zero_cnt[i] contains the number of zeros in level i
+ int_vector<64> m_rank_level; // m_rank_level[i] contains m_tree_rank(i*size())
+ mutable int_vector<64> m_path_off; // array keeps track of path offset in select-like methods
+ mutable int_vector<64> m_path_rank_off;// array keeps track of rank values for the offsets
+
+ void copy(const wm_int& wt) {
+ m_size = wt.m_size;
+ m_sigma = wt.m_sigma;
+ m_tree = wt.m_tree;
+ m_tree_rank = wt.m_tree_rank;
+ m_tree_rank.set_vector(&m_tree);
+ m_tree_select1 = wt.m_tree_select1;
+ m_tree_select1.set_vector(&m_tree);
+ m_tree_select0 = wt.m_tree_select0;
+ m_tree_select0.set_vector(&m_tree);
+ m_max_level = wt.m_max_level;
+ m_zero_cnt = wt.m_zero_cnt;
+ m_rank_level = wt.m_rank_level;
+ m_path_off = wt.m_path_off;
+ m_path_rank_off = wt.m_path_rank_off;
+ }
+
+ private:
+
+ void init_buffers(uint32_t max_level) {
+ m_path_off = int_vector<64>(max_level+1);
+ m_path_rank_off = int_vector<64>(max_level+1);
+ }
+
+ public:
+
+ const size_type& sigma = m_sigma; //!< Effective alphabet size of the wavelet tree.
+ const bit_vector_type& tree = m_tree; //!< A concatenation of all bit vectors of the wavelet tree.
+ const uint32_t& max_level = m_max_level; //!< Maximal level of the wavelet tree.
+
+ //! Default constructor
+ wm_int() {
+ init_buffers(m_max_level);
+ };
+
+ //! Semi-external constructor
+ /*! \param buf File buffer of the int_vector for which the wm_int should be build.
+ * \param size Size of the prefix of v, which should be indexed.
+ * \param max_level Maximal level of the wavelet tree. If set to 0, determined automatically.
+ * \par Time complexity
+ * \f$ \Order{n\log|\Sigma|}\f$, where \f$n=size\f$
+ * I.e. we need \Order{n\log n} if rac is a permutation of 0..n-1.
+ * \par Space complexity
+ * \f$ n\log|\Sigma| + O(1)\f$ bits, where \f$n=size\f$.
+ */
+ template<uint8_t int_width>
+ wm_int(int_vector_buffer<int_width>& buf, size_type size,
+ uint32_t max_level=0) : m_size(size) {
+ init_buffers(m_max_level);
+ if (0 == m_size)
+ return;
+ size_type n = buf.size(); // set n
+ if (n < m_size) {
+ throw std::logic_error("n="+util::to_string(n)+" < "+util::to_string(m_size)+"=m_size");
+ return;
+ }
+ m_sigma = 0; // init sigma
+
+ int_vector<int_width> rac(m_size, 0, buf.width()); // initialize rac
+
+ value_type x = 1; // variable for the biggest value in rac
+ for (size_type i=0; i < m_size; ++i) { // detect the largest value in rac
+ if (buf[i] > x)
+ x = buf[i];
+ rac[i] = buf[i];
+ }
+
+ if (max_level == 0) {
+ m_max_level = bits::hi(x)+1; // we need max_level bits to represent all values in the range [0..x]
+ } else {
+ m_max_level = max_level;
+ }
+ init_buffers(m_max_level);
+
+
+ std::string tree_out_buf_file_name = tmp_file(buf.filename(), "_m_tree");
+ osfstream tree_out_buf(tree_out_buf_file_name, std::ios::binary | std::ios::trunc | std::ios::out); // open buffer for tree
+ size_type bit_size = m_size*m_max_level;
+ tree_out_buf.write((char*) &bit_size, sizeof(bit_size)); // write size of bit_vector
+
+ std::string zero_buf_file_name = tmp_file(buf.filename(), "_zero_buf");
+
+ size_type tree_pos = 0;
+ uint64_t tree_word = 0;
+
+ m_zero_cnt = int_vector<64>(m_max_level, 0); // zeros at level i
+
+ for (uint32_t k=0; k<m_max_level; ++k) {
+ uint8_t width = m_max_level-k-1;
+ const uint64_t mask = 1ULL<<width;
+ uint64_t x = 0;
+ size_type zeros = 0;
+ int_vector_buffer<> zero_buf(zero_buf_file_name, std::ios::out, 1024*1024, m_max_level);
+ for (size_t i=0; i<m_size; ++i) {
+ x = rac[i];
+ if (x&mask) {
+ tree_word |= (1ULL << (tree_pos&0x3FULL));
+ zero_buf.push_back(x);
+ } else {
+ rac[zeros++ ] = x;
+ }
+ ++tree_pos;
+ if ((tree_pos & 0x3FULL) == 0) { // if tree_pos % 64 == 0 write old word
+ tree_out_buf.write((char*) &tree_word, sizeof(tree_word));
+ tree_word = 0;
+ }
+ }
+ m_zero_cnt[k] = zeros;
+ for (size_t i=zeros; i<m_size; ++i) {
+ rac[i] = zero_buf[i-zeros];
+ }
+ }
+ if ((tree_pos & 0x3FULL) != 0) { // if tree_pos % 64 > 0 => there are remaining entries we have to write
+ tree_out_buf.write((char*) &tree_word, sizeof(tree_word));
+ }
+ sdsl::remove(zero_buf_file_name);
+ tree_out_buf.close();
+ m_sigma = std::unique(rac.begin(), rac.end()) - rac.begin();
+ rac.resize(0);
+ bit_vector tree;
+ load_from_file(tree, tree_out_buf_file_name);
+ sdsl::remove(tree_out_buf_file_name);
+ m_tree = bit_vector_type(std::move(tree));
+ util::init_support(m_tree_rank, &m_tree);
+ util::init_support(m_tree_select0, &m_tree);
+ util::init_support(m_tree_select1, &m_tree);
+ m_rank_level = int_vector<64>(m_max_level, 0);
+ for (uint32_t k=0; k<m_rank_level.size(); ++k) {
+ m_rank_level[k] = m_tree_rank(k*m_size);
+ }
+ }
+
+ //! Copy constructor
+ wm_int(const wm_int& wt) {
+ copy(wt);
+ }
+
+ //! Copy constructor
+ wm_int(wm_int&& wt) {
+ *this = std::move(wt);
+ }
+
+ //! Assignment operator
+ wm_int& operator=(const wm_int& wt) {
+ if (this != &wt) {
+ copy(wt);
+ }
+ return *this;
+ }
+
+ //! Assignment move operator
+ wm_int& operator=(wm_int&& wt) {
+ if (this != &wt) {
+ m_size = wt.m_size;
+ m_sigma = wt.m_sigma;
+ m_tree = std::move(wt.m_tree);
+ m_tree_rank = std::move(wt.m_tree_rank);
+ m_tree_rank.set_vector(&m_tree);
+ m_tree_select1 = std::move(wt.m_tree_select1);
+ m_tree_select1.set_vector(&m_tree);
+ m_tree_select0 = std::move(wt.m_tree_select0);
+ m_tree_select0.set_vector(&m_tree);
+ m_max_level = std::move(wt.m_max_level);
+ m_zero_cnt = std::move(wt.m_zero_cnt);
+ m_rank_level = std::move(wt.m_rank_level);
+ m_path_off = std::move(wt.m_path_off);
+ m_path_rank_off = std::move(wt.m_path_rank_off);
+ }
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(wm_int& wt) {
+ if (this != &wt) {
+ std::swap(m_size, wt.m_size);
+ std::swap(m_sigma, wt.m_sigma);
+ m_tree.swap(wt.m_tree);
+ util::swap_support(m_tree_rank, wt.m_tree_rank, &m_tree, &(wt.m_tree));
+ util::swap_support(m_tree_select1, wt.m_tree_select1, &m_tree, &(wt.m_tree));
+ util::swap_support(m_tree_select0, wt.m_tree_select0, &m_tree, &(wt.m_tree));
+ std::swap(m_max_level, wt.m_max_level);
+ m_zero_cnt.swap(wt.m_zero_cnt);
+ m_rank_level.swap(wt.m_rank_level);
+ m_path_off.swap(wt.m_path_off);
+ m_path_rank_off.swap(wt.m_path_rank_off);
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Returns whether the wavelet tree contains no data.
+ bool empty()const {
+ return m_size == 0;
+ }
+
+ //! Recovers the i-th symbol of the original vector.
+ /*! \param i The index of the symbol in the original vector.
+ * \returns The i-th symbol of the original vector.
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ value_type res = 0;
+ for (uint32_t k=0; k < m_max_level; ++k) {
+ res <<= 1;
+ size_type rank_ones = m_tree_rank(i) - m_rank_level[k];
+ if (m_tree[i]) { // one at position i => follow right child
+ i = (k+1)*m_size + m_zero_cnt[k] + rank_ones;
+ res |= 1;
+ } else { // zero at position i => follow left child
+ auto rank_zeros = (i - k*m_size) - rank_ones;
+ i = (k+1)*m_size + rank_zeros;
+ }
+ }
+ return res;
+ };
+
+ //! Calculates how many symbols c are in the prefix [0..i-1] of the supported vector.
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in[0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the supported vector.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ size_type rank(size_type i, value_type c)const {
+ assert(i <= size());
+ if (((1ULL)<<(m_max_level))<=c) { // c is greater than any symbol in wt
+ return 0;
+ }
+ size_type b = 0; // start position of the interval
+ uint64_t mask = (1ULL) << (m_max_level-1);
+ for (uint32_t k=0; k < m_max_level and i; ++k) {
+ size_type rank_b = m_tree_rank(b);
+ size_type ones = m_tree_rank(b + i) - rank_b; // ones in [b..i)
+ size_type ones_p = rank_b - m_rank_level[k]; // ones in [level_b..b)
+ if (c & mask) { // search for a one at this level
+ i = ones;
+ b = (k+1)*m_size + m_zero_cnt[k] + ones_p;
+ } else { // search for a zero at this level
+ i = i-ones;
+ b = (k+1)*m_size + (b - k*m_size - ones_p);
+ }
+ mask >>= 1;
+ }
+ return i;
+ };
+
+ //! Calculates how many occurrences of symbol wt[i] are in the prefix [0..i-1] of the original sequence.
+ /*!
+ * \param i The index of the symbol.
+ * \return Pair (rank(wt[i],i),wt[i])
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ std::pair<size_type, value_type>
+ inverse_select(size_type i)const {
+ assert(i < size());
+ value_type c = 0;
+ size_type b = 0; // start position of the interval
+ uint64_t mask = (1ULL) << (m_max_level-1);
+ for (uint32_t k=0; k < m_max_level; ++k) {
+ size_type rank_b = m_tree_rank(b);
+ size_type ones = m_tree_rank(b + i) - rank_b; // ones in [b..i)
+ size_type ones_p = rank_b - m_rank_level[k]; // ones in [level_b..b)
+ c<<=1;
+ if (m_tree[b+i]) { // go to the right child
+ i = ones;
+ b = (k+1)*m_size + m_zero_cnt[k] + ones_p;
+ c|=1;
+ } else { // go to the left child
+ i = i-ones;
+ b = (k+1)*m_size + (b - k*m_size - ones_p);
+ }
+ mask >>= 1;
+ }
+ return std::make_pair(i,c);
+ }
+
+ //! Calculates the i-th occurrence of the symbol c in the supported vector.
+ /*!
+ * \param i The i-th occurrence.
+ * \param c The symbol c.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ * \par Precondition
+ * \f$ 1 \leq i \leq rank(size(), c) \f$
+ */
+ size_type select(size_type i, value_type c)const {
+ assert(1 <= i and i <= rank(size(), c));
+ uint64_t mask = 1ULL << (m_max_level-1);
+ m_path_off[0] = m_path_rank_off[0] = 0;
+ size_type b = 0; // start position of the interval
+ size_type r = i;
+ for (uint32_t k=0; k < m_max_level and i; ++k) {
+ size_type rank_b = m_tree_rank(b);
+ size_type ones = m_tree_rank(b + r) - rank_b; // ones in [b..i)
+ size_type ones_p = rank_b - m_rank_level[k]; // ones in [0..b)
+ if (c & mask) { // search for a one at this level
+ r = ones;
+ b = (k+1)*m_size + m_zero_cnt[k] + ones_p;
+ } else { // search for a zero at this level
+ r = r-ones;
+ b = (k+1)*m_size + (b - k*m_size - ones_p);
+ }
+ mask >>= 1;
+ m_path_off[k+1] = b;
+ m_path_rank_off[k] = rank_b;
+ }
+ mask = 1ULL;
+ for (uint32_t k=m_max_level; k>0; --k) {
+ b = m_path_off[k-1];
+ size_type rank_b = m_path_rank_off[k-1];
+ if (c & mask) { // right child => search i'th one
+ i = m_tree_select1(rank_b + i) - b + 1;
+ } else { // left child => search i'th zero
+ i = m_tree_select0(b - rank_b + i) - b + 1;
+ }
+ mask <<= 1;
+ }
+ return i-1;
+ };
+
+ //! range_search_2d searches points in the index interval [lb..rb] and value interval [vlb..vrb].
+ /*! \param lb Left bound of index interval (inclusive)
+ * \param rb Right bound of index interval (inclusive)
+ * \param vlb Left bound of value interval (inclusive)
+ * \param vrb Right bound of value interval (inclusive)
+ * \param report Should the matching points be returned?
+ * \return Pair (#of found points, vector of points), the vector is empty when
+ * report = false.
+ */
+ std::pair<size_type, std::vector<std::pair<value_type, size_type>>>
+ range_search_2d(size_type lb, size_type rb, value_type vlb, value_type vrb,
+ bool report=true) const {
+
+ if (vrb > (1ULL << m_max_level))
+ vrb = (1ULL << m_max_level);
+ if (vlb > vrb)
+ return make_pair(0, point_vec_type());
+ size_type cnt_answers = 0;
+ point_vec_type point_vec;
+ if (lb <= rb) {
+ size_type is[m_max_level+1];
+ size_type rank_off[m_max_level+1];
+ _range_search_2d(root(), range_type(lb, rb), vlb, vrb, 0, is,
+ rank_off, point_vec, report, cnt_answers);
+ }
+ return make_pair(cnt_answers, point_vec);
+ }
+
+ void
+ _range_search_2d(node_type v, range_type r, value_type vlb,
+ value_type vrb, size_type ilb, size_type is[],
+ size_type rank_off[], point_vec_type& point_vec,
+ bool report, size_type& cnt_answers)
+ const {
+ using std::get;
+ if (get<0>(r) > get<1>(r))
+ return;
+ is[v.level] = v.offset + get<0>(r);
+
+ if (v.level == m_max_level) {
+ for (size_type j=1; j <= sdsl::size(r) and report; ++j) {
+ size_type i = j;
+ size_type c = v.sym;
+ for (uint32_t k=m_max_level; k>0; --k) {
+ size_type offset = is[k-1];
+ size_type rank_offset = rank_off[k-1];
+ if (c&1) {
+ i = m_tree_select1(rank_offset+i)-offset+1;
+ } else {
+ i = m_tree_select0(offset-rank_offset+i)-offset+1;
+ }
+ c >>= 1;
+ }
+ point_vec.emplace_back(is[0]+i-1, v.sym);
+ }
+ cnt_answers += sdsl::size(r);
+ return;
+ } else {
+ rank_off[v.level] = m_tree_rank(is[v.level]);
+ }
+ size_type irb = ilb + (1ULL << (m_max_level-v.level));
+ size_type mid = (irb + ilb)>>1;
+
+ auto c_v = expand(v);
+ auto c_r = expand(v, r);
+
+ if (!sdsl::empty(get<0>(c_r)) and vlb < mid and mid) {
+ _range_search_2d(get<0>(c_v),get<0>(c_r), vlb,
+ std::min(vrb,mid-1), ilb, is, rank_off,
+ point_vec, report, cnt_answers);
+ }
+ if (!sdsl::empty(get<1>(c_r)) and vrb >= mid) {
+ _range_search_2d(get<1>(c_v), get<1>(c_r), std::max(mid, vlb),
+ vrb, mid, is, rank_off, point_vec, report,
+ cnt_answers);
+ }
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_sigma, out, child, "sigma");
+ written_bytes += m_tree.serialize(out, child, "tree");
+ written_bytes += m_tree_rank.serialize(out, child, "tree_rank");
+ written_bytes += m_tree_select1.serialize(out, child, "tree_select_1");
+ written_bytes += m_tree_select0.serialize(out, child, "tree_select_0");
+ written_bytes += write_member(m_max_level, out, child, "max_level");
+ written_bytes += m_zero_cnt.serialize(out, child, "zero_cnt");
+ written_bytes += m_rank_level.serialize(out, child, "rank_level");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_sigma, in);
+ m_tree.load(in);
+ m_tree_rank.load(in, &m_tree);
+ m_tree_select1.load(in, &m_tree);
+ m_tree_select0.load(in, &m_tree);
+ read_member(m_max_level, in);
+ m_zero_cnt.load(in);
+ m_rank_level.load(in);
+ init_buffers(m_max_level);
+ }
+
+ //! Represents a node in the wavelet tree
+ struct node_type {
+ size_type offset = 0;
+ size_type size = 0;
+ size_type level = 0;
+ value_type sym = 0;
+
+ // Default constructor
+ node_type(size_type o=0, size_type sz=0, size_type l=0,
+ value_type sy=0) :
+ offset(o), size(sz), level(l), sym(sy) {}
+
+ // Copy constructor
+ node_type(const node_type&) = default;
+
+ // Move copy constructor
+ node_type(node_type&&) = default;
+
+ // Assignment operator
+ node_type& operator=(const node_type&) = default;
+
+ // Move assignment operator
+ node_type& operator=(node_type&&) = default;
+
+ // Comparator operator
+ bool operator==(const node_type& v) const {
+ return offset == v.offset;
+ }
+
+ // Smaller operator
+ bool operator<(const node_type& v) const {
+ return offset < v.offset;
+ }
+
+ // Greater operator
+ bool operator>(const node_type& v) const {
+ return offset > v.offset;
+ }
+ };
+
+ //! Checks if the node is a leaf node
+ bool is_leaf(const node_type& v) const {
+ return v.level == m_max_level;
+ }
+
+ value_type sym(const node_type& v) const {
+ return v.sym;
+ }
+
+ bool empty(const node_type& v) const {
+ return v.size == (size_type)0;
+ }
+
+ //! Return the root node
+ node_type root() const {
+ return node_type(0, m_size, 0, 0);
+ }
+
+ //! Returns the two child nodes of an inner node
+ /*! \param v An inner node of a wavelet tree.
+ * \return Return a pair of nodes (left child, right child).
+ * \pre !is_leaf(v)
+ */
+ std::pair<node_type, node_type>
+ expand(const node_type& v) const {
+ node_type v_right = v;
+ return expand(std::move(v_right));
+ }
+
+ //! Returns the two child nodes of an inner node
+ /*! \param v An inner node of a wavelet tree.
+ * \return Return a pair of nodes (left child, right child).
+ * \pre !is_leaf(v)
+ */
+ std::pair<node_type, node_type>
+ expand(node_type&& v) const {
+ node_type v_left;
+ size_type rank_b = m_tree_rank(v.offset);
+ size_type ones = m_tree_rank(v.offset+v.size)-rank_b; // ones in [b..size)
+ size_type ones_p = rank_b - m_rank_level[v.level]; // ones in [level_b..b)
+
+ v_left.offset = (v.level+1)*m_size + (v.offset - v.level*m_size) - ones_p;
+ v_left.size = v.size - ones;
+ v_left.level = v.level + 1;
+ v_left.sym = v.sym<<1;
+
+ v.offset = (v.level+1)*m_size + m_zero_cnt[v.level] + ones_p;
+ v.size = ones;
+ v.level = v.level + 1;
+ v.sym = (v.sym<<1)|1;
+
+ return std::make_pair(std::move(v_left), v);
+ }
+
+ //! Returns for each range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param ranges A vector of ranges. Each range [s,e]
+ * has to be contained in v=[v_s,v_e].
+ * \return A vector a range pairs. The first element of each
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_vec_type, range_vec_type>
+ expand(const node_type& v,
+ const range_vec_type& ranges) const {
+ auto ranges_copy = ranges;
+ return expand(v, std::move(ranges_copy));
+ }
+
+ //! Returns for each range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param ranges A vector of ranges. Each range [s,e]
+ * has to be contained in v=[v_s,v_e].
+ * \return A vector a range pairs. The first element of each
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_vec_type, range_vec_type>
+ expand(const node_type& v,
+ range_vec_type&& ranges) const {
+ auto v_sp_rank = m_tree_rank(v.offset); // this is already calculated in expand(v)
+ range_vec_type res(ranges.size());
+ size_t i = 0;
+ for (auto& r : ranges) {
+ auto sp_rank = m_tree_rank(v.offset + r.first);
+ auto right_size = m_tree_rank(v.offset + r.second + 1)
+ - sp_rank;
+ auto left_size = (r.second-r.first+1)-right_size;
+
+ auto right_sp = sp_rank - v_sp_rank;
+ auto left_sp = r.first - right_sp;
+
+ r = range_type(left_sp, left_sp + left_size - 1);
+ res[i++] = range_type(right_sp, right_sp + right_size - 1);
+ }
+ return make_pair(ranges, std::move(res));
+ }
+
+ //! Returns for a range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param r A ranges [s,e], such that [s,e] is
+ * contained in v=[v_s,v_e].
+ * \return A range pair. The first element of the
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_type, range_type>
+ expand(const node_type& v, const range_type& r) const {
+ auto v_sp_rank = m_tree_rank(v.offset); // this is already calculated in expand(v)
+ auto sp_rank = m_tree_rank(v.offset + r.first);
+ auto right_size = m_tree_rank(v.offset + r.second + 1)
+ - sp_rank;
+ auto left_size = (r.second-r.first+1)-right_size;
+
+ auto right_sp = sp_rank - v_sp_rank;
+ auto left_sp = r.first - right_sp;
+
+ return make_pair(range_type(left_sp, left_sp + left_size - 1),
+ range_type(right_sp, right_sp + right_size - 1));
+ }
+
+ //! return the path to the leaf for a given symbol
+ std::pair<uint64_t,uint64_t> path(value_type c) const {
+ return {m_max_level,c};
+ }
+};
+
+}// end namespace sdsl
+#endif
diff --git a/include/sdsl/wt_algorithm.hpp b/include/sdsl/wt_algorithm.hpp
new file mode 100644
index 0000000..61daeb7
--- /dev/null
+++ b/include/sdsl/wt_algorithm.hpp
@@ -0,0 +1,600 @@
+#ifndef INCLUDED_SDSL_WT_ALGORITHM
+#define INCLUDED_SDSL_WT_ALGORITHM
+
+#include <algorithm>
+#include <utility>
+
+namespace sdsl
+{
+
+template<typename t_wt>
+struct has_interval_symbols;
+
+template<typename t_wt, bool t_has_interval_symbols>
+struct _interval_symbols_wt;
+
+template<typename, typename T>
+struct has_expand;
+
+//! Intersection of elements in WT[s_0,e_0], WT[s_1,e_1],...,WT[s_k,e_k]
+/*! \param wt The wavelet tree object.
+ * \param ranges The ranges.
+ * \param t Threshold in how many distinct ranges the value has to be
+ * present. Default: t=ranges.size()
+ * \return A vector containing (value, frequency) - of value which are
+ * contained in t different ranges. Frequency = accumulated
+ * frequencies in all ranges. The tuples are ordered according
+ * to value, if t_wt::lex_ordered=1.
+ */
+template<class t_wt>
+std::vector< std::pair<typename t_wt::value_type, typename t_wt::size_type> >
+intersect(const t_wt& wt, const std::vector<range_type>& ranges, typename t_wt::size_type t=0)
+{
+ using std::get;
+ using size_type = typename t_wt::size_type;
+ using value_type = typename t_wt::value_type;
+ using node_type = typename t_wt::node_type;
+ using pnvr_type = std::pair<node_type, range_vec_type>;
+ typedef std::stack<pnvr_type> stack_type;
+
+ static_assert(has_expand<t_wt, std::pair<node_type,node_type>(const node_type&)>::value,
+ "intersect requires t_wt to have expand(const node_type&)");
+
+ using p_t = std::pair<value_type,size_type>;
+ std::vector<p_t> res;
+
+ auto push_node = [&wt,&t](stack_type& s, node_type& child,
+ range_vec_type& child_range) {
+ auto end = std::remove_if(child_range.begin(), child_range.end(),
+ [&](const range_type& x) { return empty(x);});
+ if (end > child_range.begin() + t - 1) {
+ s.emplace(pnvr_type(child, range_vec_type(child_range.begin(),
+ end)));
+ }
+ };
+
+ if (ranges.empty())
+ return res;
+
+ t = (t==0) ? ranges.size() : t;
+
+ std::stack<pnvr_type> stack;
+ stack.emplace(pnvr_type(wt.root(), ranges));
+
+ while (!stack.empty()) {
+ pnvr_type x = stack.top(); stack.pop();
+
+ if (wt.is_leaf(x.first)) {
+ const auto& iv = x.second;
+ if (t <= iv.size()) {
+ auto freq = std::accumulate(iv.begin(), iv.end(), 0ULL,
+ [](size_type acc, const range_type& r) {
+ return acc+(r.second-r.first+1);
+ });
+ res.emplace_back(wt.sym(x.first),freq);
+ }
+ } else {
+ auto child = wt.expand(x.first);
+ auto child_ranges = wt.expand(x.first, x.second);
+
+ push_node(stack, get<1>(child), get<1>(child_ranges));
+ push_node(stack, get<0>(child), get<0>(child_ranges));
+ }
+ }
+ return res;
+}
+
+
+//! Returns the q-th smallest element and its frequency in wt[lb..rb].
+/*! \param wt The wavelet tree.
+ * \param lb Left array bound in T
+ * \param rb Right array bound in T
+ * \param q q-th largest element ('quantile'), 0-based indexed.
+ */
+template<class t_wt>
+std::pair<typename t_wt::value_type, typename t_wt::size_type>
+quantile_freq(const t_wt& wt, typename t_wt::size_type lb,
+ typename t_wt::size_type rb, typename t_wt::size_type q)
+{
+ static_assert(t_wt::lex_ordered,
+ "quantile_freq requires a lex_ordered WT");
+ using std::get;
+ using node_type = typename t_wt::node_type;
+ static_assert(has_expand<t_wt, std::pair<node_type,node_type>(const node_type&)>::value,
+ "quantile_freq requires t_wt to have expand(const node_type&)");
+
+ node_type v = wt.root();
+ range_type r(lb,rb);
+
+ while (!wt.is_leaf(v)) {
+ auto child = wt.expand(v);
+ auto child_ranges = wt.expand(v, r);
+ auto num_zeros = size(get<0>(child_ranges));
+
+ if (q >= num_zeros) {
+ q -= num_zeros;
+ v = get<1>(child);
+ r = get<1>(child_ranges);
+ } else {
+ v = get<0>(child);
+ r = get<0>(child_ranges);
+ }
+ }
+ return {wt.sym(v), size(r)};
+};
+
+
+template<class t_wt>
+void
+_interval_symbols_rec(const t_wt& wt, range_type r,
+ typename t_wt::size_type& k,
+ std::vector<typename t_wt::value_type>& cs,
+ std::vector<typename t_wt::size_type>& rank_c_i,
+ std::vector<typename t_wt::size_type>& rank_c_j,
+ const typename t_wt::node_type& v)
+{
+ using std::get;
+ if (wt.is_leaf(v)) {
+ rank_c_i[k] = r.first;
+ rank_c_j[k] = r.second+1;
+ cs[k++] = wt.sym(v);
+ } else {
+ auto child = wt.expand(v);
+ auto child_ranges = wt.expand(v, r);
+ if (!empty(get<0>(child_ranges))) {
+ _interval_symbols_rec(wt, get<0>(child_ranges), k, cs, rank_c_i,
+ rank_c_j, get<0>(child));
+ }
+ if (!empty(get<1>(child_ranges))) {
+ _interval_symbols_rec(wt, get<1>(child_ranges), k, cs, rank_c_i,
+ rank_c_j, get<1>(child));
+ }
+ }
+}
+
+template<class t_wt>
+void
+_interval_symbols(const t_wt& wt, typename t_wt::size_type i,
+ typename t_wt::size_type j,
+ typename t_wt::size_type& k,
+ std::vector<typename t_wt::value_type>& cs,
+ std::vector<typename t_wt::size_type>& rank_c_i,
+ std::vector<typename t_wt::size_type>& rank_c_j)
+{
+
+ assert(i <= j and j <= wt.size());
+ k=0;
+ if ((i+1)==j) {
+ auto res = wt.inverse_select(i);
+ cs[0]=res.second;
+ rank_c_i[0]=res.first;
+ rank_c_j[0]=res.first+1;
+ k=1;
+ return;
+ } else if (j>i) {
+ _interval_symbols_rec(wt, range_type(i,j-1), k, cs,
+ rank_c_i, rank_c_j, wt.root());
+ }
+}
+
+//! For each symbol c in wt[i..j-1] get rank(i,c) and rank(j,c).
+/*!
+ * \param i The start index (inclusive) of the interval.
+ * \param j The end index (exclusive) of the interval.
+ * \param k Reference for number of different symbols in [i..j-1].
+ * \param cs Reference to a vector that will contain in
+ * cs[0..k-1] all symbols that occur in [i..j-1] in
+ * ascending order.
+ * \param rank_c_i Reference to a vector which equals
+ * rank_c_i[p] = rank(i,cs[p]), for \f$ 0 \leq p < k \f$.
+ * \param rank_c_j Reference to a vector which equals
+ * rank_c_j[p] = rank(j,cs[p]), for \f$ 0 \leq p < k \f$.
+ * \par Time complexity
+ * \f$ \Order{\min{\sigma, k \log \sigma}} \f$
+ *
+ * \par Precondition
+ * \f$ i \leq j \leq size() \f$
+ * \f$ cs.size() \geq \sigma \f$
+ * \f$ rank_{c_i}.size() \geq \sigma \f$
+ * \f$ rank_{c_j}.size() \geq \sigma \f$
+ */
+template<class t_wt>
+void
+interval_symbols(const t_wt& wt, typename t_wt::size_type i,
+ typename t_wt::size_type j,
+ typename t_wt::size_type& k,
+ std::vector<typename t_wt::value_type>& cs,
+ std::vector<typename t_wt::size_type>& rank_c_i,
+ std::vector<typename t_wt::size_type>& rank_c_j)
+{
+ // check if wt has a built-in interval_symbols method
+ constexpr bool has_own = has_interval_symbols<t_wt>::value;
+ if (has_own) { // if yes, call it
+ _interval_symbols_wt<t_wt, has_own>::call(wt, i, j, k,
+ cs, rank_c_i, rank_c_j);
+ } else { // otherwise use generic implementation based on expand
+ _interval_symbols(wt, i,j, k, cs, rank_c_i, rank_c_j);
+ }
+}
+
+
+
+// has_interval_symbols<X>::value is true if class X has
+// implement method interval_symbols
+// Adapted solution from jrok's proposal:
+// http://stackoverflow.com/questions/87372/check-if-a-class-has-a-member-function-of-a-given-signature
+template<typename t_wt>
+struct has_interval_symbols {
+ template<typename T>
+ static constexpr auto check(T*)
+ -> typename
+ std::is_same<
+ decltype(std::declval<T>().interval_symbols(
+ std::declval<typename T::size_type>(),
+ std::declval<typename T::size_type>(),
+ std::declval<typename T::size_type&>(),
+ std::declval<std::vector<typename T::value_type>&>(),
+ std::declval<std::vector<typename T::size_type>&>(),
+ std::declval<std::vector<typename T::size_type>&>()
+ )),
+ void>::type {return std::true_type();}
+ template<typename>
+ static constexpr std::false_type check(...) {return std::false_type();}
+ typedef decltype(check<t_wt>(nullptr)) type;
+ static constexpr bool value = type::value;
+};
+
+template<typename t_wt, bool t_has_interval_symbols>
+struct _interval_symbols_wt {
+ typedef typename t_wt::size_type size_type;
+ typedef typename t_wt::value_type value_type;
+
+ static void call(const t_wt& wt, size_type i, size_type j, size_type& k,
+ std::vector<value_type>& cs, std::vector<size_type>& rank_c_i,
+ std::vector<size_type>& rank_c_j) {
+ wt.interval_symbols(i,j,k,cs,rank_c_i,rank_c_j);
+ }
+};
+
+
+template<typename t_wt>
+struct _interval_symbols_wt<t_wt, false> {
+ typedef typename t_wt::size_type size_type;
+ typedef typename t_wt::value_type value_type;
+
+ static void call(const t_wt&, size_type, size_type, size_type&,
+ std::vector<value_type>&, std::vector<size_type>&,
+ std::vector<size_type>&) {
+ }
+};
+
+template<typename, typename T>
+struct has_expand {
+ static_assert(std::integral_constant<T, false>::value,
+ "Second template parameter needs to be of function type.");
+};
+
+template<typename t_wt, typename t_ret, typename... t_args>
+struct has_expand<t_wt, t_ret(t_args...)> {
+ template<typename T>
+ static constexpr auto check(T*)
+ -> typename
+ std::is_same<
+ decltype(std::declval<T>().expand(std::declval<t_args>()...)),
+ t_ret>::type { return std::true_type();}
+ template<typename>
+static constexpr std::false_type check(...) { return std::false_type();}
+typedef decltype(check<t_wt>(nullptr)) type;
+static constexpr bool value = type::value;
+};
+
+template<typename t_wt>
+struct has_range_search_2d {
+ template<typename T>
+ static constexpr auto check(T*)
+ -> typename
+ std::is_same<
+ decltype(std::declval<T>().range_search_2d(//
+ std::declval<typename T::size_type>(),
+ std::declval<typename T::size_type>(),
+ std::declval<typename T::value_type>(),
+ std::declval<typename T::value_type>(),
+ false
+ )),
+ std::pair<typename T::size_type,
+ std::vector<std::pair<typename T::value_type,
+ typename T::size_type>>>>::type {return std::true_type();}
+
+ template<typename>
+ static constexpr std::false_type check(...) {return std::false_type();}
+ typedef decltype(check<t_wt>(nullptr)) type;
+ static constexpr bool value = type::value;
+};
+
+
+//! Returns for a symbol c the previous smaller or equal symbol in the WT.
+/*! \param c the symbol
+ * \return A pair. The first element of the pair consititues if
+ * a valid answer was found (true) or no valid answer (false)
+ * could be found. The second element contains the found symbol.
+ */
+template<class t_wt>
+std::pair<bool,typename t_wt::value_type>
+_symbol_lte(const t_wt& wt,typename t_wt::value_type c)
+{
+ if (((1ULL) << (wt.max_level)) <= c) {
+ // c is greater than any symbol in wt. return the largest symbol!
+ c = sdsl::bits::lo_set[wt.max_level];
+ }
+ auto node = wt.root();
+ auto predecessor_subtree = node;
+ uint64_t mask = (1ULL) << (wt.max_level - 1);
+ while (!wt.is_leaf(node)) {
+ auto children = wt.expand(node);
+ auto left_child = std::get<0>(children);
+ auto right_child = std::get<1>(children);
+ if (c & (mask >> node.level)) { // go right
+ if (right_child.size) {
+ node = right_child;
+ if (left_child.size) { // potential predecessor subtree?
+ predecessor_subtree = left_child;
+ }
+ } else { // dead end
+ // left child can't be empty if left child is
+ node = left_child;
+ c = sdsl::bits::all_set;
+ }
+ } else { // go left
+ if (left_child.size) {
+ node = left_child;
+ } else { // dead end
+ if (predecessor_subtree == wt.root()) {
+ // there is no valid predecessor. symbol must be
+ // smaller than the smallest symbol in the wt.
+ return {false, 0};
+ }
+ node = predecessor_subtree;
+ c = sdsl::bits::all_set;
+ }
+ }
+ }
+ return {true, node.sym};
+}
+
+
+//! Returns for a symbol c the next larger or equal symbol in the WT.
+/*! \param c the symbol
+ * \return A pair. The first element of the pair consititues if
+ * a valid answer was found (true) or no valid answer (false)
+ * could be found. The second element contains the found symbol.
+ */
+template<class t_wt>
+std::pair<bool,typename t_wt::value_type>
+_symbol_gte(const t_wt& wt,typename t_wt::value_type c)
+{
+ if (((1ULL) << (wt.max_level)) <= c) {
+ // c is greater than any symbol in wt
+ return {false, 0};
+ }
+ auto node = wt.root();
+ auto successor_subtree = node;
+ uint64_t mask = (1ULL) << (wt.max_level - 1);
+ while (!wt.is_leaf(node)) {
+ auto children = wt.expand(node);
+ auto left_child = std::get<0>(children);
+ auto right_child = std::get<1>(children);
+ if (c & (mask >> node.level)) { // go right
+ if (right_child.size) {
+ node = right_child;
+ } else { // dead end
+ if (successor_subtree == wt.root()) {
+ // there is no valid successor. symbol must be
+ // bigger than the largest symbol in the wt.
+ return {false, 0};
+ }
+ node = successor_subtree;
+ c = 0;
+ }
+ } else { // go left
+ if (left_child.size) {
+ node = left_child;
+ if (right_child.size) { // potential successor subtree?
+ successor_subtree = right_child;
+ }
+ } else { // dead end
+ // right child can't be empty if left child is
+ node = right_child;
+ c = 0;
+ }
+ }
+ }
+ return {true, node.sym};
+}
+
+template<class t_wt, bool t_has_interval_symbols>
+struct _symbols_calls_wt {
+ typedef typename t_wt::value_type value_type;
+
+ static std::pair<bool, value_type>
+ call_symbol_gte(const t_wt& wt,value_type c) {
+ return wt.symbol_gte(c);
+ }
+
+ static std::pair<bool,value_type>
+ call_symbol_lte(const t_wt& wt,value_type c) {
+ return wt.symbol_lte(c);
+ }
+};
+
+
+template<class t_wt>
+struct _symbols_calls_wt<t_wt, false> {
+ typedef typename t_wt::value_type value_type;
+
+ static std::pair<bool,value_type>
+ call_symbol_gte(const t_wt& wt,value_type c) {
+ return _symbol_gte(wt,c);
+ }
+
+ static std::pair<bool,value_type>
+ call_symbol_lte(const t_wt& wt,value_type c) {
+ return _symbol_lte(wt,c);
+ }
+};
+
+template<typename t_wt>
+struct has_symbols_wt {
+ template<typename T>
+ static constexpr auto check(T*)
+ -> typename
+ std::is_same<
+ decltype(std::declval<T>().symbol_gte(std::declval<typename T::value_type>())),
+ std::pair<bool,typename T::value_type>
+ >::type {return std::true_type();}
+
+ template<typename>
+ static constexpr std::false_type check(...) {return std::false_type();}
+ typedef decltype(check<t_wt>(nullptr)) type;
+ static constexpr bool value = type::value;
+};
+
+//! Returns for a symbol c the previous smaller or equal symbol in the WT.
+/*! \param c the symbol
+ * \return A pair. The first element of the pair consititues if
+ * a valid answer was found (true) or no valid answer (false)
+ * could be found. The second element contains the found symbol.
+ */
+template<class t_wt>
+std::pair<bool,typename t_wt::value_type>
+symbol_lte(const t_wt& wt, typename t_wt::value_type c)
+{
+ static_assert(t_wt::lex_ordered, "symbols_lte requires a lex_ordered WT");
+ // check if wt has a built-in interval_symbols method
+ constexpr bool has_own = has_symbols_wt<t_wt>::value;
+ return _symbols_calls_wt<t_wt, has_own>::call_symbol_lte(wt,c);
+}
+
+//! Returns for a symbol c the next larger or equal symbol in the WT.
+/*! \param c the symbol
+ * \return A pair. The first element of the pair consititues if
+ * a valid answer was found (true) or no valid answer (false)
+ * could be found. The second element contains the found symbol.
+ */
+template<class t_wt>
+std::pair<bool,typename t_wt::value_type>
+symbol_gte(const t_wt& wt, typename t_wt::value_type c)
+{
+ static_assert(t_wt::lex_ordered, "symbols_gte requires a lex_ordered WT");
+ // check if wt has a built-in interval_symbols method
+ constexpr bool has_own = has_symbols_wt<t_wt>::value;
+ return _symbols_calls_wt<t_wt, has_own>::call_symbol_gte(wt,c);
+}
+
+//! Returns for a x range [x_i,x_j] and a value range [y_i,y_j] all unique y
+//! values occuring in [x_i,x_j] in ascending order.
+/*! \param x_i lower bound of the x range
+ * \param x_j upper bound of the x range
+ * \param y_i lower bound of the y range
+ * \param y_j upper bound of the y range
+ * \return a vector of increasing y values occuring in the range [x_i,x_j]
+ */
+template <class t_wt>
+std::vector<typename t_wt::value_type>
+restricted_unique_range_values(const t_wt& wt,
+ typename t_wt::size_type x_i,
+ typename t_wt::size_type x_j,
+ typename t_wt::value_type y_i,
+ typename t_wt::value_type y_j)
+{
+ static_assert(t_wt::lex_ordered, "restricted_unique_range_values requires a lex_ordered WT");
+
+ std::vector<typename t_wt::value_type> unique_values;
+
+ // make sure things are within bounds
+ if( x_j > wt.size()-1 ) x_j = wt.size()-1;
+ if( (x_i > x_j) || (y_i > y_j) ) {
+ return unique_values;
+ }
+ auto lower_y_bound = symbol_gte(wt,y_i);
+ auto upper_y_bound = symbol_lte(wt,y_j);
+ // is the y range valid?
+ if( !lower_y_bound.first || !upper_y_bound.first
+ || (lower_y_bound.second > upper_y_bound.second) ) {
+ return unique_values;
+ }
+
+ auto lower_y_bound_path = wt.path(lower_y_bound.second);
+ auto upper_y_bound_path = wt.path(upper_y_bound.second);
+
+ auto compare_path = [](uint64_t node_path,uint64_t node_path_len,
+ std::pair<uint64_t,uint64_t> bound_path) -> int {
+ auto bound_path_len = bound_path.first;
+ auto bound_path_val = bound_path.second;
+ /* align to same length */
+ if (bound_path_len > node_path_len)
+ bound_path_val = bound_path_val >> (bound_path_len-node_path_len);
+ if (bound_path_len < node_path_len)
+ bound_path_val = bound_path_val << (node_path_len-bound_path_len);
+ /* cmp */
+ if (node_path < bound_path_val) return -1;
+ if (node_path > bound_path_val) return 1;
+ return 0;
+ };
+
+ std::stack<std::tuple<typename t_wt::node_type,sdsl::range_type,uint64_t,uint64_t>> stack;
+ sdsl::range_type initial_range = {x_i,x_j};
+ stack.emplace(wt.root(),initial_range,0,0);
+ while (!stack.empty()) {
+ auto node_data = stack.top(); stack.pop();
+ auto node = std::get<0>(node_data);
+ auto range = std::get<1>(node_data);
+ auto node_path = std::get<2>(node_data);
+ auto node_level = std::get<3>(node_data);
+ if (wt.is_leaf(node)) {
+ unique_values.emplace_back(wt.sym(node));
+ } else {
+ auto children = wt.expand(node);
+ auto left_path = node_path<<1ULL;
+ auto right_path = (node_path<<1ULL)|1ULL;
+ auto child_ranges = wt.expand(node,range);
+ if (compare_path(right_path,node_level+1,upper_y_bound_path) < 1) {
+ auto right_child = std::get<1>(children);
+ auto right_range = std::get<1>(child_ranges);
+ if (!sdsl::empty(right_range))
+ stack.emplace(right_child,right_range,right_path,node_level+1);
+ }
+ if (compare_path(left_path,node_level+1,lower_y_bound_path) > -1) {
+ auto left_child = std::get<0>(children);
+ auto left_range = std::get<0>(child_ranges);
+ if (!sdsl::empty(left_range))
+ stack.emplace(left_child,left_range,left_path,node_level+1);
+ }
+ }
+ }
+
+ return unique_values;
+}
+
+
+
+// Check for node_type of wavelet_tree
+// http://stackoverflow.com/questions/7834226/detecting-typedef-at-compile-time-template-metaprogramming
+
+template<typename T>
+struct void_ { typedef void type; };
+
+template<typename t_wt, typename T = void>
+struct has_node_type {
+ static constexpr std::false_type value = std::false_type();
+};
+
+template<typename t_wt>
+struct has_node_type<t_wt, typename void_<typename t_wt::node_type>::type> {
+ static constexpr std::true_type value = std::true_type();
+};
+
+
+
+} // end namespace
+
+#endif
diff --git a/include/sdsl/wt_blcd.hpp b/include/sdsl/wt_blcd.hpp
new file mode 100644
index 0000000..aa0f430
--- /dev/null
+++ b/include/sdsl/wt_blcd.hpp
@@ -0,0 +1,132 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_blcd.hpp
+ * \brief wt_blcd.hpp contains a generic wavelet tree class.
+ * \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_WT_BLCD
+#define INCLUDED_SDSL_WT_BLCD
+
+#include "wt_pc.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+// forward declaration
+struct balanced_shape;
+
+//! A balanced wavelet tree.
+/*!
+ * \par Space complexity
+ * \f$\Order{n\log|\Sigma| + 2|\Sigma|\log n}\f$ bits, where \f$n\f$ is
+ * the size of the vector the wavelet tree was build for.
+ *
+ * \tparam t_bitvector Underlying bitvector structure.
+ * \tparam t_rank Type of the support structure for rank on pattern `1`.
+ * \tparam t_select Type of the support structure for select on pattern `1`.
+ * \tparam t_select_zero Type of the support structure for select on pattern `0`.
+ *
+ * \par Reference
+ * Roberto Grossi, Ankur Gupta, Jeffrey Scott Vitter:
+ * High-order entropy-compressed text indexes.
+ * Proceedings of the 14th Annual ACM-SIAM Symposium on
+ * Discrete Algorithms (SODA 2013).
+ *
+ * @ingroup wt
+ */
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select_one = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type,
+ class t_tree_strat = byte_tree<>
+ >
+using wt_blcd = wt_pc<balanced_shape,
+ t_bitvector,
+ t_rank,
+ t_select_one,
+ t_select_zero,
+ t_tree_strat>;
+
+template<class t_wt>
+struct _balanced_shape {
+ typedef typename t_wt::size_type size_type;
+ typedef std::pair<uint64_t, uint64_t> tPII; // (freq, nodenr)-pair
+ enum { lex_ordered = 1 };
+
+ template<class t_rac>
+ static void
+ construct_tree(t_rac& C, std::vector<pc_node>& temp_nodes) {
+ size_type c = 0;
+ std::vector<uint64_t> symbols;
+ std::for_each(std::begin(C), std::end(C), [&](decltype(*std::begin(C)) &freq) {
+ if (freq > 0) {
+ symbols.push_back(c);
+ }
+ ++c;
+ });
+ uint64_t sigma = symbols.size();
+ if (sigma > 0) {
+ _construct_tree(pc_node::undef, symbols, 0, sigma, C, temp_nodes);
+ pc_node root = temp_nodes[0];
+ for (uint64_t i=1; i < temp_nodes.size(); ++i) {
+ temp_nodes[i-1] = temp_nodes[i];
+ temp_nodes[i-1].parent = (temp_nodes[i-1].parent+temp_nodes.size()-1)%temp_nodes.size();
+ temp_nodes[i-1].child[0] -= (temp_nodes[i-1].child[0] != pc_node::undef);
+ temp_nodes[i-1].child[1] -= (temp_nodes[i-1].child[1] != pc_node::undef);
+ }
+ root.child[0] -= (root.child[0] != pc_node::undef);
+ root.child[1] -= (root.child[1] != pc_node::undef);
+ temp_nodes[temp_nodes.size()-1] = root;
+ }
+ }
+
+ // recursive construct_tree method returns node frequency and node pointer
+ template<class t_rac>
+ static tPII
+ _construct_tree(uint64_t parent,
+ const std::vector<uint64_t>& symbols,
+ uint64_t lb,
+ uint64_t sigma,
+ const t_rac& C, std::vector<pc_node>& temp_nodes) {
+ if (sigma == 1) {
+ uint64_t freq = C[symbols[lb]];
+ temp_nodes.emplace_back(pc_node(freq, symbols[lb], parent, pc_node::undef, pc_node::undef));
+ return tPII(freq, temp_nodes.size()-1);
+ } else {
+ temp_nodes.emplace_back(pc_node(0, 0, parent, pc_node::undef, pc_node::undef));
+ uint64_t node_id = temp_nodes.size()-1;
+ uint64_t l_sigma = (sigma+1)/2;
+ tPII freq_nptr_0 = _construct_tree(node_id, symbols, lb, l_sigma, C, temp_nodes);
+ tPII freq_nptr_1 = _construct_tree(node_id, symbols, lb+l_sigma, sigma-l_sigma, C, temp_nodes);
+ uint64_t freq = freq_nptr_0.first + freq_nptr_1.first;
+ temp_nodes[node_id].freq = freq;
+ temp_nodes[node_id].child[0] = freq_nptr_0.second;
+ temp_nodes[node_id].child[1] = freq_nptr_1.second;
+ return tPII(freq, node_id);
+ }
+ }
+
+};
+
+struct balanced_shape {
+ template<class t_wt>
+ using type = _balanced_shape<t_wt>;
+};
+
+}// end namespace sdsl
+#endif
diff --git a/include/sdsl/wt_gmr.hpp b/include/sdsl/wt_gmr.hpp
new file mode 100644
index 0000000..c2bdbb9
--- /dev/null
+++ b/include/sdsl/wt_gmr.hpp
@@ -0,0 +1,931 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2014 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_gmr.hpp
+ \brief wt_gmr.hpp contains a specialized class to support select, rank
+ and access on inputs over a large alphabet.
+ \author Alexander Diehm, Timo Beller, Simon Gog
+*/
+#ifndef INCLUDED_SDSL_WT_GMR
+#define INCLUDED_SDSL_WT_GMR
+
+#include <sdsl/bit_vectors.hpp>
+#include <sdsl/int_vector.hpp>
+#include <sdsl/vectors.hpp>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! Class inv_multi_perm_support adds access to the inverse of permutations.
+/*!
+ * \tparam t_s Sampling parameter of the inverse permutation.
+ * \tparam t_rac Type of the random access container used for storing the permutation.
+ * \tparam t_bv Type of the bitvector used to indicate back-pointers.
+ * \tparam t_rank Type of rank_support to rank the indicator bitvector.
+ *
+ * This support class adds access to the inverse of permutations in at
+ * most \(t_s\) steps.
+ *
+ * \par References
+ * [1] J. Munro, R. Raman, V. Raman, S. Rao: ,,Succinct representation
+ * of permutations'', Proceedings of ICALP 2003
+ */
+template<uint64_t t_s=32,
+ class t_rac=int_vector<>,
+ class t_bv=bit_vector,
+ class t_rank=typename t_bv::rank_1_type>
+class inv_multi_perm_support
+{
+ public:
+
+ typedef t_rac iv_type;
+ typedef typename iv_type::size_type size_type;
+ typedef typename iv_type::value_type value_type;
+ typedef typename iv_type::difference_type difference_type;
+ typedef t_bv bit_vector_type;
+ typedef t_rank rank_type;
+ typedef random_access_const_iterator<inv_multi_perm_support> const_iterator;
+
+ private:
+
+ const iv_type* m_perm = nullptr;// pointer to supported permutation
+ uint64_t m_chunksize; // size of one permutation
+ int_vector<> m_back_pointer; // back pointers
+ bit_vector_type m_marked; // back pointer marking
+ rank_type m_marked_rank; // rank support for back pointer marking
+
+ public:
+
+ //! Default constructor
+ inv_multi_perm_support() {};
+
+ //! Constructor
+ inv_multi_perm_support(const iv_type* perm, int_vector<>& iv, uint64_t chunksize) : m_perm(perm), m_chunksize(chunksize) {
+ bit_vector marked(iv.size(), 0);
+ bit_vector done(m_chunksize, 0);
+
+ size_type max_back_pointer = 0;
+ for (size_type i=0, off=0; i < iv.size(); ++i) {
+ if (i == off+chunksize) {
+ off = i;
+ util::set_to_value(done, 0);
+ }
+ if (!done[i-off]) {
+ done[i-off] = 1;
+ size_type back_pointer=i, j = i, j_new=0;
+ uint64_t steps = 0, all_steps = 0;
+ while ((j_new=(iv[j]+off)) != i) {
+ j = j_new;
+ done[j-off] = 1;
+ ++steps; ++all_steps;
+ if (t_s == steps) {
+ max_back_pointer = std::max(max_back_pointer, back_pointer-off);
+ marked[j] = 1;
+ steps = 0;
+ back_pointer = j;
+ }
+ }
+ if (all_steps > t_s) {
+ marked[i] = 1;
+ max_back_pointer = std::max(max_back_pointer, back_pointer-off);
+ }
+ }
+ }
+
+ m_marked = t_bv(std::move(marked));
+ util::init_support(m_marked_rank, &m_marked);
+
+ util::set_to_value(done, 0);
+ size_type n_bp = m_marked_rank(iv.size());
+ m_back_pointer = int_vector<>(n_bp, 0, bits::hi(max_back_pointer)+1);
+
+ for (size_type i=0, off=0; i < iv.size(); ++i) {
+ if (i == off+chunksize) {
+ off = i;
+ util::set_to_value(done, 0);
+ }
+ if (!done[i-off]) {
+ done[i-off] = 1;
+ size_type back_pointer = i, j = i, j_new=0;
+ uint64_t steps = 0, all_steps = 0;
+ while ((j_new=(iv[j]+off)) != i) {
+ j = j_new;
+ done[j-off] = 1;
+ ++steps; ++all_steps;
+ if (t_s == steps) {
+ m_back_pointer[m_marked_rank(j)] = back_pointer-off;
+ steps = 0;
+ back_pointer = j;
+ }
+ }
+ if (all_steps > t_s) {
+ m_back_pointer[m_marked_rank(i)] = back_pointer-off;
+ }
+ }
+ }
+ }
+
+ //! Copy constructor
+ inv_multi_perm_support(const inv_multi_perm_support& p) : m_perm(p.m_perm),
+ m_chunksize(p.m_chunksize), m_back_pointer(p.m_back_pointer), m_marked(p.m_marked),
+ m_marked_rank(p.m_marked_rank) {
+ m_marked_rank.set_vector(&m_marked);
+ }
+
+ //! Move constructor
+ inv_multi_perm_support(inv_multi_perm_support&& p) {
+ *this = std::move(p);
+ }
+
+ //! Assignment operation
+ inv_multi_perm_support& operator=(const inv_multi_perm_support& p) {
+ if (this != &p) {
+ m_perm = p.m_perm;
+ m_chunksize = p.m_chunksize;
+ m_back_pointer = p.m_back_pointer;
+ m_marked = p.m_marked;
+ m_marked_rank = p.m_marked_rank;
+ m_marked_rank.set_vector(&m_marked);
+ }
+ return *this;
+ }
+
+ //! Assignment move operation
+ inv_multi_perm_support& operator=(inv_multi_perm_support&& p) {
+ if (this != &p) {
+ m_perm = std::move(p.m_perm);
+ m_chunksize = std::move(p.m_chunksize);
+ m_back_pointer = std::move(p.m_back_pointer);
+ m_marked = std::move(p.m_marked);
+ m_marked_rank = std::move(p.m_marked_rank);
+ m_marked_rank.set_vector(&m_marked);
+ }
+ return *this;
+ }
+
+ //! Swap operation
+ void swap(inv_multi_perm_support& p) {
+ if (this != &p) {
+ std::swap(m_chunksize, p.m_chunksize);
+ m_back_pointer.swap(p.m_back_pointer);
+ m_marked.swap(p.m_marked);
+ util::swap_support(m_marked_rank, p.m_marked_rank, &m_marked, &(p.m_marked));
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size() const {
+ return nullptr == m_perm ? 0 : m_perm->size();
+ }
+
+ //! Returns whether the original vector contains no data.
+ bool empty()const {
+ return size() == 0;
+ }
+
+ //! Access operator
+ /*
+ * \par Time complexity
+ * \f$ \Order{t_s} \f$
+ */
+ value_type operator[](size_type i) const {
+ size_type off = (i/m_chunksize)*m_chunksize;
+ size_type j = i, j_new=0;
+ while ((j_new=((*m_perm)[j])+off) != i) {
+ if (m_marked[j]) {
+ j = m_back_pointer[m_marked_rank(j)]+off;
+ while ((j_new=((*m_perm)[j])+off) != i) j = j_new;
+ } else {
+ j = j_new;
+ }
+ }
+ return j;
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ void set_vector(const iv_type* v) { m_perm = v; }
+
+ //! Serialize into stream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_chunksize, out, child, "chunksize");
+ written_bytes += m_back_pointer.serialize(out, child, "back_pointer");
+ written_bytes += m_marked.serialize(out, child, "marked");
+ written_bytes += m_marked_rank.serialize(out, child, "marked_rank");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Load sampling from disk
+ void load(std::istream& in, const iv_type* v=nullptr) {
+ set_vector(v);
+ read_member(m_chunksize, in);
+ m_back_pointer.load(in);
+ m_marked.load(in);
+ m_marked_rank.load(in, &m_marked);
+ }
+};
+
+template<class t_rac>
+void
+_transform_to_compressed(int_vector<>& iv, typename std::enable_if<!(std::is_same<t_rac, int_vector<>>::value),
+ t_rac>::type& rac, const std::string filename)
+{
+ std::string tmp_file_name = tmp_file(filename, "_compress_int_vector");
+ store_to_file(iv, tmp_file_name);
+ util::clear(iv);
+ int_vector_buffer<> buf(tmp_file_name, std::ios::in, 1024*1024, iv.width());
+ rac = t_rac(buf);
+ buf.close(true); // delete tmp_file
+}
+
+template<class t_rac>
+void
+_transform_to_compressed(int_vector<>& iv, typename std::enable_if<std::is_same<t_rac, int_vector<>>::value,
+ t_rac>::type& rac, const std::string)
+{
+ rac = std::move(iv);
+}
+
+//! A wavelet tree class for integer sequences.
+/*!
+ * \tparam t_rac Type of the random access container used for E.
+ * \tparam t_bitvector Type of the bitvector used for storing B.
+ * \tparam t_select Type of the support structure for select on pattern `1`.
+ * \tparam t_select_zero Type of the support structure for select on pattern `0`.
+ *
+ * This is an implementation of the first proposal in the SODA paper of Golynski et. al.
+ * which support fast rank and select, but not fast access.
+ *
+ * \par References
+ * [1] A. Golynski, J. Munro and S. Rao:
+ * ,,Rank/select operations on large alphabets: a tool for text indexing''
+ * Proceedings of SODA 2006.
+ *
+ * @ingroup wt
+ */
+template<class t_rac = int_vector<>,
+ class t_bitvector = bit_vector,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type>
+class wt_gmr_rs
+{
+ public:
+
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<>::value_type value_type;
+ typedef wt_tag index_category;
+ typedef int_alphabet_tag alphabet_category;
+ enum {lex_ordered=0};
+
+ private:
+
+ t_bitvector m_bv_blocks;
+ t_rac m_e;
+ t_select m_bv_blocks_select1;
+ t_select_zero m_bv_blocks_select0;
+ uint64_t m_size; // input length
+ uint64_t m_block_size = 0; // size of the blocks
+ uint64_t m_blocks; // blocks per character
+ uint64_t m_sigma = 0;
+
+ public:
+
+ const size_type& sigma = m_sigma;
+
+ //! Default constructor
+ wt_gmr_rs() {}
+
+ //! Semi-external constructor
+ /*! \param buf File buffer of the int_vector for which the wt_gmr should be build.
+ * \param size Size of the prefix of v, which should be indexed.
+ */
+ template<uint8_t int_width>
+ wt_gmr_rs(int_vector_buffer<int_width>& input, size_type size) : m_size(size) {
+ // Determine max. symbol
+ for (uint64_t i=0; i<m_size; ++i) {
+ if (m_block_size < input[i]) m_block_size = input[i];
+ }
+ ++m_block_size;
+
+ // Create and fill m_bv_blocks
+ m_blocks = (m_size+m_block_size-1)/m_block_size;
+ bit_vector b(m_size+m_block_size*m_blocks+1, 0);
+ int_vector<> symbols(m_block_size, 0, bits::hi(m_size)+1);
+ {
+ int_vector<> tmp(m_block_size*m_blocks, 0, bits::hi(m_block_size)+1);
+
+ for (uint64_t i=0, offset=0, j=0; i<m_size; ++i, ++j) {
+ if (j==m_block_size) {
+ ++offset;
+ j = 0;
+ }
+ ++tmp[input[i]*m_blocks+offset];
+ }
+
+ for (uint64_t i=0; i<symbols.size(); ++i) {
+ for (uint64_t j=m_blocks*i; j<(i+1)*m_blocks; ++j) {
+ symbols[i] += tmp[j];
+ }
+ }
+
+ for (uint64_t i=0,l=1; i<tmp.size(); ++i,++l) {
+ for (uint64_t j=0; j<tmp[i]; ++j)
+ b[l++]=1;
+ }
+
+ // calc m_sigma
+ bool write = true;
+ uint64_t blocks = 0;
+ for (uint64_t i=1; i<b.size(); ++i) {
+ if (blocks==m_blocks) {
+ blocks = 0;
+ write = true;
+ }
+ if (b[i]) {
+ if (write) {
+ ++m_sigma;
+ write = false;
+ }
+ } else ++blocks;
+ }
+
+ m_bv_blocks = t_bitvector(std::move(b));
+ }
+
+ // Create and fill e
+ int_vector<> positions(m_size, 0, bits::hi(m_block_size)+1);
+ for (uint64_t i=0, tmp=0, sum=0; i<m_block_size; ++i) {
+ tmp = symbols[i];
+ symbols[i] = sum;
+ sum += tmp;
+ }
+ for (uint64_t i=0; i<m_size;) {
+ for (uint64_t j=0; j<m_block_size and i<m_size; ++i, ++j) {
+ positions[symbols[input[i]]++] = j;
+ }
+ }
+ _transform_to_compressed<t_rac>(positions, m_e, input.filename());
+
+ util::init_support(m_bv_blocks_select0, &m_bv_blocks);
+ util::init_support(m_bv_blocks_select1, &m_bv_blocks);
+ }
+
+ //! Copy constructor
+ wt_gmr_rs(const wt_gmr_rs& wt) {
+ m_bv_blocks = wt.m_bv_blocks;
+ m_e = wt.m_e;
+ m_bv_blocks_select1 = wt.m_bv_blocks_select1;
+ m_bv_blocks_select1.set_vector(&m_bv_blocks);
+ m_bv_blocks_select0 = wt.m_bv_blocks_select0;
+ m_bv_blocks_select0.set_vector(&m_bv_blocks);
+ m_size = wt.m_size;
+ m_block_size = wt.m_block_size;
+ m_blocks = wt.m_blocks;
+ m_sigma = wt.m_sigma;
+ }
+
+ //! Assignment operator
+ wt_gmr_rs& operator=(const wt_gmr_rs& wt) {
+ wt_gmr_rs tmp(wt);
+ tmp.swap(*this);
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(wt_gmr_rs& fs) {
+ if (this != &fs) {
+ m_bv_blocks.swap(fs.m_bv_blocks);
+ m_e.swap(fs.m_e);
+ util::swap_support(m_bv_blocks_select0, fs.m_bv_blocks_select0, &m_bv_blocks, &(fs.m_bv_blocks));
+ util::swap_support(m_bv_blocks_select1, fs.m_bv_blocks_select1, &m_bv_blocks, &(fs.m_bv_blocks));
+ std::swap(m_size, fs.m_size);
+ std::swap(m_block_size, fs.m_block_size);
+ std::swap(m_blocks, fs.m_blocks);
+ std::swap(m_sigma, fs.m_sigma);
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Returns whether the wavelet tree contains no data.
+ bool empty()const {
+ return m_size == 0;
+ }
+
+ //! Recovers the i-th symbol of the original vector.
+ /*! \param i The index of the symbol in the original vector.
+ * \returns The i-th symbol of the original vector.
+ * \par Time complexity
+ * \f$ \Order{|\Sigma|} \f$
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i<m_size);
+ size_type block=i/m_block_size+1, val=i%m_block_size, search_begin, search_end, j;
+ while (true) {
+ j = m_bv_blocks_select0(block)+1;
+ search_begin = j-block;
+ if (m_bv_blocks[j]) {
+ search_end = m_bv_blocks_select0(block+1)-(block);
+ if (search_end-search_begin<50) { // After a short test, this seems to be a good threshold
+ while (search_begin < search_end and m_e[search_begin] <= val) {
+ if (m_e[search_begin]==val) {
+ return (block-1)/m_blocks;
+ }
+ ++search_begin;
+ }
+ } else {
+ if (binary_search(m_e.begin()+search_begin, m_e.begin()+search_end, val)) {
+ return (block-1)/m_blocks;
+ }
+ }
+ }
+ block += m_blocks;
+ }
+ }
+
+ //! Calculates how many symbols c are in the prefix [0..i-1] of the supported vector.
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in[0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the supported vector.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ size_type rank(size_type i, value_type c)const {
+ if (0==i or c>m_block_size-1) {
+ return 0;
+ }
+
+ size_type offset=0;
+ size_type ones_before_cblock = m_bv_blocks_select0(c*m_blocks+1)-c*m_blocks;
+
+ auto begin = m_e.begin()+m_bv_blocks_select0(c*m_blocks+(i-1)/m_block_size+1)-(c*m_blocks+(i-1)/m_block_size+1)+1;
+ auto end = m_e.begin()+m_bv_blocks_select0(c*m_blocks+(i-1)/m_block_size+2)-(c*m_blocks+(i-1)/m_block_size+1);
+
+ size_type val = (i-1)%m_block_size;
+ if (end-begin<50) { // After a short test, this seems to be a good threshold
+ offset = std::find_if(begin, end, [&val](const decltype(*begin) x) { return x > val; }) - begin;
+ } else {
+ offset = lower_bound(begin, end, val+1)-begin;
+ }
+ return (begin-m_e.begin())+offset-ones_before_cblock;
+ }
+
+ //! Calculates how many symbols c are in the prefix [0..i-1] of the supported vector.
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in[0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the supported vector.
+ * \par Time complexity
+ * \f$ \Order{|\Sigma|} \f$
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ std::pair<size_type, value_type> inverse_select(size_type i)const {
+ assert(i<m_size);
+ size_type block = i/m_block_size+1, val = i%m_block_size, offset = 0, search_begin, search_end, j;
+ while (true) {
+ j = m_bv_blocks_select0(block)+1;
+ search_begin = j-block;
+ if (m_bv_blocks[j]) {
+ search_end = m_bv_blocks_select0(block+1)-(block);
+ offset = 0;
+ if (search_end-search_begin<50) { // After a short test, this seems to be a good threshold
+ while (search_begin < search_end and m_e[search_begin] <= val) {
+ if (m_e[search_begin]==val) {
+ value_type c = (block-1)/m_blocks;
+ size_type ones_before_cblock = m_bv_blocks_select0(c*m_blocks+1)-(c*m_blocks);
+ size_type r = search_begin-ones_before_cblock;
+ return std::make_pair(r,c);
+ }
+ ++search_begin;
+ }
+ } else {
+ offset = lower_bound(m_e.begin()+search_begin, m_e.begin()+search_end, val)-m_e.begin();
+ if (offset<search_end) {
+ if (m_e[offset]==val) {
+ value_type c = (block-1)/m_blocks;
+ size_type ones_before_cblock = m_bv_blocks_select0(c*m_blocks+1)-(c*m_blocks);
+ size_type r = offset-ones_before_cblock;
+ return std::make_pair(r,c);
+ }
+ }
+ }
+ }
+ block+=m_blocks;
+ }
+ }
+
+ //! Calculates the i-th occurrence of the symbol c in the supported vector.
+ /*!
+ * \param i The i-th occurrence.
+ * \param c The symbol c.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \par Precondition
+ * \f$ 1 \leq i \leq rank(size(), c) \f$
+ */
+ size_type select(size_type i, value_type c)const {
+ size_type k = m_bv_blocks_select0(c*m_blocks+1)-(c*m_blocks)+i;
+ return (m_bv_blocks_select1(k)-k)*m_block_size+m_e[k-1]-c*m_blocks*m_block_size;
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_block_size, out, child, "block_size");
+ written_bytes += write_member(m_blocks, out, child, "blocks");
+ written_bytes += write_member(m_sigma, out, child, "sigma");
+ written_bytes += m_e.serialize(out, child, "E");
+ written_bytes += m_bv_blocks.serialize(out, child, "bv_blocks");
+ written_bytes += m_bv_blocks_select0.serialize(out, child, "bv_blocks_select0");
+ written_bytes += m_bv_blocks_select1.serialize(out, child, "bv_blocks_select1");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_block_size, in);
+ read_member(m_blocks, in);
+ read_member(m_sigma, in);
+ m_e.load(in);
+ m_bv_blocks.load(in);
+ m_bv_blocks_select0.load(in, &m_bv_blocks);
+ m_bv_blocks_select1.load(in, &m_bv_blocks);
+ }
+};
+
+//! A wavelet tree class for integer sequences.
+/*!
+ * \tparam t_rac Type of the random access container used for storing the permutation.
+ * \tparam t_inv_support Type of the support structure for inverse permutation
+ * \tparam t_bitvector Type of the bitvector used for storing B and X.
+ * \tparam t_select Type of the support structure for select on pattern `1`.
+ * \tparam t_select_zero Type of the support structure for select on pattern `0`.
+ *
+ * This is an implementation of the second proposal in the SODA paper of Golynski et. al.
+ * which supports fast access, inverse select, rank, and select.
+ *
+ * \par References
+ * [1] A. Golynski, J. Munro and S. Rao:
+ * ,,Rank/select operations on large alphabets: a tool for text indexing''
+ * Proceedings of SODA 2006.
+ *
+ * @ingroup wt
+ */
+template<class t_rac = int_vector<>,
+ class t_inverse_support = inv_multi_perm_support<32, t_rac>,
+ class t_bitvector = bit_vector,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type
+ >
+class wt_gmr
+{
+ public:
+
+ typedef typename t_rac::size_type size_type;
+ typedef typename t_rac::value_type value_type;
+ typedef wt_tag index_category;
+ typedef int_alphabet_tag alphabet_category;
+ enum {lex_ordered=0};
+
+ private:
+
+ t_bitvector m_bv_blocks; // 0 indicates end of block. Corresponds to B in the paper.
+ t_bitvector m_bv_chunks; // 0 indicates end of symbol in chunk. Corresponds to X in the paper.
+
+ t_rac m_perm; // Contains permutation of each chunk. Corresponds to \f$ \pi \f$ in the paper.
+ t_inverse_support m_ips; // Support for inverse permutation
+
+ t_select m_bv_blocks_select1, m_bv_chunks_select1;
+ t_select_zero m_bv_blocks_select0, m_bv_chunks_select0;
+
+ uint64_t m_size; // input length
+ uint64_t m_max_symbol = 0; // maximum character + 1
+ uint64_t m_chunks; // number of chunks
+ uint64_t m_chunksize;
+ uint64_t m_sigma = 0;
+
+ public:
+
+ const size_type& sigma = m_sigma;
+
+ //! Default constructor
+ wt_gmr() {}
+
+ //! Semi-external constructor
+ /*! \param buf File buffer of the int_vector for which the wt_gmr should be build.
+ * \param size Size of the prefix of v, which should be indexed.
+ */
+ template<uint8_t int_width>
+ wt_gmr(int_vector_buffer<int_width>& input, size_type size) : m_size(size) {
+ // Determine max. symbol
+ for (uint64_t i=0; i<m_size; ++i) {
+ if (m_max_symbol < input[i]) m_max_symbol = input[i];
+ }
+ ++m_max_symbol;
+ m_chunksize = (1 << (bits::hi(m_max_symbol-1)+1)); // In some cases this is better than m_max_smbol
+ m_chunks = (m_size+m_chunksize-1)/m_chunksize;
+
+ // calc m_bv_blocks
+ {
+ bit_vector b(m_size+m_max_symbol*m_chunks+1, 0);
+ int_vector<> tmp(m_max_symbol*m_chunks, 0, bits::hi(m_max_symbol-1)+2);
+
+ for (uint64_t i=0, offset=0, j=0; i<m_size; ++i, ++j) {
+ if (j==m_chunksize) {
+ ++offset;
+ j = 0;
+ }
+ ++tmp[input[i]*m_chunks+offset];
+ }
+
+ for (uint64_t i=0, l=1; i<tmp.size(); ++i, ++l)
+ for (uint64_t j=0; j<tmp[i]; ++j)
+ b[l++]=1;
+
+ // calc m_sigma
+ bool write = true;
+ uint64_t blocks = 0;
+ for (uint64_t i=1; i<b.size(); ++i) {
+ if (blocks==m_chunks) {
+ blocks = 0;
+ write = true;
+ }
+ if (b[i]) {
+ if (write) {
+ ++m_sigma;
+ write = false;
+ }
+ } else ++blocks;
+ }
+
+ m_bv_blocks = t_bitvector(std::move(b));
+ }
+
+ // Calc perm and bv_chunks
+ {
+ uint64_t x_pos = 0;
+ bit_vector x(m_size+m_chunks*m_max_symbol+1, 0);
+
+ // fill perm and m_bv_chunks for every chunk
+ int_vector<> perm(m_size, 0, bits::hi(m_max_symbol-1)+1);
+ for (uint64_t i=0; i<m_chunks; ++i) {
+ int_vector<> symbols(m_max_symbol, 0, bits::hi(m_max_symbol-1)+2);
+
+ // calc symbols
+ for (uint64_t j=i*m_chunksize; j<(i+1)*m_chunksize and j<m_size; ++j) {
+ ++symbols[input[j]];
+ }
+ // calc m_bv_chunks
+ for (uint64_t j=0; j<m_max_symbol; ++j, ++x_pos)
+ for (uint64_t k=0; k<symbols[j]; ++k)
+ x[++x_pos]=1;
+
+ // calc symbols prefix sum
+ for (uint64_t j=0, tmp=0, sum=0; j<m_max_symbol; ++j) {
+ tmp = symbols[j];
+ symbols[j] = sum;
+ sum += tmp;
+ }
+ // calc perm
+ for (uint64_t j=i* m_chunksize, k=0; j<(i+1)*m_chunksize and j<m_size; ++j, ++k) {
+ perm[i*m_chunksize+(symbols[input[j]]++)] = k;
+ }
+ }
+ m_bv_chunks = t_bitvector(std::move(x));
+ m_ips = t_inverse_support(&m_perm, perm, m_chunksize);
+ _transform_to_compressed<t_rac>(perm, m_perm, input.filename());
+ m_ips.set_vector(&m_perm);
+ }
+ util::init_support(m_bv_chunks_select1, &m_bv_chunks);
+ util::init_support(m_bv_chunks_select0, &m_bv_chunks);
+ util::init_support(m_bv_blocks_select1, &m_bv_blocks);
+ util::init_support(m_bv_blocks_select0, &m_bv_blocks);
+ }
+
+ //! Copy constructor
+ wt_gmr(const wt_gmr& wt) {
+ m_bv_blocks = wt.m_bv_blocks;
+ m_bv_chunks = wt.m_bv_chunks;
+ m_perm = wt.m_perm;
+ m_ips = wt.m_ips;
+ m_bv_blocks_select1 = wt.m_bv_blocks_select1;
+ m_bv_blocks_select1.set_vector(&m_bv_blocks);
+ m_bv_chunks_select1 = wt.m_bv_chunks_select1;
+ m_bv_chunks_select1.set_vector(&m_bv_chunks);
+ m_bv_blocks_select0 = wt.m_bv_blocks_select0;
+ m_bv_blocks_select0.set_vector(&m_bv_blocks);
+ m_bv_chunks_select0 = wt.m_bv_chunks_select0;
+ m_bv_chunks_select0.set_vector(&m_bv_chunks);
+ m_size = wt.m_size;
+ m_max_symbol = wt.m_max_symbol;
+ m_chunks = wt.m_chunks;
+ m_chunksize = wt.m_chunksize;
+ m_sigma = wt.m_sigma;
+ }
+
+ //! Assignment operator
+ wt_gmr& operator=(const wt_gmr& wt) {
+ wt_gmr tmp(wt);
+ tmp.swap(*this);
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(wt_gmr& fs) {
+ if (this != &fs) {
+ m_bv_blocks.swap(fs.m_bv_blocks);
+ m_bv_chunks.swap(fs.m_bv_chunks);
+ m_perm.swap(fs.m_perm);
+ util::swap_support(m_ips, fs.m_ips, &m_perm, &(fs.m_perm));
+ util::swap_support(m_bv_blocks_select0, fs.m_bv_blocks_select0, &m_bv_blocks, &(fs.m_bv_blocks));
+ util::swap_support(m_bv_blocks_select1, fs.m_bv_blocks_select1, &m_bv_blocks, &(fs.m_bv_blocks));
+ util::swap_support(m_bv_chunks_select1, fs.m_bv_chunks_select1, &m_bv_chunks, &(fs.m_bv_chunks));
+ util::swap_support(m_bv_chunks_select0, fs.m_bv_chunks_select0, &m_bv_chunks, &(fs.m_bv_chunks));
+ std::swap(m_size, fs.m_size);
+ std::swap(m_max_symbol, fs.m_max_symbol);
+ std::swap(m_chunks, fs.m_chunks);
+ std::swap(m_chunksize, fs.m_chunksize);
+ std::swap(m_sigma, fs.m_sigma);
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Returns whether the wavelet tree contains no data.
+ bool empty()const {
+ return m_size == 0;
+ }
+
+ //! Recovers the i-th symbol of the original vector.
+ /*! \param i The index of the symbol in the original vector.
+ * \returns The i-th symbol of the original vector.
+ * \par Time complexity
+ * \f$ \Order{1} + 1 Access to the inverse permutation \f$
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ uint64_t chunk = i/m_chunksize;
+ uint64_t x = m_ips[i];
+ return m_bv_chunks_select1(x+1)-x-(chunk*m_max_symbol)-1;
+ }
+
+ //! Calculates how many symbols c are in the prefix [0..i-1] of the supported vector.
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in[0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the supported vector.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ size_type rank(size_type i, value_type c)const {
+ assert(i <= size());
+
+ if (0==i or c>m_max_symbol-1) {
+ return 0;
+ }
+
+ uint64_t chunk = (i-1)/m_chunksize;
+ uint64_t ones_before_c = m_bv_blocks_select0(c*m_chunks+1)-(c*m_chunks+1)+1;
+ uint64_t c_ones_before_chunk = m_bv_blocks_select0(c*m_chunks+chunk+1)-(c*m_chunks+chunk+1)+1-ones_before_c;
+
+ uint64_t c_ones_in_chunk = 0;
+ auto begin = m_perm.begin()+m_bv_chunks_select0(chunk*m_max_symbol+1+c)-(chunk*m_max_symbol+1+c)+1;
+ auto end = m_perm.begin()+m_bv_chunks_select0(chunk*m_max_symbol+2+c)-(chunk*m_max_symbol+2+c)+1;
+
+ size_type val = (i-1)%m_chunksize;
+ if (end-begin<50) { // After a short test, this seems to be a good threshold
+ c_ones_in_chunk = std::find_if(begin, end, [&val](const decltype(*begin) x) { return x > val; }) - begin;
+ } else {
+ c_ones_in_chunk = lower_bound(begin, end, val+1) - begin;
+ }
+ return c_ones_before_chunk+c_ones_in_chunk;
+ }
+
+ //! Calculates how many occurrences of symbol input[i] are in the prefix [0..i-1] of the original input.
+ /*!
+ * \param i The index of the symbol.
+ * \return Pair (rank(input[i],i), input[i])
+ * \par Time complexity
+ * \f$ \Order{1} + One access to the inverse permutation \f$
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ std::pair<size_type, value_type> inverse_select(size_type i)const {
+ assert(i < size());
+ uint64_t chunk = i/m_chunksize;
+ uint64_t x = m_ips[i];
+ uint64_t tmp = m_bv_chunks_select1(x+1);
+ uint64_t c = tmp-x-(chunk*m_max_symbol)-1;
+
+ uint64_t ones_before_c = m_bv_blocks_select0(c*m_chunks+1)-(c*m_chunks+1)+1;
+ uint64_t c_before_chunk = m_bv_blocks_select0(c*m_chunks+chunk+1)-(c*m_chunks+chunk+1)+1-ones_before_c;
+ uint64_t c_in_chunk = tmp-m_bv_chunks_select0(c+1+chunk*m_max_symbol)-1;
+ return std::make_pair(c_before_chunk+c_in_chunk, c);
+ }
+
+ //! Calculates the i-th occurrence of the symbol c in the supported vector.
+ /*!
+ * \param i The i-th occurrence.
+ * \param c The symbol c.
+ * \par Time complexity
+ * \f$ \Order{1} \f$
+ * \par Precondition
+ * \f$ 1 \leq i \leq rank(size(), c) \f$
+ */
+ size_type select(size_type i, value_type c)const {
+ assert(1 <= i and i <= rank(size(), c));
+
+ uint64_t ones_before_c = m_bv_blocks_select0(c*m_chunks+1)-(c*m_chunks);
+ uint64_t chunk = m_bv_blocks_select1(ones_before_c+i)-ones_before_c-(c*m_chunks+1)-i+1;
+ uint64_t c_ones_before_chunk = m_bv_blocks_select0(c*m_chunks+chunk+1)-(c*m_chunks+chunk)-ones_before_c;
+ uint64_t pi_pos = m_bv_chunks_select0(chunk*m_max_symbol+c+1)+(i-c_ones_before_chunk)-chunk*m_max_symbol-c-1;
+
+ return m_perm[pi_pos]+chunk*m_chunksize;
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_max_symbol, out, child, "max_symbol");
+ written_bytes += write_member(m_chunks, out, child, "chunks");
+ written_bytes += write_member(m_chunksize, out, child, "chunksize");
+ written_bytes += write_member(m_sigma, out, child, "sigma");
+ written_bytes += m_bv_blocks.serialize(out, child, "bv_blocks");
+ written_bytes += m_bv_blocks_select0.serialize(out, child, "bv_blocks_select0");
+ written_bytes += m_bv_blocks_select1.serialize(out, child, "bv_blocks_select1");
+ written_bytes += m_bv_chunks.serialize(out, child, "bv_chunks");
+ written_bytes += m_bv_chunks_select0.serialize(out, child, "bv_chunks_select0");
+ written_bytes += m_bv_chunks_select1.serialize(out, child, "bv_chunks_select1");
+ written_bytes += m_perm.serialize(out, child, "permutation");
+ written_bytes += m_ips.serialize(out, child, "inverse_permutation_support");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_max_symbol, in);
+ read_member(m_chunks, in);
+ read_member(m_chunksize, in);
+ read_member(m_sigma, in);
+ m_bv_blocks.load(in);
+ m_bv_blocks_select0.load(in, &m_bv_blocks);
+ m_bv_blocks_select1.load(in, &m_bv_blocks);
+ m_bv_chunks.load(in);
+ m_bv_chunks_select0.load(in, &m_bv_chunks);
+ m_bv_chunks_select1.load(in, &m_bv_chunks);
+ m_perm.load(in);
+ m_ips.load(in, &m_perm);
+ }
+};
+}
+
+#endif
diff --git a/include/sdsl/wt_helper.hpp b/include/sdsl/wt_helper.hpp
new file mode 100644
index 0000000..9617ac4
--- /dev/null
+++ b/include/sdsl/wt_helper.hpp
@@ -0,0 +1,632 @@
+#ifndef INCLUDED_SDSL_WT_HELPER
+#define INCLUDED_SDSL_WT_HELPER
+
+#include "int_vector.hpp"
+#include <algorithm>
+#include <limits>
+#include <deque>
+#include <queue>
+#include <vector>
+#include <utility>
+
+namespace sdsl
+{
+
+typedef std::pair<int_vector<>::size_type, int_vector<>::size_type> range_type;
+typedef std::vector<range_type> range_vec_type;
+
+//! Empty range check
+/*! \param r Range to check
+ * \returns True if the range is empty, false otherwise.
+ */
+bool empty(const range_type& r);
+
+//! Size of a range
+/*! \param r Range to check
+ * \returns True if the range is empty, false otherwise.
+ */
+int_vector<>::size_type size(const range_type& r);
+
+//! Count for each character the number of occurrences in rac[0..size-1]
+/*!
+ * \param C An array of size 256, which contains for each character the number of occurrences in rac[0..size-1]
+ */
+template<class t_file_buffer,class t_rac>
+void calculate_character_occurences(t_file_buffer& text, const int_vector_size_type size, t_rac& C)
+{
+ C = t_rac();
+ if (text.size() < size) {
+ throw std::logic_error("calculate_character_occurrences: stream size is smaller than size!");
+ return;
+ }
+ for (int_vector_size_type i=0; i < size; ++i) {
+ uint64_t c = text[i];
+ if (c >= C.size()) { C.resize(c+1, 0); }
+ ++C[c];
+ }
+}
+
+
+template<class t_rac, class sigma_type>
+void calculate_effective_alphabet_size(const t_rac& C, sigma_type& sigma)
+{
+ sigma = std::count_if(begin(C),end(C),[](decltype(*begin(C)) &x) {
+ return x > 0;
+ });
+}
+
+struct pc_node {
+ uint64_t freq; // frequency of symbol sym
+ uint64_t sym; // symbol
+ uint64_t parent; // pointer to the parent
+ uint64_t child[2]; // pointer to the children
+
+ enum :uint64_t {undef = 0xFFFFFFFFFFFFFFFFULL}; // max uint64_t value
+
+ pc_node(uint64_t freq=0, uint64_t sym=0, uint64_t parent=undef,
+ uint64_t child_left=undef, uint64_t child_right=undef);
+
+ pc_node& operator=(const pc_node& v);
+};
+
+template<class t_tree_strat_fat>
+struct _node {
+ using node_type = typename t_tree_strat_fat::node_type;
+ typedef uint64_t size_type;
+ uint64_t bv_pos = 0; // pointer into the bit_vector, which represents the wavelet tree
+ uint64_t bv_pos_rank = 0; // pre-calculated rank for the prefix up to but not including bv_pos
+ node_type parent = t_tree_strat_fat::undef; // pointer to the parent
+ node_type child[2] = {t_tree_strat_fat::undef,t_tree_strat_fat::undef}; // pointer to the children
+
+ _node(uint64_t bv_pos=0, uint64_t bv_pos_rank=0, node_type parent=t_tree_strat_fat::undef,
+ node_type child_left=t_tree_strat_fat::undef, node_type child_right=t_tree_strat_fat::undef):
+ bv_pos(bv_pos), bv_pos_rank(bv_pos_rank), parent(parent) {
+ child[0] = child_left;
+ child[1] = child_right;
+ }
+
+ _node& operator=(const _node& v) {
+ if (this != &v) {
+ bv_pos = v.bv_pos;
+ bv_pos_rank = v.bv_pos_rank;
+ parent = v.parent;
+ child[0] = v.child[0];
+ child[1] = v.child[1];
+ }
+ return *this;
+ }
+
+ _node& operator=(const pc_node& v) {
+ bv_pos = v.freq;
+ bv_pos_rank = v.sym;
+ parent = v.parent;
+ child[0] = v.child[0];
+ child[1] = v.child[1];
+ return *this;
+ }
+
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* st_child = structure_tree::add_child(v, name, util::class_name(*this));
+ uint64_t written_bytes = 0;
+ written_bytes += write_member(bv_pos, out);
+ written_bytes += write_member(bv_pos_rank, out);
+ written_bytes += write_member(parent, out);
+ out.write((char*)child, 2*sizeof(child[0]));
+ written_bytes += 2*sizeof(child[0]);
+ structure_tree::add_size(st_child, written_bytes);
+ return written_bytes;
+ }
+
+ void load(std::istream& in) {
+ read_member(bv_pos, in);
+ read_member(bv_pos_rank, in);
+ read_member(parent, in);
+ in.read((char*) child, 2*sizeof(child[0]));
+ }
+};
+
+// TODO: version of _byte_tree for lex_ordered tree shapes
+// m_c_to_leaf can be compressed and
+// m_path is only needed for sigma chars
+
+// Strategy class for tree representation of a WT
+template<bool t_dfs_shape, class t_wt>
+struct _byte_tree {
+ using alphabet_category = byte_alphabet_tag;
+ using value_type = uint8_t;
+ using node_type = uint16_t; // node is represented by index in m_nodes
+ using data_node = _node<_byte_tree>;
+ enum :uint16_t {undef = 0xFFFF}; // max uint16_t value
+ enum :uint32_t {fixed_sigma = 256};
+ enum :uint8_t {int_width = 8}; // width of the input integers
+
+
+
+ std::vector<data_node> m_nodes; // nodes for the prefix code tree structure
+ node_type m_c_to_leaf[fixed_sigma]; // map symbol c to a leaf in the tree structure
+ // if m_c_to_leaf[c] == undef the char does
+ // not exists in the text
+ uint64_t m_path[fixed_sigma]; // path information for each char; the bits at position
+ // 0..55 hold path information; bits 56..63 the length
+ // of the path in binary representation
+
+ void copy(const _byte_tree& bt) {
+ m_nodes = bt.m_nodes;
+ for (uint32_t i=0; i<fixed_sigma; ++i)
+ m_c_to_leaf[i] = bt.m_c_to_leaf[i];
+ for (uint32_t i=0; i<fixed_sigma; ++i)
+ m_path[i] = bt.m_path[i];
+ }
+
+ _byte_tree() {}
+
+ _byte_tree(const std::vector<pc_node>& temp_nodes, uint64_t& bv_size, const t_wt*) {
+ m_nodes.resize(temp_nodes.size());
+ m_nodes[0] = temp_nodes.back(); // insert root at index 0
+ bv_size = 0;
+ size_t node_cnt = 1;
+ node_type last_parent = undef;
+ std::deque<node_type> q;
+ q.push_back(0);
+ while (!q.empty()) {
+ node_type idx;
+ if (!t_dfs_shape) {
+ idx = q.front(); q.pop_front();
+ } else {
+ idx = q.back(); q.pop_back();
+ }
+ // frq_sum is store in bv_pos value
+ uint64_t frq = m_nodes[idx].bv_pos;
+ m_nodes[idx].bv_pos = bv_size;
+ if (m_nodes[idx].child[0] != undef) // if node is not a leaf
+ bv_size += frq; // add frequency
+ if (idx > 0) { // node is not the root
+ if (last_parent != m_nodes[idx].parent)
+ m_nodes[m_nodes[idx].parent].child[0] = idx;
+ else
+ m_nodes[m_nodes[idx].parent].child[1] = idx;
+ last_parent = m_nodes[idx].parent;
+ }
+ if (m_nodes[idx].child[0] != undef) { // if node is not a leaf
+ for (uint32_t k=0; k<2; ++k) { // add children to tree
+ m_nodes[node_cnt] = temp_nodes[ m_nodes[idx].child[k] ];
+ m_nodes[node_cnt].parent = idx;
+ q.push_back(node_cnt);
+ m_nodes[idx].child[k] = node_cnt++;
+ }
+ }
+ }
+ // initialize m_c_to_leaf
+ for (uint32_t i=0; i<fixed_sigma; ++i)
+ m_c_to_leaf[i] = undef; // if c is not in the alphabet m_c_to_leaf[c] = undef
+ for (node_type v=0; v < m_nodes.size(); ++v) {
+ if (m_nodes[v].child[0] == undef) // if node is a leaf
+ m_c_to_leaf[(uint8_t)m_nodes[v].bv_pos_rank] = v; // calculate value
+ }
+ // initialize path information
+ // Note: In the case of a bfs search order,
+ // we can classify nodes as right child and left child with an easy criterion:
+ // node is a left child, if node%2==1
+ // node is a right child, if node%2==0
+ for (uint32_t c=0, prev_c=0; c<fixed_sigma; ++c) {
+ if (m_c_to_leaf[c] != undef) { // if char exists in the alphabet
+ node_type v = m_c_to_leaf[c];
+ uint64_t pw = 0; // path
+ uint64_t pl = 0; // path len
+ while (v != root()) { // while node is not the root
+ pw <<= 1;
+ if (m_nodes[m_nodes[v].parent].child[1] == v) // if the node is a right child
+ pw |= 1ULL;
+ ++pl;
+ v = m_nodes[v].parent; // go up the tree
+ }
+ if (pl > 56) {
+ throw std::logic_error("Code depth greater than 56!!!");
+ }
+ m_path[c] = pw | (pl << 56);
+ prev_c = c;
+ } else {
+ uint64_t pl = 0; // len is 0, good for special case in rank
+ m_path[c] = prev_c | (pl << 56);
+ }
+ }
+ }
+
+ template<class t_rank_type>
+ void init_node_ranks(const t_rank_type& rank) {
+ for (uint64_t i=0; i<m_nodes.size(); ++i) {
+ if (m_nodes[i].child[0] != undef) // if node is not a leaf
+ m_nodes[i].bv_pos_rank = rank.rank(m_nodes[i].bv_pos);
+ }
+ }
+
+ _byte_tree(const _byte_tree& bt) {
+ copy(bt);
+ }
+
+ void swap(_byte_tree& bt) {
+ std::swap(m_nodes, bt.m_nodes);
+ for (uint32_t i=0; i<fixed_sigma; ++i) {
+ std::swap(m_c_to_leaf[i], bt.m_c_to_leaf[i]);
+ std::swap(m_path[i], bt.m_path[i]);
+ }
+ }
+
+ _byte_tree& operator=(const _byte_tree& bt) {
+ if (this != &bt) {
+ copy(bt);
+ }
+ return *this;
+ }
+
+ //! Serializes the data structure into the given ostream
+ uint64_t serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="") const {
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ uint64_t written_bytes = 0;
+ uint64_t m_nodes_size = m_nodes.size();
+ write_member(m_nodes_size, out, child, "m_nodes.size()");
+ serialize_vector(m_nodes, out, child, "m_nodes");
+ out.write((char*) m_c_to_leaf, fixed_sigma*sizeof(m_c_to_leaf[0]));
+ written_bytes += fixed_sigma*sizeof(m_c_to_leaf[0]);// bytes from previous loop
+ out.write((char*) m_path, fixed_sigma*sizeof(m_path[0]));
+ written_bytes += fixed_sigma*sizeof(m_path[0]);// bytes from previous loop
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ uint64_t m_nodes_size = 0;
+ read_member(m_nodes_size, in);
+ m_nodes = std::vector<data_node>(m_nodes_size);
+ load_vector(m_nodes, in);
+ in.read((char*) m_c_to_leaf, fixed_sigma*sizeof(m_c_to_leaf[0]));
+ in.read((char*) m_path, fixed_sigma*sizeof(m_path[0]));
+ }
+
+ //! Get corresponding leaf for symbol c.
+ inline node_type c_to_leaf(value_type c)const {
+ return m_c_to_leaf[c];
+ }
+ //! Return the root node of the tree.
+ inline static node_type root() {
+ return 0;
+ }
+
+ //! Return the number of nodes in the tree.
+ uint64_t size() const {
+ return m_nodes.size();
+ }
+
+ //! Return the parent node of v.
+ inline node_type parent(node_type v)const {
+ return m_nodes[v].parent;
+ }
+ //! Return left (i=0) or right (i=1) child node of v.
+ inline node_type child(node_type v, uint8_t i)const {
+ return m_nodes[v].child[i];
+ }
+
+ //! Return if v is a leaf node.
+ inline bool is_leaf(node_type v)const {
+ return m_nodes[v].child[0] == undef;
+ }
+
+ //! Return the path as left/right bit sequence in a uint64_t
+ inline uint64_t bit_path(value_type c)const {
+ return m_path[c];
+ }
+
+ //! Return the start of the node in the WT's bit vector
+ inline uint64_t bv_pos(node_type v)const {
+ return m_nodes[v].bv_pos;
+ }
+
+ //! Returns for node v the rank of 1's up to bv_pos(v)
+ inline uint64_t bv_pos_rank(node_type v)const {
+ return m_nodes[v].bv_pos_rank;
+ }
+
+ //! Return if the node is a valid node
+ inline bool is_valid(node_type v)const {
+ return v != undef;
+ }
+
+ //! Return symbol c or the next larger symbol in the wt
+ inline std::pair<bool,value_type> symbol_gte(value_type c) const
+ {
+ for(uint32_t i=c;i<fixed_sigma;i++) {
+ if(m_c_to_leaf[i]!=undef) {
+ return {true,i};
+ }
+ }
+ return {false,0};
+ }
+
+ //! Return symbol c or the next smaller symbol in the wt
+ inline std::pair<bool,value_type> symbol_lte(value_type c) const
+ {
+ for(uint32_t i=c;i>0;i--) {
+ if(m_c_to_leaf[i]!=undef) {
+ return {true,i};
+ }
+ }
+ if(m_c_to_leaf[0]!=undef)
+ return {true,0};
+ return {false,0};
+ }
+};
+
+// Strategy class for tree representation of a WT
+template<bool t_dfs_shape=false>
+struct byte_tree {
+ template<class t_wt>
+ using type = _byte_tree<t_dfs_shape, t_wt>;
+};
+
+// Strategy class for tree representation of a WT
+template<bool t_dfs_shape, class t_wt>
+struct _int_tree {
+ using alphabet_category = int_alphabet_tag;
+ using value_type = uint64_t;
+ using node_type = uint64_t; // node is represented by index in m_nodes
+ using data_node = _node<_int_tree>;
+ enum :uint64_t {undef = 0xFFFFFFFFFFFFFFFFULL}; // max uint64_t value
+ enum :uint8_t {int_width = 0}; // width of the input integers is variable
+
+
+
+ std::vector<data_node> m_nodes; // nodes for the prefix code tree structure
+ std::vector<node_type> m_c_to_leaf; // map symbol c to a leaf in the tree structure
+ // if m_c_to_leaf[c] == undef the char does
+ // not exists in the text
+ std::vector<uint64_t> m_path; // path information for each char; the bits at position
+ // 0..55 hold path information; bits 56..63 the length
+ // of the path in binary representation
+
+ void copy(const _int_tree& bt) {
+ m_nodes = bt.m_nodes;
+ m_c_to_leaf = bt.m_c_to_leaf;
+ m_path = bt.m_path;
+ }
+
+ _int_tree() {}
+
+ _int_tree(const std::vector<pc_node>& temp_nodes, uint64_t& bv_size, const t_wt*) {
+ m_nodes.resize(temp_nodes.size());
+ m_nodes[0] = temp_nodes.back(); // insert root at index 0
+ bv_size = 0;
+ size_t node_cnt = 1;
+ node_type last_parent = undef;
+ std::deque<node_type> q;
+ q.push_back(0);
+ uint64_t max_c = 0;
+ while (!q.empty()) {
+ node_type idx;
+ if (!t_dfs_shape) {
+ idx = q.front(); q.pop_front();
+ } else {
+ idx = q.back(); q.pop_back();
+ }
+ // frq_sum is store in bv_pos value
+ uint64_t frq = m_nodes[idx].bv_pos;
+ m_nodes[idx].bv_pos = bv_size;
+ if (m_nodes[idx].child[0] != undef) { // if node is not a leaf
+ bv_size += frq; // add frequency
+ } else if (max_c < m_nodes[idx].bv_pos_rank) { // node is leaf and contains large symbol
+ max_c = m_nodes[idx].bv_pos_rank;
+ }
+ if (idx > 0) { // node is not the root
+ if (last_parent != m_nodes[idx].parent)
+ m_nodes[m_nodes[idx].parent].child[0] = idx;
+ else
+ m_nodes[m_nodes[idx].parent].child[1] = idx;
+ last_parent = m_nodes[idx].parent;
+ }
+ if (m_nodes[idx].child[0] != undef) { // if node is not a leaf
+ for (uint32_t k=0; k<2; ++k) { // add children to tree
+ m_nodes[node_cnt] = temp_nodes[ m_nodes[idx].child[k] ];
+ m_nodes[node_cnt].parent = idx;
+ q.push_back(node_cnt);
+ m_nodes[idx].child[k] = node_cnt++;
+ }
+ }
+ }
+ // initialize m_c_to_leaf
+ // if c is not in the alphabet m_c_to_leaf[c] = undef
+ m_c_to_leaf.resize(max_c+1, undef);
+ for (node_type v=0; v < m_nodes.size(); ++v) {
+ if (m_nodes[v].child[0] == undef) { // if node is a leaf
+ uint64_t c = m_nodes[v].bv_pos_rank;
+ m_c_to_leaf[c] = v; // calculate value
+ if (c > max_c) max_c = c;
+ }
+ }
+ m_path = std::vector<uint64_t>(m_c_to_leaf.size(), 0);
+ // initialize path information
+ // Note: In the case of a bfs search order,
+ // we can classify nodes as right child and left child with an easy criterion:
+ // node is a left child, if node%2==1
+ // node is a right child, if node%2==0
+ for (value_type c=0, prev_c=0; c < m_c_to_leaf.size(); ++c) {
+ if (m_c_to_leaf[c] != undef) { // if char exists in the alphabet
+ node_type v = m_c_to_leaf[c];
+ uint64_t w = 0; // path
+ uint64_t l = 0; // path len
+ while (v != root()) { // while node is not the root
+ w <<= 1;
+ if (m_nodes[m_nodes[v].parent].child[1] == v) // if the node is a right child
+ w |= 1ULL;
+ ++l;
+ v = m_nodes[v].parent; // go up the tree
+ }
+ if (l > 56) {
+ throw std::logic_error("Code depth greater than 56!!!");
+ }
+ m_path[c] = w | (l << 56);
+ prev_c = c;
+ } else {
+ uint64_t pl = 0; // len is 0, good for special case in rank
+ m_path[c] = prev_c | (pl << 56);
+ }
+ }
+ }
+
+ template<class t_rank_type>
+ void init_node_ranks(const t_rank_type& rank) {
+ for (uint64_t i=0; i<m_nodes.size(); ++i) {
+ if (m_nodes[i].child[0] != undef) // if node is not a leaf
+ m_nodes[i].bv_pos_rank = rank.rank(m_nodes[i].bv_pos);
+ }
+ }
+
+ _int_tree(const _int_tree& bt) {
+ copy(bt);
+ }
+
+ void swap(_int_tree& bt) {
+ std::swap(m_nodes, bt.m_nodes);
+ std::swap(m_c_to_leaf, bt.m_c_to_leaf);
+ std::swap(m_path, bt.m_path);
+ }
+
+ _int_tree& operator=(const _int_tree& bt) {
+ if (this != &bt) {
+ copy(bt);
+ }
+ return *this;
+ }
+
+ //! Serializes the data structure into the given ostream
+ uint64_t serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="") const {
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ uint64_t written_bytes = 0;
+ uint64_t m_nodes_size = m_nodes.size();
+ written_bytes += write_member(m_nodes_size, out, child, "m_nodes.size()");
+ written_bytes += serialize_vector(m_nodes, out, child, "m_nodes");
+ uint64_t m_c_to_leaf_size = m_c_to_leaf.size();
+ written_bytes += write_member(m_c_to_leaf_size, out, child, "m_c_to_leaf.size()");
+ written_bytes += serialize_vector(m_c_to_leaf, out, child, "m_c_to_leaf");
+ uint64_t m_path_size = m_path.size();
+ written_bytes += write_member(m_path_size, out, child, "m_path.size()");
+ written_bytes += serialize_vector(m_path, out, child, "m_path");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ uint64_t m_nodes_size = 0;
+ read_member(m_nodes_size, in);
+ m_nodes = std::vector<data_node>(m_nodes_size);
+ load_vector(m_nodes, in);
+ uint64_t m_c_to_leaf_size = 0;
+ read_member(m_c_to_leaf_size, in);
+ m_c_to_leaf = std::vector<node_type>(m_c_to_leaf_size);
+ load_vector(m_c_to_leaf, in);
+ uint64_t m_path_size = 0;
+ read_member(m_path_size, in);
+ m_path = std::vector<uint64_t>(m_path_size);
+ load_vector(m_path, in);
+ }
+
+ //! Get corresponding leaf for symbol c.
+ inline node_type c_to_leaf(value_type c)const {
+ if (c >= m_c_to_leaf.size())
+ return undef;
+ else
+ return m_c_to_leaf[c];
+ }
+ //! Return the root node of the tree.
+ inline static node_type root() {
+ return 0;
+ }
+
+ //! Return the number of nodes in the tree.
+ uint64_t size() const {
+ return m_nodes.size();
+ }
+
+ //! Return the parent node of v.
+ inline node_type parent(node_type v)const {
+ return m_nodes[v].parent;
+ }
+ //! Return left (i=0) or right (i=1) child node of v.
+ inline node_type child(node_type v, uint8_t i)const {
+ return m_nodes[v].child[i];
+ }
+
+ //! Return if v is a leaf node.
+ inline bool is_leaf(node_type v)const {
+ return m_nodes[v].child[0] == undef;
+ }
+
+ //! Return the path as left/right bit sequence in a uint64_t
+ inline uint64_t bit_path(value_type c)const {
+ if (c >= m_path.size()) {
+ return m_path.size()-1;
+ }
+ return m_path[c];
+ }
+
+ //! Return the start of the node in the WT's bit vector
+ inline uint64_t bv_pos(node_type v)const {
+ return m_nodes[v].bv_pos;
+ }
+
+ //! Returns for node v the rank of 1's up to bv_pos(v)
+ inline uint64_t bv_pos_rank(node_type v)const {
+ return m_nodes[v].bv_pos_rank;
+ }
+
+ //! Return if the node is a valid node
+ inline bool is_valid(node_type v)const {
+ return v != undef;
+ }
+
+ //! Return symbol c or the next larger symbol in the wt
+ inline std::pair<bool,value_type> symbol_gte(value_type c) const
+ {
+ if(c >= m_c_to_leaf.size()) {
+ return {false,0};
+ }
+ for(value_type i=c;i<m_c_to_leaf.size();i++) {
+ if(m_c_to_leaf[i]!=undef) {
+ return {true,i};
+ }
+ }
+ return {false,0};
+ }
+
+ //! Return symbol c or the next smaller symbol in the wt
+ inline std::pair<bool,value_type> symbol_lte(value_type c) const
+ {
+ if(c >= m_c_to_leaf.size()) {
+ // return the largest symbol
+ c = m_c_to_leaf.size()-1;
+ }
+ for(value_type i=c;i>0;i--) {
+ if(m_c_to_leaf[i]!=undef) {
+ return {true,i};
+ }
+ }
+ if(m_c_to_leaf[0]!=undef)
+ return {true,0};
+ return {false,0};
+ }
+
+};
+
+// Strategy class for tree representation of a WT
+template<bool t_dfs_shape=false>
+struct int_tree {
+ template<class t_wt>
+ using type = _int_tree<t_dfs_shape, t_wt>;
+};
+
+} // end namespace sdsl
+#endif
diff --git a/include/sdsl/wt_huff.hpp b/include/sdsl/wt_huff.hpp
new file mode 100644
index 0000000..f247470
--- /dev/null
+++ b/include/sdsl/wt_huff.hpp
@@ -0,0 +1,127 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_huff.hpp
+ \brief wt_huff.hpp contains a class for a Huffman shaped wavelet tree
+ over byte sequences.
+ \author Simon Gog and Timo Beller
+*/
+#ifndef INCLUDED_SDSL_WT_HUFF
+#define INCLUDED_SDSL_WT_HUFF
+
+#include "wt_pc.hpp"
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+// forward declaration
+struct huff_shape;
+
+//! A Huffman-shaped wavelet tree.
+/*!
+ * A wavelet tree is build for a vector of characters over the byte alphabet
+ * \f$\Sigma\f$. If you need a wavelet tree for a integer alphabet you should
+ * use `wt_int`.
+ * The wavelet tree \f$wt\f$ consists of a tree of bitvectors and provides
+ * three efficient methods:
+ * - The "[]"-operator: \f$wt[i]\f$ returns the i-th symbol of vector for
+ * which the wavelet tree was build for.
+ * - The rank method: \f$wt.rank(i,c)\f$ returns the number of occurrences
+ * of symbol \f$c\f$ in the prefix [0..i-1] in the vector for which the
+ * wavelet tree was build for.
+ * - The select method: \f$wt.select(j,c)\f$ returns the index
+ * \f$i\in [0..size()-1]\f$ of the j-th occurrence of symbol \f$c\f$.
+ *
+ * The idea of using a Huffman shaped wavelet was first mentioned on page 17
+ * of the following technical report:
+ * Veli Mäkinen and Gonzalo Navarro:
+ * ,,Succinct Suffix Arrays based on Run-Length Encoding.''
+ * Available under: http://swp.dcc.uchile.cl/TR/2005/TR_DCC-2005-004.pdf
+ *
+ * \tparam t_bitvector Underlying bitvector structure.
+ * \tparam t_rank Rank support for pattern `1` on the bitvector.
+ * \tparam t_select Select support for pattern `1` on the bitvector.
+ * \tparam t_select_zero Select support for pattern `0` on the bitvector.
+ * \tparam t_dfs_shape Layout of the tree structure in memory. Set 0
+ * for BFS layout and 1 fro DFS layout.
+ *
+ * \par Space complexity
+ * \f$n H_0 + 2|\Sigma|\log n\f$ bits, where \f$n\f$ is the size
+ * of the vector the wavelet tree was build for.
+ *
+ * @ingroup wt
+ */
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type,
+ class t_tree_strat = byte_tree<> >
+using wt_huff = wt_pc<huff_shape,
+ t_bitvector,
+ t_rank,
+ t_select,
+ t_select_zero,
+ t_tree_strat>;
+
+// Huffman shape for wt_pc
+template<class t_wt>
+struct _huff_shape {
+ typedef typename t_wt::size_type size_type;
+ typedef std::pair<size_type, size_type> tPII; // (freq, nodenr)-pair
+ typedef std::priority_queue
+ <tPII, std::vector<tPII>,
+ std::greater<tPII>> tMPQPII; // min priority queue
+ enum { lex_ordered = 0 };
+
+ template<class t_rac>
+ static void
+ construct_tree(t_rac& C, std::vector<pc_node>& temp_nodes) {
+ tMPQPII pq;
+ size_type i = 0;
+ // add leaves of Huffman tree
+ std::for_each(std::begin(C), std::end(C), [&](decltype(*std::begin(C)) &freq) {
+ if (freq > 0) {
+ pq.push(tPII(freq, temp_nodes.size()));// push (frequency, node pointer)
+ // initial bv_pos with number of occurrences and bv_pos_rank
+ // value with the code of the corresponding char, parent,
+ // child[0], and child[1] are set to undef
+ temp_nodes.emplace_back(pc_node(freq, i));
+ }
+ ++i;
+ });
+ while (pq.size() > 1) {
+ tPII v1, v2;
+ v1 = pq.top(); pq.pop();
+ v2 = pq.top(); pq.pop();
+ temp_nodes[v1.second].parent = temp_nodes.size(); // parent is new node
+ temp_nodes[v2.second].parent = temp_nodes.size(); // parent is new node
+ size_type frq_sum = v1.first + v2.first;
+ pq.push(tPII(frq_sum, temp_nodes.size()));
+ temp_nodes.emplace_back(pc_node(frq_sum, 0, pc_node::undef,
+ v1.second, v2.second));
+ }
+ }
+};
+
+struct huff_shape {
+ template<class t_wt>
+ using type = _huff_shape<t_wt>;
+};
+
+
+}// end namespace sdsl
+#endif
diff --git a/include/sdsl/wt_hutu.hpp b/include/sdsl/wt_hutu.hpp
new file mode 100644
index 0000000..51929af
--- /dev/null
+++ b/include/sdsl/wt_hutu.hpp
@@ -0,0 +1,607 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2013 Simon Gog, Timo Beller and Markus Brenner
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_hutu.hpp
+ \brief wt_hutu.hpp contains a class for a Hu-Tucker shaped wavelet tree
+ over byte sequences.
+ \author Simon Gog, Markus Brenner
+*/
+#ifndef INCLUDED_SDSL_WT_HUTU
+#define INCLUDED_SDSL_WT_HUTU
+
+#include "wt_pc.hpp"
+#include <vector>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+// forward declaration
+struct hutu_shape;
+
+//! A Hu-Tucker-shaped wavelet tree.
+/*!
+ * \tparam t_bitvector Underlying bitvector structure.
+ * \tparam t_rank Rank support for pattern `1` on the bitvector.
+ * \tparam t_select Select support for pattern `1` on the bitvector.
+ * \tparam t_select_zero Select support for pattern `0` on the bitvector.
+ * \tparam t_dfs_shape Layout of the tree structure in memory. Set 0
+ * for BFS layout and 1 fro DFS layout.
+ * \par Space complexity
+ * Almost \f$n H_0 + 2|\Sigma|\log n\f$ bits, where \f$n\f$ is the size of
+ * the vector the wavelet tree was build for.
+ *
+ * @ingroup wt
+ */
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type,
+ class t_tree_strat = byte_tree<> >
+using wt_hutu = wt_pc<hutu_shape,
+ t_bitvector,
+ t_rank,
+ t_select,
+ t_select_zero,
+ t_tree_strat>;
+
+// Hu Tucker shape for wt_pc
+template<class t_wt>
+struct _hutu_shape {
+ typedef typename t_wt::size_type size_type;
+ enum { lex_ordered = 1 };
+
+ //! Node class used by the leftist heap
+ template <class t_element>
+ struct heap_node {
+ t_element* item; // pointer to the represented item
+ heap_node* left, *right, *parent; // pointer to left/right child, parent
+ int64_t rank; // rank of the heap node
+ //! Constructor
+ heap_node(t_element* it=nullptr) : item(it), left(nullptr),
+ right(nullptr), parent(nullptr),
+ rank(0) { }
+ //! Less then operator
+ bool operator< (const heap_node& other) {
+ return *item < *(other.item);
+ }
+ };
+
+ // Implementation of a leftist heap as needed in the first phase of
+ // Hu-Tucker Code construction
+ template <class t_element>
+ class l_heap
+ {
+ private:
+ heap_node<t_element>* m_root; // pointer to the root
+
+ // fixes node information after the deletion of elements
+ void fix_node(heap_node<t_element>* item) {
+ if (item != nullptr) {
+ if (!item->left || !item->right) { // if node has only one child
+ // only go on fixing if the node information needs to be changed
+ if (item->rank != 0) {
+ item->rank = 0;
+ if (item->parent) fix_node(item->parent);
+ }
+ } else { // node information has to be adapted
+ int64_t nn = (item->left->rank > item->right->rank) ? item->right->rank : item->left->rank;
+ if (item->rank != nn && item->parent != 0) {
+ item->rank = nn;
+ fix_node(item->parent);
+ }
+ }
+ }
+ }
+
+ // helper function to remove the data structure from memory
+ void free_node(heap_node<t_element>* item) {
+ if (item->left) {
+ free_node(item->left);
+ delete item->left;
+ item->left = nullptr;
+ }
+ if (item->right) {
+ free_node(item->right);
+ delete item->right;
+ item->right = nullptr;
+ }
+ }
+
+ // internal merge function
+ heap_node<t_element>* merge(heap_node<t_element>* h1, heap_node<t_element>* h2) {
+ if (!h1) return h2;
+ if (!h2) return h1;
+ if (*(h1->item) < *(h2->item)) return merge1(h1, h2);
+ else return merge1(h2, h1);
+ }
+ // internal merge function
+ heap_node<t_element>* merge1(heap_node<t_element>* h1, heap_node<t_element>* h2) {
+ if (!h1->left) { // if h1 has no children, the merge is simple
+ h1->left = h2;
+ h2->parent = h1; // adjust the parent pointer
+ } else {
+ h1->right = merge(h1->right, h2);
+ if (h1->right) h1->right->parent = h1;
+
+ if (h1->left->rank < h1->right->rank) {
+ heap_node<t_element>* tmp = h1->left;
+ h1->left = h1->right;
+ h1->right = tmp;
+ }
+ h1 -> rank = h1 -> right -> rank + 1;
+ }
+ return h1;
+ }
+
+ public:
+
+ //! Default constructor
+ l_heap() : m_root(nullptr) { }
+
+ //! Indicates if the heap is empty
+ bool empty() const {
+ return (m_root==nullptr);
+ }
+
+ //! Get the smallest element
+ /*! \return The smallest element in the heap
+ * or nullptr if it does not exist.
+ */
+ heap_node<t_element>* find_min() const {
+ return m_root;
+ }
+
+ //! Get the second smallest element
+ /*! \return The second smallest element in the heap
+ * or nullptr if it does not exist.
+ */
+ heap_node<t_element>* find_snd_min() const {
+ if (m_root == nullptr) return nullptr;
+ if (m_root->left == nullptr) return m_root->right;
+ if (m_root->right == nullptr) return m_root->left;
+
+ if (m_root->left->operator< (*m_root->right)) return m_root->left;
+ else return m_root->right;
+ }
+
+ //! Insert an element into the heap
+ /*! \param x Element that is inserted into the heap.
+ * \return The new generated heap node.
+ */
+ heap_node<t_element>* insert(t_element* x) {
+ heap_node<t_element>* n = new heap_node<t_element>(x);
+ l_heap<t_element> lh;
+ lh.m_root = n;
+ merge(&lh);
+ return n;
+ }
+
+ //! Delete the smallest element in the heap
+ void delete_min() {
+ heap_node<t_element>* old_root = m_root;
+ m_root = merge(m_root->left, m_root->right);
+ if (m_root) m_root->parent = nullptr;
+ delete old_root;
+ }
+
+ // deletes an arbitrary element from the heap
+ // this function assumes, that item is an element of the heap
+ void delete_element(heap_node<t_element>* item) {
+ if (item != nullptr) {
+ if (m_root == item) { // deleting the root is trivial
+ delete_min();
+ } else {
+ // otherwise we have to adapt the parent node and
+ // the children of item
+ heap_node<t_element>* h1 = merge(item->left,item->right);
+ if (h1) h1->parent = item->parent;
+ if (item == item->parent->left) {
+ item->parent->left = h1;
+ } else if (item == item->parent->right) {
+ item->parent->right = h1;
+ }
+ // fix node information considering rank
+ fix_node(item->parent);
+ delete item; // remove the item from memory
+ }
+ }
+ }
+
+ // public merge function
+ void merge(l_heap<t_element>* rhs) {
+ m_root = merge(m_root, rhs->m_root);
+ rhs->m_root = nullptr;
+ }
+
+ // removes the whole data structure from memory
+ void free_memory() {
+ if (m_root != nullptr) {
+ free_node(m_root);
+ delete m_root;
+ m_root = nullptr;
+ }
+ }
+ };
+
+
+ // forward declaration of node classes
+ struct ht_node;
+
+ // Master node as used in the first phase of the Hu-Tucker algorithm
+ struct m_node {
+ // min sum of the two min elements of the hpq this node points to
+ size_type min_sum;
+ int64_t i; // position of the left node in the working sequence
+ int64_t j; // position of the right node in the working sequence
+ // pointer to the corresponding heap element (used for deletion)
+ heap_node<m_node>* qel;
+ l_heap<ht_node>* myhpq; // pointer to the hpq
+
+ ht_node* lt; // pointer to the left- and rightmost leafs of the hpq
+ ht_node* rt; // need for merge operations
+
+ m_node() : qel(0), myhpq(0), lt(0), rt(0) { }
+
+ bool operator<(const m_node other) {
+ if (min_sum != other.min_sum) {
+ return min_sum < other.min_sum;
+ }
+ if (i != other.i) {
+ return i < other.i;
+ }
+ return j < other.j;
+ }
+
+ bool operator> (const m_node other) {
+ return other < *this;
+ }
+ };
+
+ // Hu-Tucker node as used in the first phase of the Hu-Tucker algorithm
+ struct ht_node {
+ int64_t pos; // position of the node
+ uint64_t c; // the represented letter
+ size_type w; // frequency of the node
+ bool t; // whether the node is a leaf
+ int64_t level; // level in the tree
+
+ // pointer to the two master nodes
+ // (as a node can belong to up to two hpqs)
+ m_node* mpql;
+ m_node* mpqr; // only mpql is used for inner nodes
+ // pointer to the two heap nodes (as a node can belong to up to two hpqs)
+ heap_node<ht_node>* ql;
+ heap_node<ht_node>* qr; // only ql is used for inner nodes
+ ht_node* left; // left child
+ ht_node* right; // right child
+
+ ht_node() : mpql(0), mpqr(0), ql(0), qr(0),
+ left(nullptr), right(nullptr) { }
+
+ bool operator< (const ht_node& other) {
+ if (w != other.w) {
+ return w < other.w;
+ }
+ return pos < other.pos;
+ }
+
+ bool operator> (const ht_node& other) {
+ return other < *this;
+ }
+ };
+
+
+ template<class t_rac>
+ static void
+ construct_tree(t_rac& C, std::vector<pc_node>& temp_nodes) {
+ //create a leaf for every letter
+ std::vector<ht_node> node_vector;
+ for (size_t i = 0; i < C.size(); i++) {
+ if (C[i]) {
+ ht_node n;
+ n.c = (uint64_t)i;
+ n.w = C[i];
+ n.t = true;
+ n.pos = node_vector.size();
+ node_vector.push_back(n);
+ }
+ }
+ if (node_vector.size() == 1) {
+ // special case of an alphabet of size 1:
+ // just instantly create the tree and return it
+ temp_nodes.emplace_back(pc_node(node_vector[0].w,
+ (size_type)node_vector[0].c));
+ return;
+ }
+ size_type sigma = node_vector.size();
+ std::vector<ht_node> T(sigma); // physical leaves
+ std::vector<ht_node*> A(sigma); // the current working sequence
+ // Priority Queues, containing the Huffman Sequences
+ std::vector<l_heap<ht_node>> HPQ(sigma);
+ l_heap<m_node> MPQ; // Master Priority Queue
+
+ // init T, A, HPQs and MPQ
+ T[0] = node_vector[0];
+ A[0] = &T[0];
+
+ // initialization needed for every leaf
+ for (size_type i = 1; i < sigma; i++) {
+ T[i] = node_vector[i];
+ A[i] = &T[i];
+
+ T[i - 1].qr = HPQ[i - 1].insert(&T[i - 1]);
+ T[i].ql = HPQ[i - 1].insert(&T[i]);
+
+ m_node* m = new m_node();
+ m->min_sum = T[i - 1].w + T[i].w;
+ m->i = i - 1;
+ m->j = i;
+ m->lt = &T[i-1];
+ m->rt = &T[i];
+ m->myhpq = &HPQ[i - 1];
+
+ m->qel = MPQ.insert(m);
+
+ T[i-1].mpqr = m;
+ T[i].mpql = m;
+ }
+
+ // main action loop
+ for (size_type k = 1; k < sigma; k++) {
+ m_node* m = MPQ.find_min()->item;
+ ht_node* l = A[m->i];
+ ht_node* r = A[m->j];
+ int64_t lpos = m->i;
+ int64_t rpos = m->j;
+
+ l_heap<ht_node>* n_hpq = nullptr;
+ ht_node* n_rt = nullptr;
+ ht_node* n_lt = nullptr;
+
+ // create a new master priority queue
+ m_node* n_m = new m_node();
+ // delete old nodes from all hpqs
+ if (l->t) {
+ if (l->mpql) l->mpql->myhpq->delete_element(l->ql);
+ l->ql = nullptr;
+ if (l->mpqr) l->mpqr->myhpq->delete_element(l->qr);
+ l->qr = nullptr;
+ } else {
+ m->myhpq->delete_element(l->ql);
+ l->ql = nullptr;
+ }
+ if (r->t) {
+ if (r->mpql) r->mpql->myhpq->delete_element(r->ql);
+ l->ql = nullptr;
+
+ if (r->mpqr) r->mpqr->myhpq->delete_element(r->qr);
+ r->qr = nullptr;
+ } else {
+ m->myhpq->delete_element(r->ql);
+ r->ql = nullptr;
+ }
+ // handle the merge of hpqs
+ if (l->t && r ->t) {
+ // both nodes are leaves
+ l_heap<ht_node>* h1 = nullptr;
+ l_heap<ht_node>* h2 = nullptr;
+ l_heap<ht_node>* h3 = nullptr;
+ if (l -> mpql) {
+ n_lt = l->mpql->lt;
+ if (n_lt == l) n_lt = nullptr;
+ if (n_lt) n_lt -> mpqr = n_m;
+
+ h1 = l->mpql->myhpq;
+ h2 = l->mpqr->myhpq;
+
+ h1 -> merge(h2);
+ MPQ.delete_element(l->mpql->qel);
+ MPQ.delete_element(l->mpqr->qel);
+ delete l->mpql;
+ delete l->mpqr;
+
+ } else {
+ h1 = l->mpqr->myhpq;
+ h2 = l->mpqr->myhpq;
+ n_lt = nullptr;
+
+ MPQ.delete_element(l->mpqr->qel);
+ delete l->mpqr;
+ }
+ if (r->mpqr) {
+ n_rt = r->mpqr->rt;
+ if (n_rt == r) n_rt = nullptr;
+ if (n_rt) n_rt -> mpql = n_m;
+
+ h3 = r->mpqr->myhpq;
+ h1->merge(h3);
+ MPQ.delete_element(r->mpqr->qel);
+ delete r->mpqr;
+
+ n_hpq = h1;
+ if (n_rt) n_rt -> mpql = n_m;
+ } else {
+ n_rt = nullptr;
+ n_hpq = h1;
+ }
+ } else if (l->t) { // the left node is a leaf
+ if (l->mpql) {
+ n_lt = l->mpql->lt;
+ if (n_lt) n_lt->mpqr = n_m;
+ n_rt = l->mpqr->rt;
+ if (n_rt) n_rt ->mpql = n_m;
+
+ l -> mpql ->myhpq -> merge(l->mpqr->myhpq);
+ n_hpq=l->mpql->myhpq;
+ MPQ.delete_element(l->mpql->qel);
+ MPQ.delete_element(l->mpqr->qel);
+ delete l->mpql;
+ delete l->mpqr;
+ } else {
+ n_lt = nullptr;
+ n_rt = l->mpqr->rt;
+ if (n_rt) n_rt->mpql = n_m;
+
+ n_hpq = l->mpqr->myhpq;
+ MPQ.delete_element(l->mpqr->qel);
+ delete l->mpqr;
+ }
+ } else if (r->t) { // right node is a leaf
+ if (r->mpqr) {
+ n_lt = r->mpql->lt;
+ if (n_lt) n_lt->mpqr = n_m;
+ n_rt = r->mpqr->rt;
+ if (n_rt) n_rt->mpql = n_m;
+
+ r -> mpql ->myhpq -> merge(r->mpqr->myhpq);
+ n_hpq=r->mpql->myhpq;
+ MPQ.delete_element(r->mpql->qel);
+ MPQ.delete_element(r->mpqr->qel);
+ delete r->mpql;
+ delete r->mpqr;
+ } else {
+ n_lt = r->mpql->lt;
+ if (n_lt) n_lt->mpqr = n_m;
+ n_rt = nullptr;
+
+ n_hpq = r->mpql->myhpq;
+ MPQ.delete_element(r->mpql->qel);
+ delete r->mpql;
+ }
+ } else {
+ // merge of two inner nodes
+ // no need to merge hpqs
+ MPQ.delete_element(m->qel);
+
+ n_hpq = m->myhpq;
+ n_lt = m->lt;
+ n_rt = m->rt;
+
+ if (n_lt) n_lt->mpqr = n_m;
+ if (n_rt) n_rt->mpql = n_m;
+
+ delete m;
+ }
+
+ // create a new node with the information gained above
+ ht_node* new_node = new ht_node();
+ new_node -> c = ' ';
+ new_node -> w = l->w + r->w;
+ new_node -> t = false;
+ new_node -> pos = lpos;
+ new_node -> left = l;
+ new_node -> right = r;
+ // insert node to the correct hpq
+ new_node -> ql = n_hpq->insert(new_node);
+
+ // update working sequence
+ A[lpos] = new_node;
+ A[rpos] = nullptr;
+ // update information in the new master node and reinsert it to mpq
+ ht_node* tmp_min = n_hpq->find_min()->item;
+ heap_node<ht_node>* tmpsnd = n_hpq->find_snd_min();
+ if (tmpsnd) {
+ ht_node* tmp_snd = n_hpq->find_snd_min()->item;
+ n_m->min_sum = tmp_min->w + tmp_snd->w;
+
+ if (tmp_min -> pos < tmp_snd->pos) {
+ n_m->i = tmp_min -> pos;
+ n_m->j = tmp_snd -> pos;
+ } else {
+ n_m->i = tmp_snd -> pos;
+ n_m->j = tmp_min -> pos;
+ }
+ n_m->qel = MPQ.insert(n_m);
+ n_m->myhpq = n_hpq;
+ n_m->lt = n_lt;
+ n_m->rt = n_rt;
+ } else {
+ // free the last remaining hpq
+ n_hpq->free_memory();
+ delete n_m;
+ }
+ }
+
+ // level assignment and deletion of unneeded nodes
+ assign_level(A[0], 0);
+
+ // reconstruction phase using the stack algorithm
+ ht_node* stack[sigma];
+
+ for (size_type i = 0; i < sigma; i++) {
+ stack[i] = nullptr;
+ temp_nodes.emplace_back(pc_node(T[i].w, (size_type)T[i].c));
+ T[i].pos = i;
+ }
+
+ int64_t spointer = -1;
+ uint64_t qpointer = 0; // use the Array T as a stack
+ int64_t max_nodes = sigma;
+ while (qpointer < sigma or spointer >= 1LL) {
+ if (spointer >= 1LL and
+ (stack[spointer]->level == stack[spointer-1]->level)) {
+ ht_node* n_node = new ht_node();
+ max_nodes++;
+ n_node->t = false;
+ n_node->left = stack[spointer-1];
+ n_node->right = stack[spointer];
+ n_node->level = stack[spointer]->level-1;
+ n_node->w = stack[spointer]->w + stack[spointer-1]->w;
+ n_node->c = '|';
+
+ n_node->pos = temp_nodes.size();
+ temp_nodes[stack[spointer-1]->pos].parent = temp_nodes.size();
+ temp_nodes[stack[spointer]->pos].parent = temp_nodes.size();
+ temp_nodes.emplace_back(pc_node(n_node->w, 0,
+ pc_node::undef,
+ stack[spointer-1]->pos,
+ stack[spointer]->pos));
+
+ if (!stack[spointer-1]->t) delete stack[spointer-1];
+ if (!stack[spointer]->t) delete stack[spointer];
+
+ stack[--spointer] = n_node;
+ } else {
+ stack[++spointer] = &T[qpointer++];
+ }
+ }
+ delete stack[0];
+ }
+
+ static void assign_level(ht_node* n, int64_t lvl) {
+ if (n) {
+ n->level = lvl;
+ assign_level(n->left, lvl + 1);
+ assign_level(n->right, lvl + 1);
+
+ if (!n->t) {
+ delete n;
+ }
+ }
+ }
+};
+
+struct hutu_shape {
+ template<class t_wt>
+ using type = _hutu_shape<t_wt>;
+};
+
+
+
+}// end namespace sdsl
+
+#endif // end file
diff --git a/include/sdsl/wt_int.hpp b/include/sdsl/wt_int.hpp
new file mode 100644
index 0000000..1d7b4ca
--- /dev/null
+++ b/include/sdsl/wt_int.hpp
@@ -0,0 +1,906 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_int.hpp
+ \brief wt_int.hpp contains a specialized class for a wavelet tree of a
+ sequence of the numbers. This wavelet tree class takes
+ less memory than the wt_pc class for large alphabets.
+ \author Simon Gog, Shanika Kuruppu
+*/
+#ifndef INCLUDED_SDSL_INT_WAVELET_TREE
+#define INCLUDED_SDSL_INT_WAVELET_TREE
+
+#include "sdsl_concepts.hpp"
+#include "int_vector.hpp"
+#include "rank_support_v.hpp"
+#include "select_support_mcl.hpp"
+#include "wt_helper.hpp"
+#include "util.hpp"
+#include <set> // for calculating the alphabet size
+#include <map> // for mapping a symbol to its lexicographical index
+#include <algorithm> // for std::swap
+#include <stdexcept>
+#include <vector>
+#include <queue>
+#include <utility>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A wavelet tree class for integer sequences.
+/*!
+ * \par Space complexity
+ * \f$\Order{n\log|\Sigma|}\f$ bits, where \f$n\f$ is the size of the vector the wavelet tree was build for.
+ *
+ * \tparam t_bitvector Type of the bitvector used for representing the wavelet tree.
+ * \tparam t_rank Type of the support structure for rank on pattern `1`.
+ * \tparam t_select Type of the support structure for select on pattern `1`.
+ * \tparam t_select_zero Type of the support structure for select on pattern `0`.
+ *
+ * @ingroup wt
+ */
+template<class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type>
+class wt_int
+{
+ public:
+
+ typedef int_vector<>::size_type size_type;
+ typedef int_vector<>::value_type value_type;
+ typedef typename t_bitvector::difference_type difference_type;
+ typedef random_access_const_iterator<wt_int> const_iterator;
+ typedef const_iterator iterator;
+ typedef t_bitvector bit_vector_type;
+ typedef t_rank rank_1_type;
+ typedef t_select select_1_type;
+ typedef t_select_zero select_0_type;
+ typedef wt_tag index_category;
+ typedef int_alphabet_tag alphabet_category;
+ enum {lex_ordered=1};
+
+ typedef std::pair<value_type, size_type> point_type;
+ typedef std::vector<point_type> point_vec_type;
+ typedef std::pair<size_type, point_vec_type> r2d_res_type;
+
+
+ protected:
+
+ size_type m_size = 0;
+ size_type m_sigma = 0; //<- \f$ |\Sigma| \f$
+ bit_vector_type m_tree; // bit vector to store the wavelet tree
+ rank_1_type m_tree_rank; // rank support for the wavelet tree bit vector
+ select_1_type m_tree_select1; // select support for the wavelet tree bit vector
+ select_0_type m_tree_select0;
+ uint32_t m_max_level = 0;
+ mutable int_vector<64> m_path_off; // array keeps track of path offset in select-like methods
+ mutable int_vector<64> m_path_rank_off;// array keeps track of rank values for the offsets
+
+ void copy(const wt_int& wt) {
+ m_size = wt.m_size;
+ m_sigma = wt.m_sigma;
+ m_tree = wt.m_tree;
+ m_tree_rank = wt.m_tree_rank;
+ m_tree_rank.set_vector(&m_tree);
+ m_tree_select1 = wt.m_tree_select1;
+ m_tree_select1.set_vector(&m_tree);
+ m_tree_select0 = wt.m_tree_select0;
+ m_tree_select0.set_vector(&m_tree);
+ m_max_level = wt.m_max_level;
+ m_path_off = wt.m_path_off;
+ m_path_rank_off = wt.m_path_rank_off;
+ }
+
+ private:
+
+ void init_buffers(uint32_t max_level) {
+ m_path_off = int_vector<64>(max_level+1);
+ m_path_rank_off = int_vector<64>(max_level+1);
+ }
+
+ // recursive internal version of the method interval_symbols
+ void _interval_symbols(size_type i, size_type j, size_type& k,
+ std::vector<value_type>& cs,
+ std::vector<size_type>& rank_c_i,
+ std::vector<size_type>& rank_c_j,
+ size_type level,
+ size_type path,
+ size_type node_size,
+ size_type offset) const {
+ // invariant: j>i
+
+ if (level >= m_max_level) {
+ rank_c_i[k]= i;
+ rank_c_j[k]= j;
+ cs[k++]= path;
+ return;
+ }
+
+ size_type ones_before_o = m_tree_rank(offset);
+ size_type ones_before_i = m_tree_rank(offset+i) - ones_before_o;
+ size_type ones_before_j = m_tree_rank(offset+j) - ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset+ node_size) - ones_before_o;
+
+ // goto left child
+ if ((j-i)-(ones_before_j-ones_before_i)>0) {
+ size_type new_offset = offset + m_size;
+ size_type new_node_size = node_size - ones_before_end;
+ size_type new_i = i - ones_before_i;
+ size_type new_j = j - ones_before_j;
+ _interval_symbols(new_i, new_j, k, cs, rank_c_i, rank_c_j, level+1, path<<1, new_node_size, new_offset);
+ }
+
+ // goto right child
+ if ((ones_before_j-ones_before_i)>0) {
+ size_type new_offset = offset+(node_size - ones_before_end) + m_size;
+ size_type new_node_size = ones_before_end;
+ size_type new_i = ones_before_i;
+ size_type new_j = ones_before_j;
+ _interval_symbols(new_i, new_j, k, cs, rank_c_i, rank_c_j, level+1, (path<<1)|1, new_node_size, new_offset);
+ }
+ }
+
+ public:
+
+ const size_type& sigma = m_sigma; //!< Effective alphabet size of the wavelet tree.
+ const bit_vector_type& tree = m_tree; //!< A concatenation of all bit vectors of the wavelet tree.
+ const uint32_t& max_level = m_max_level; //!< Maximal level of the wavelet tree.
+
+ //! Default constructor
+ wt_int() {
+ init_buffers(m_max_level);
+ };
+
+ //! Semi-external constructor
+ /*! \param buf File buffer of the int_vector for which the wt_int should be build.
+ * \param size Size of the prefix of v, which should be indexed.
+ * \param max_level Maximal level of the wavelet tree. If set to 0, determined automatically.
+ * \par Time complexity
+ * \f$ \Order{n\log|\Sigma|}\f$, where \f$n=size\f$
+ * I.e. we need \Order{n\log n} if rac is a permutation of 0..n-1.
+ * \par Space complexity
+ * \f$ n\log|\Sigma| + O(1)\f$ bits, where \f$n=size\f$.
+ */
+ template<uint8_t int_width>
+ wt_int(int_vector_buffer<int_width>& buf, size_type size,
+ uint32_t max_level=0) : m_size(size) {
+ init_buffers(m_max_level);
+ if (0 == m_size)
+ return;
+ size_type n = buf.size(); // set n
+ if (n < m_size) {
+ throw std::logic_error("n="+util::to_string(n)+" < "+util::to_string(m_size)+"=m_size");
+ return;
+ }
+ m_sigma = 0;
+ int_vector<int_width> rac(m_size, 0, buf.width());
+
+ value_type x = 1; // variable for the biggest value in rac
+ for (size_type i=0; i < m_size; ++i) {
+ if (buf[i] > x)
+ x = buf[i];
+ rac[i] = buf[i];
+ }
+
+ if (max_level == 0) {
+ m_max_level = bits::hi(x)+1; // max_level bits to represent all values range [0..x]
+ } else {
+ m_max_level = max_level;
+ }
+ init_buffers(m_max_level);
+
+ // buffer for elements in the right node
+ int_vector_buffer<> buf1(tmp_file(buf.filename(), "_wt_constr_buf"),
+ std::ios::out, 10*(1<<20), buf.width());
+ std::string tree_out_buf_file_name = tmp_file(buf.filename(), "_m_tree");
+ osfstream tree_out_buf(tree_out_buf_file_name, std::ios::binary|
+ std::ios::trunc|std::ios::out);
+
+ size_type bit_size = m_size*m_max_level;
+ tree_out_buf.write((char*) &bit_size, sizeof(bit_size));// write size of bit_vector
+
+ size_type tree_pos = 0;
+ uint64_t tree_word = 0;
+
+ uint64_t mask_old = 1ULL<<(m_max_level);
+ for (uint32_t k=0; k<m_max_level; ++k) {
+ size_type start = 0;
+ const uint64_t mask_new = 1ULL<<(m_max_level-k-1);
+ do {
+ size_type i = start;
+ size_type cnt0 = 0;
+ size_type cnt1 = 0;
+ uint64_t start_value = (rac[i]&mask_old);
+ uint64_t x;
+ while (i < m_size and((x=rac[i])&mask_old)==start_value) {
+ if (x&mask_new) {
+ tree_word |= (1ULL << (tree_pos&0x3FULL));
+ buf1[cnt1++] = x;
+ } else {
+ rac[start + cnt0++ ] = x;
+ }
+ ++tree_pos;
+ if ((tree_pos & 0x3FULL) == 0) { // if tree_pos % 64 == 0 write old word
+ tree_out_buf.write((char*) &tree_word, sizeof(tree_word));
+ tree_word = 0;
+ }
+ ++i;
+ }
+ if (k+1 < m_max_level) { // inner node
+ for (size_type j=0; j<cnt1; ++j) {
+ rac[start+cnt0+j] = buf1[j];
+ }
+ } else { // leaf node
+ m_sigma += (cnt0>0) + (cnt1>0); // increase sigma for each leaf
+ }
+ start += cnt0+cnt1;
+ } while (start < m_size);
+ mask_old += mask_new;
+ }
+ if ((tree_pos & 0x3FULL) != 0) { // if tree_pos % 64 > 0 => there are remaining entries we have to write
+ tree_out_buf.write((char*) &tree_word, sizeof(tree_word));
+ }
+ buf1.close(true); // remove temporary file
+ tree_out_buf.close();
+ rac.resize(0);
+ bit_vector tree;
+ load_from_file(tree, tree_out_buf_file_name);
+ sdsl::remove(tree_out_buf_file_name);
+ m_tree = bit_vector_type(std::move(tree));
+ util::init_support(m_tree_rank, &m_tree);
+ util::init_support(m_tree_select0, &m_tree);
+ util::init_support(m_tree_select1, &m_tree);
+ }
+
+ //! Copy constructor
+ wt_int(const wt_int& wt) {
+ copy(wt);
+ }
+
+ //! Copy constructor
+ wt_int(wt_int&& wt) {
+ *this = std::move(wt);
+ }
+
+ //! Assignment operator
+ wt_int& operator=(const wt_int& wt) {
+ if (this != &wt) {
+ copy(wt);
+ }
+ return *this;
+ }
+
+ //! Assignment move operator
+ wt_int& operator=(wt_int&& wt) {
+ if (this != &wt) {
+ m_size = wt.m_size;
+ m_sigma = wt.m_sigma;
+ m_tree = std::move(wt.m_tree);
+ m_tree_rank = std::move(wt.m_tree_rank);
+ m_tree_rank.set_vector(&m_tree);
+ m_tree_select1 = std::move(wt.m_tree_select1);
+ m_tree_select1.set_vector(&m_tree);
+ m_tree_select0 = std::move(wt.m_tree_select0);
+ m_tree_select0.set_vector(&m_tree);
+ m_max_level = std::move(wt.m_max_level);
+ m_path_off = std::move(wt.m_path_off);
+ m_path_rank_off = std::move(wt.m_path_rank_off);
+ }
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(wt_int& wt) {
+ if (this != &wt) {
+ std::swap(m_size, wt.m_size);
+ std::swap(m_sigma, wt.m_sigma);
+ m_tree.swap(wt.m_tree);
+ util::swap_support(m_tree_rank, wt.m_tree_rank, &m_tree, &(wt.m_tree));
+ util::swap_support(m_tree_select1, wt.m_tree_select1, &m_tree, &(wt.m_tree));
+ util::swap_support(m_tree_select0, wt.m_tree_select0, &m_tree, &(wt.m_tree));
+ std::swap(m_max_level, wt.m_max_level);
+ m_path_off.swap(wt.m_path_off);
+ m_path_rank_off.swap(wt.m_path_rank_off);
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Returns whether the wavelet tree contains no data.
+ bool empty()const {
+ return m_size == 0;
+ }
+
+ //! Recovers the i-th symbol of the original vector.
+ /*! \param i The index of the symbol in the original vector.
+ * \returns The i-th symbol of the original vector.
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ size_type offset = 0;
+ value_type res = 0;
+ size_type node_size = m_size;
+ for (uint32_t k=0; k < m_max_level; ++k) {
+ res <<= 1;
+ size_type ones_before_o = m_tree_rank(offset);
+ size_type ones_before_i = m_tree_rank(offset + i) - ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset + node_size) - ones_before_o;
+ if (m_tree[offset+i]) { // one at position i => follow right child
+ offset += (node_size - ones_before_end);
+ node_size = ones_before_end;
+ i = ones_before_i;
+ res |= 1;
+ } else { // zero at position i => follow left child
+ node_size = (node_size - ones_before_end);
+ i = (i-ones_before_i);
+ }
+ offset += m_size;
+ }
+ return res;
+ };
+
+ //! Calculates how many symbols c are in the prefix [0..i-1] of the supported vector.
+ /*!
+ * \param i The exclusive index of the prefix range [0..i-1], so \f$i\in[0..size()]\f$.
+ * \param c The symbol to count the occurrences in the prefix.
+ * \returns The number of occurrences of symbol c in the prefix [0..i-1] of the supported vector.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ size_type rank(size_type i, value_type c)const {
+ assert(i <= size());
+ if (((1ULL)<<(m_max_level))<=c) { // c is greater than any symbol in wt
+ return 0;
+ }
+ size_type offset = 0;
+ uint64_t mask = (1ULL) << (m_max_level-1);
+ size_type node_size = m_size;
+ for (uint32_t k=0; k < m_max_level and i; ++k) {
+ size_type ones_before_o = m_tree_rank(offset);
+ size_type ones_before_i = m_tree_rank(offset + i) - ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset + node_size) - ones_before_o;
+ if (c & mask) { // search for a one at this level
+ offset += (node_size - ones_before_end);
+ node_size = ones_before_end;
+ i = ones_before_i;
+ } else { // search for a zero at this level
+ node_size = (node_size - ones_before_end);
+ i = (i-ones_before_i);
+ }
+ offset += m_size;
+ mask >>= 1;
+ }
+ return i;
+ };
+
+
+
+ //! Calculates how many occurrences of symbol wt[i] are in the prefix [0..i-1] of the original sequence.
+ /*!
+ * \param i The index of the symbol.
+ * \return Pair (rank(wt[i],i),wt[i])
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ std::pair<size_type, value_type>
+ inverse_select(size_type i)const {
+ assert(i < size());
+
+ value_type c = 0;
+ size_type node_size = m_size, offset = 0;
+ for (uint32_t k=0; k < m_max_level; ++k) {
+ size_type ones_before_o = m_tree_rank(offset);
+ size_type ones_before_i = m_tree_rank(offset + i) - ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset + node_size) - ones_before_o;
+ c<<=1;
+ if (m_tree[offset+i]) { // go to the right child
+ offset += (node_size - ones_before_end);
+ node_size = ones_before_end;
+ i = ones_before_i;
+ c|=1;
+ } else { // go to the left child
+ node_size = (node_size - ones_before_end);
+ i = (i-ones_before_i);
+ }
+ offset += m_size;
+ }
+ return std::make_pair(i,c);
+ }
+
+ //! Calculates the i-th occurrence of the symbol c in the supported vector.
+ /*!
+ * \param i The i-th occurrence.
+ * \param c The symbol c.
+ * \par Time complexity
+ * \f$ \Order{\log |\Sigma|} \f$
+ * \par Precondition
+ * \f$ 1 \leq i \leq rank(size(), c) \f$
+ */
+ size_type select(size_type i, value_type c)const {
+ assert(1 <= i and i <= rank(size(), c));
+ // possible optimization: if the array is a permutation we can start at the bottom of the tree
+ size_type offset = 0;
+ uint64_t mask = (1ULL) << (m_max_level-1);
+ size_type node_size = m_size;
+ m_path_off[0] = m_path_rank_off[0] = 0;
+
+ for (uint32_t k=0; k < m_max_level and node_size; ++k) {
+ size_type ones_before_o = m_tree_rank(offset);
+ m_path_rank_off[k] = ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset + node_size) - ones_before_o;
+ if (c & mask) { // search for a one at this level
+ offset += (node_size - ones_before_end);
+ node_size = ones_before_end;
+ } else { // search for a zero at this level
+ node_size = (node_size - ones_before_end);
+ }
+ offset += m_size;
+ m_path_off[k+1] = offset;
+ mask >>= 1;
+ }
+ if (0ULL == node_size or node_size < i) {
+ throw std::logic_error("select("+util::to_string(i)+","+util::to_string(c)+"): c does not occur i times in the WT");
+ return m_size;
+ }
+ mask = 1ULL;
+ for (uint32_t k=m_max_level; k>0; --k) {
+ offset = m_path_off[k-1];
+ size_type ones_before_o = m_path_rank_off[k-1];
+ if (c & mask) { // right child => search i'th
+ i = m_tree_select1(ones_before_o + i) - offset + 1;
+ } else { // left child => search i'th zero
+ i = m_tree_select0(offset - ones_before_o + i) - offset + 1;
+ }
+ mask <<= 1;
+ }
+ return i-1;
+ };
+
+
+ //! For each symbol c in wt[i..j-1] get rank(i,c) and rank(j,c).
+ /*!
+ * \param i The start index (inclusive) of the interval.
+ * \param j The end index (exclusive) of the interval.
+ * \param k Reference for number of different symbols in [i..j-1].
+ * \param cs Reference to a vector that will contain in
+ * cs[0..k-1] all symbols that occur in [i..j-1] in
+ * ascending order.
+ * \param rank_c_i Reference to a vector which equals
+ * rank_c_i[p] = rank(i,cs[p]), for \f$ 0 \leq p < k \f$.
+ * \param rank_c_j Reference to a vector which equals
+ * rank_c_j[p] = rank(j,cs[p]), for \f$ 0 \leq p < k \f$.
+ * \par Time complexity
+ * \f$ \Order{\min{\sigma, k \log \sigma}} \f$
+ *
+ * \par Precondition
+ * \f$ i \leq j \leq size() \f$
+ * \f$ cs.size() \geq \sigma \f$
+ * \f$ rank_{c_i}.size() \geq \sigma \f$
+ * \f$ rank_{c_j}.size() \geq \sigma \f$
+ */
+ void interval_symbols(size_type i, size_type j, size_type& k,
+ std::vector<value_type>& cs,
+ std::vector<size_type>& rank_c_i,
+ std::vector<size_type>& rank_c_j) const {
+ assert(i <= j and j <= size());
+ k=0;
+ if (i==j) {
+ return;
+ }
+ if ((i+1)==j) {
+ auto res = inverse_select(i);
+ cs[0]=res.second;
+ rank_c_i[0]=res.first;
+ rank_c_j[0]=res.first+1;
+ k=1;
+ return;
+ }
+
+ _interval_symbols(i, j, k, cs, rank_c_i, rank_c_j, 0, 0, m_size, 0);
+
+ }
+
+ //! How many symbols are lexicographic smaller/greater than c in [i..j-1].
+ /*!
+ * \param i Start index (inclusive) of the interval.
+ * \param j End index (exclusive) of the interval.
+ * \param c Symbol c.
+ * \return A triple containing:
+ * * rank(i,c)
+ * * #symbols smaller than c in [i..j-1]
+ * * #symbols greater than c in [i..j-1]
+ *
+ * \par Precondition
+ * \f$ i \leq j \leq size() \f$
+ */
+ template<class t_ret_type = std::tuple<size_type, size_type, size_type>>
+ t_ret_type lex_count(size_type i, size_type j, value_type c)const {
+ assert(i <= j and j <= size());
+ if (((1ULL)<<(m_max_level))<=c) { // c is greater than any symbol in wt
+ return t_ret_type {0, j-i, 0};
+ }
+ size_type offset = 0;
+ size_type smaller = 0;
+ size_type greater = 0;
+ uint64_t mask = (1ULL) << (m_max_level-1);
+ size_type node_size = m_size;
+ for (uint32_t k=0; k < m_max_level; ++k) {
+ size_type ones_before_o = m_tree_rank(offset);
+ size_type ones_before_i = m_tree_rank(offset + i) - ones_before_o;
+ size_type ones_before_j = m_tree_rank(offset + j) - ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset + node_size) - ones_before_o;
+ if (c & mask) { // search for a one at this level
+ offset += (node_size - ones_before_end);
+ node_size = ones_before_end;
+ smaller += j-i-ones_before_j+ones_before_i;
+ i = ones_before_i;
+ j = ones_before_j;
+ } else { // search for a zero at this level
+ node_size -= ones_before_end;
+ greater += ones_before_j-ones_before_i;
+ i -= ones_before_i;
+ j -= ones_before_j;
+ }
+ offset += m_size;
+ mask >>= 1;
+ }
+ return t_ret_type {i, smaller, greater};
+ };
+
+ //! How many symbols are lexicographic smaller than c in [0..i-1].
+ /*!
+ * \param i Exclusive right bound of the range.
+ * \param c Symbol c.
+ * \return A tuple containing:
+ * * rank(i,c)
+ * * #symbols smaller than c in [0..i-1]
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ template<class t_ret_type = std::tuple<size_type, size_type>>
+ t_ret_type lex_smaller_count(size_type i, value_type c) const {
+ assert(i <= size());
+ if (((1ULL)<<(m_max_level))<=c) { // c is greater than any symbol in wt
+ return t_ret_type {0, i};
+ }
+ size_type offset = 0;
+ size_type result = 0;
+ uint64_t mask = (1ULL) << (m_max_level-1);
+ size_type node_size = m_size;
+ for (uint32_t k=0; k < m_max_level and i; ++k) {
+ size_type ones_before_o = m_tree_rank(offset);
+ size_type ones_before_i = m_tree_rank(offset + i) - ones_before_o;
+ size_type ones_before_end = m_tree_rank(offset + node_size) - ones_before_o;
+ if (c & mask) { // search for a one at this level
+ offset += (node_size - ones_before_end);
+ node_size = ones_before_end;
+ result += i - ones_before_i;
+ i = ones_before_i;
+ } else { // search for a zero at this level
+ node_size = (node_size - ones_before_end);
+ i -= ones_before_i;
+ }
+ offset += m_size;
+ mask >>= 1;
+ }
+ return t_ret_type {i, result};
+ }
+
+ //! range_search_2d searches points in the index interval [lb..rb] and value interval [vlb..vrb].
+ /*! \param lb Left bound of index interval (inclusive)
+ * \param rb Right bound of index interval (inclusive)
+ * \param vlb Left bound of value interval (inclusive)
+ * \param vrb Right bound of value interval (inclusive)
+ * \param report Should the matching points be returned?
+ * \return Pair (#of found points, vector of points), the vector is empty when
+ * report = false.
+ */
+ std::pair<size_type, std::vector<std::pair<value_type, size_type>>>
+ range_search_2d(size_type lb, size_type rb, value_type vlb, value_type vrb,
+ bool report=true) const {
+ size_type offsets[m_max_level+1];
+ size_type ones_before_os[m_max_level+1];
+ offsets[0] = 0;
+ if (vrb > (1ULL << m_max_level))
+ vrb = (1ULL << m_max_level);
+ if (vlb > vrb)
+ return make_pair(0, point_vec_type());
+ size_type cnt_answers = 0;
+ point_vec_type point_vec;
+ _range_search_2d(lb, rb, vlb, vrb, 0, 0, m_size, offsets, ones_before_os, 0, point_vec, report, cnt_answers);
+ return make_pair(cnt_answers, point_vec);
+ }
+
+ void
+ _range_search_2d(size_type lb, size_type rb, value_type vlb, value_type vrb, size_type level,
+ size_type ilb, size_type node_size, size_type offsets[],
+ size_type ones_before_os[], size_type path,
+ point_vec_type& point_vec, bool report, size_type& cnt_answers)
+ const {
+ if (lb > rb)
+ return;
+ if (level == m_max_level) {
+ if (report) {
+ for (size_type j=lb+1; j <= rb+1; ++j) {
+ size_type i = j;
+ size_type c = path;
+ for (uint32_t k=m_max_level; k>0; --k) {
+ size_type offset = offsets[k-1];
+ size_type ones_before_o = ones_before_os[k-1];
+ if (c&1) {
+ i = m_tree_select1(ones_before_o + i) - offset + 1;
+ } else {
+ i = m_tree_select0(offset - ones_before_o + i) - offset + 1;
+ }
+ c >>= 1;
+ }
+ point_vec.emplace_back(i-1, path);
+ }
+ }
+ cnt_answers += rb-lb+1;
+ return;
+ }
+ size_type irb = ilb + (1ULL << (m_max_level-level));
+ size_type mid = (irb + ilb)>>1;
+
+ size_type offset = offsets[level];
+
+ size_type ones_before_o = m_tree_rank(offset);
+ ones_before_os[level] = ones_before_o;
+ size_type ones_before_lb = m_tree_rank(offset + lb);
+ size_type ones_before_rb = m_tree_rank(offset + rb + 1);
+ size_type ones_before_end = m_tree_rank(offset + node_size);
+ size_type zeros_before_o = offset - ones_before_o;
+ size_type zeros_before_lb = offset + lb - ones_before_lb;
+ size_type zeros_before_rb = offset + rb + 1 - ones_before_rb;
+ size_type zeros_before_end = offset + node_size - ones_before_end;
+ if (vlb < mid and mid) {
+ size_type nlb = zeros_before_lb - zeros_before_o;
+ size_type nrb = zeros_before_rb - zeros_before_o;
+ offsets[level+1] = offset + m_size;
+ if (nrb)
+ _range_search_2d(nlb, nrb-1, vlb, std::min(vrb,mid-1), level+1, ilb, zeros_before_end - zeros_before_o, offsets, ones_before_os, path<<1, point_vec, report, cnt_answers);
+ }
+ if (vrb >= mid) {
+ size_type nlb = ones_before_lb - ones_before_o;
+ size_type nrb = ones_before_rb - ones_before_o;
+ offsets[level+1] = offset + m_size + (zeros_before_end - zeros_before_o);
+ if (nrb)
+ _range_search_2d(nlb, nrb-1, std::max(mid, vlb), vrb, level+1, mid, ones_before_end - ones_before_o, offsets, ones_before_os, (path<<1)+1 , point_vec, report, cnt_answers);
+ }
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr, std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += write_member(m_sigma, out, child, "sigma");
+ written_bytes += m_tree.serialize(out, child, "tree");
+ written_bytes += m_tree_rank.serialize(out, child, "tree_rank");
+ written_bytes += m_tree_select1.serialize(out, child, "tree_select_1");
+ written_bytes += m_tree_select0.serialize(out, child, "tree_select_0");
+ written_bytes += write_member(m_max_level, out, child, "max_level");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_sigma, in);
+ m_tree.load(in);
+ m_tree_rank.load(in, &m_tree);
+ m_tree_select1.load(in, &m_tree);
+ m_tree_select0.load(in, &m_tree);
+ read_member(m_max_level, in);
+ init_buffers(m_max_level);
+ }
+
+ //! Represents a node in the wavelet tree
+ struct node_type {
+ size_type offset = 0;
+ size_type size = 0;
+ size_type level = 0;
+ value_type sym = 0;
+
+ // Default constructor
+ node_type(size_type o=0, size_type sz=0, size_type l=0,
+ value_type sy=0) :
+ offset(o), size(sz), level(l), sym(sy) {}
+
+ // Copy constructor
+ node_type(const node_type&) = default;
+
+ // Move copy constructor
+ node_type(node_type&&) = default;
+
+ // Assignment operator
+ node_type& operator=(const node_type&) = default;
+
+ // Move assignment operator
+ node_type& operator=(node_type&&) = default;
+
+ // Comparator operator
+ bool operator==(const node_type& v) const {
+ return offset == v.offset;
+ }
+
+ // Smaller operator
+ bool operator<(const node_type& v) const {
+ return offset < v.offset;
+ }
+
+ // Greater operator
+ bool operator>(const node_type& v) const {
+ return offset > v.offset;
+ }
+ };
+
+ //! Checks if the node is a leaf node
+ bool is_leaf(const node_type& v) const {
+ return v.level == m_max_level;
+ }
+
+ value_type sym(const node_type& v) const {
+ return v.sym;
+ }
+
+ bool empty(const node_type& v) const {
+ return v.size == (size_type)0;
+ }
+
+ //! Return the root node
+ node_type root() const {
+ return node_type(0, m_size, 0, 0);
+ }
+
+ //! Returns the two child nodes of an inner node
+ /*! \param v An inner node of a wavelet tree.
+ * \return Return a pair of nodes (left child, right child).
+ * \pre !is_leaf(v)
+ */
+ std::pair<node_type, node_type>
+ expand(const node_type& v) const {
+ node_type v_right = v;
+ return expand(std::move(v_right));
+ }
+
+ //! Returns the two child nodes of an inner node
+ /*! \param v An inner node of a wavelet tree.
+ * \return Return a pair of nodes (left child, right child).
+ * \pre !is_leaf(v)
+ */
+ std::pair<node_type, node_type>
+ expand(node_type&& v) const {
+ node_type v_left;
+ size_type offset_rank = m_tree_rank(v.offset);
+ size_type ones = m_tree_rank(v.offset + v.size) - offset_rank;
+
+ v_left.offset = v.offset + m_size;
+ v_left.size = v.size - ones;
+ v_left.level = v.level + 1;
+ v_left.sym = v.sym<<1;
+
+ v.offset = v.offset + m_size + v_left.size;
+ v.size = ones;
+ v.level = v.level + 1;
+ v.sym = (v.sym<<1)|1;
+
+ return std::make_pair(std::move(v_left), v);
+ }
+
+ //! Returns for each range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param ranges A vector of ranges. Each range [s,e]
+ * has to be contained in v=[v_s,v_e].
+ * \return A vector a range pairs. The first element of each
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_vec_type, range_vec_type>
+ expand(const node_type& v,
+ const range_vec_type& ranges) const {
+ auto ranges_copy = ranges;
+ return expand(v, std::move(ranges_copy));
+ }
+
+ //! Returns for each range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param ranges A vector of ranges. Each range [s,e]
+ * has to be contained in v=[v_s,v_e].
+ * \return A vector a range pairs. The first element of each
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_vec_type, range_vec_type>
+ expand(const node_type& v,
+ range_vec_type&& ranges) const {
+ auto v_sp_rank = m_tree_rank(v.offset); // this is already calculated in expand(v)
+ range_vec_type res(ranges.size());
+ size_t i = 0;
+ for (auto& r : ranges) {
+ auto sp_rank = m_tree_rank(v.offset + r.first);
+ auto right_size = m_tree_rank(v.offset + r.second + 1)
+ - sp_rank;
+ auto left_size = (r.second-r.first+1)-right_size;
+
+ auto right_sp = sp_rank - v_sp_rank;
+ auto left_sp = r.first - right_sp;
+
+ r = range_type(left_sp, left_sp + left_size - 1);
+ res[i++] = range_type(right_sp, right_sp + right_size - 1);
+ }
+ return make_pair(ranges, std::move(res));
+ }
+
+ //! Returns for a range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param r A ranges [s,e], such that [s,e] is
+ * contained in v=[v_s,v_e].
+ * \return A range pair. The first element of the
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_type, range_type>
+ expand(const node_type& v, const range_type& r) const {
+ auto v_sp_rank = m_tree_rank(v.offset); // this is already calculated in expand(v)
+ auto sp_rank = m_tree_rank(v.offset + r.first);
+ auto right_size = m_tree_rank(v.offset + r.second + 1)
+ - sp_rank;
+ auto left_size = (r.second-r.first+1)-right_size;
+
+ auto right_sp = sp_rank - v_sp_rank;
+ auto left_sp = r.first - right_sp;
+
+ return make_pair(range_type(left_sp, left_sp + left_size - 1),
+ range_type(right_sp, right_sp + right_size - 1));
+ }
+
+ //! return the path to the leaf for a given symbol
+ std::pair<uint64_t,uint64_t> path(value_type c) const {
+ return {m_max_level,c};
+ }
+};
+
+}// end namespace sdsl
+#endif
diff --git a/include/sdsl/wt_pc.hpp b/include/sdsl/wt_pc.hpp
new file mode 100644
index 0000000..edfb46f
--- /dev/null
+++ b/include/sdsl/wt_pc.hpp
@@ -0,0 +1,799 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_pc.hpp
+ \brief wt_pc.hpp contains a class for the wavelet tree of byte sequences.
+ The wavelet tree shape is parametrized by a prefix code.
+ \author Simon Gog, Timo Beller
+*/
+#ifndef INCLUDED_SDSL_WT_PC
+#define INCLUDED_SDSL_WT_PC
+
+#include "bit_vectors.hpp"
+#include "rank_support.hpp"
+#include "select_support.hpp"
+#include "wt_helper.hpp"
+#include <vector>
+#include <utility>
+#include <tuple>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+//! A prefix code-shaped wavelet.
+/*!
+ * \tparam t_shape Shape of the tree ().
+ * \tparam t_bitvector Underlying bitvector structure.
+ * \tparam t_rank Rank support for pattern `1` on the bitvector.
+ * \tparam t_select Select support for pattern `1` on the bitvector.
+ * \tparam t_select_zero Select support for pattern `0` on the bitvector.
+ * \tparam t_tree_strat Tree strategy determines alphabet and the tree
+ * class used to navigate the WT.
+ *
+ * @ingroup wt
+ */
+template<class t_shape,
+ class t_bitvector = bit_vector,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_select_zero = typename t_bitvector::select_0_type,
+ class t_tree_strat = byte_tree<>
+ >
+class wt_pc
+{
+ public:
+ typedef typename
+ t_tree_strat::template type<wt_pc> tree_strat_type;
+ typedef int_vector<>::size_type size_type;
+ typedef typename
+ tree_strat_type::value_type value_type;
+ typedef typename t_bitvector::difference_type difference_type;
+ typedef random_access_const_iterator<wt_pc> const_iterator;
+ typedef const_iterator iterator;
+ typedef t_bitvector bit_vector_type;
+ typedef t_rank rank_1_type;
+ typedef t_select select_1_type;
+ typedef t_select_zero select_0_type;
+ typedef wt_tag index_category;
+ typedef typename
+ tree_strat_type::alphabet_category alphabet_category;
+ typedef typename
+ t_shape::template type<wt_pc> shape_type;
+ enum { lex_ordered=shape_type::lex_ordered };
+ using node_type = typename tree_strat_type::node_type;
+
+ private:
+
+#ifdef WT_PC_CACHE
+ mutable value_type m_last_access_answer;
+ mutable size_type m_last_access_i;
+ mutable size_type m_last_access_rl;
+#endif
+
+ size_type m_size = 0; // original text size
+ size_type m_sigma = 0; // alphabet size
+ bit_vector_type m_bv; // bit vector to store the wavelet tree
+ rank_1_type m_bv_rank; // rank support for the wavelet tree bit vector
+ select_1_type m_bv_select1; // select support for the wavelet tree bit vector
+ select_0_type m_bv_select0;
+ tree_strat_type m_tree;
+
+ void copy(const wt_pc& wt) {
+ m_size = wt.m_size;
+ m_sigma = wt.m_sigma;
+ m_bv = wt.m_bv;
+ m_bv_rank = wt.m_bv_rank;
+ m_bv_rank.set_vector(&m_bv);
+ m_bv_select1 = wt.m_bv_select1;
+ m_bv_select1.set_vector(&m_bv);
+ m_bv_select0 = wt.m_bv_select0;
+ m_bv_select0.set_vector(&m_bv);
+ m_tree = wt.m_tree;
+ }
+
+ // insert a character into the wavelet tree, see construct method
+ void insert_char(value_type old_chr, std::vector<uint64_t>& bv_node_pos,
+ size_type times, bit_vector& bv) {
+ uint64_t p = m_tree.bit_path(old_chr);
+ uint32_t path_len = p>>56;
+ node_type v = m_tree.root();
+ for (uint32_t l=0; l<path_len; ++l, p >>= 1) {
+ if (p&1) {
+ bv.set_int(bv_node_pos[v], 0xFFFFFFFFFFFFFFFFULL,times);
+ }
+ bv_node_pos[v] += times;
+ v = m_tree.child(v, p&1);
+ }
+ }
+
+
+
+ // calculates the tree shape returns the size of the WT bit vector
+ size_type construct_tree_shape(const std::vector<size_type>& C) {
+ // vector for node of the tree
+ std::vector<pc_node> temp_nodes; //(2*m_sigma-1);
+ shape_type::construct_tree(C, temp_nodes);
+ // Convert code tree into BFS order in memory and
+ // calculate bv_pos values
+ size_type bv_size = 0;
+ tree_strat_type temp_tree(temp_nodes, bv_size, this);
+ m_tree.swap(temp_tree);
+ return bv_size;
+ }
+
+ void construct_init_rank_select() {
+ util::init_support(m_bv_rank, &m_bv);
+ util::init_support(m_bv_select0, &m_bv);
+ util::init_support(m_bv_select1, &m_bv);
+ }
+
+ // recursive internal version of the method interval_symbols
+ void
+ _interval_symbols(size_type i, size_type j, size_type& k,
+ std::vector<value_type>& cs,
+ std::vector<size_type>& rank_c_i,
+ std::vector<size_type>& rank_c_j, node_type v) const {
+ // invariant: j>i
+ size_type i_new = (m_bv_rank(m_tree.bv_pos(v) + i)
+ - m_tree.bv_pos_rank(v));
+ size_type j_new = (m_bv_rank(m_tree.bv_pos(v) + j)
+ - m_tree.bv_pos_rank(v));
+ // goto left child
+ i -= i_new; j -= j_new;
+ if (i != j) {
+ node_type v_new = m_tree.child(v, 0);
+ if (!m_tree.is_leaf(v_new)) {
+ _interval_symbols(i, j, k, cs, rank_c_i, rank_c_j, v_new);
+ } else {
+ rank_c_i[k] = i;
+ rank_c_j[k] = j;
+ cs[k++] = m_tree.bv_pos_rank(v_new);
+ }
+ }
+ // goto right child
+ if (i_new!=j_new) {
+ node_type v_new = m_tree.child(v, 1);
+ if (!m_tree.is_leaf(v_new)) {
+ _interval_symbols(i_new, j_new, k, cs, rank_c_i, rank_c_j,
+ v_new);
+ } else {
+ rank_c_i[k] = i_new;
+ rank_c_j[k] = j_new;
+ cs[k++] = m_tree.bv_pos_rank(v_new);
+ }
+ }
+ }
+
+ public:
+
+ const size_type& sigma = m_sigma;
+ const bit_vector_type& bv = m_bv;
+
+ // Default constructor
+ wt_pc() {};
+
+ //! Construct the wavelet tree from a file_buffer
+ /*!
+ * \param input_buf File buffer of the input.
+ * \param size The length of the prefix.
+ * \par Time complexity
+ * \f$ \Order{n\log|\Sigma|}\f$, where \f$n=size\f$
+ */
+ wt_pc(int_vector_buffer<tree_strat_type::int_width>& input_buf,
+ size_type size):m_size(size) {
+ if (0 == m_size)
+ return;
+ // O(n + |\Sigma|\log|\Sigma|) algorithm for calculating node sizes
+ // TODO: C should also depend on the tree_strategy. C is just a mapping
+ // from a symbol to its frequency. So a map<uint64_t,uint64_t> could be
+ // used for integer alphabets...
+ std::vector<size_type> C;
+ // 1. Count occurrences of characters
+ calculate_character_occurences(input_buf, m_size, C);
+ // 2. Calculate effective alphabet size
+ calculate_effective_alphabet_size(C, m_sigma);
+ // 3. Generate tree shape
+ size_type tree_size = construct_tree_shape(C);
+ // 4. Generate wavelet tree bit sequence m_bv
+ bit_vector temp_bv(tree_size, 0);
+
+ // Initializing starting position of wavelet tree nodes
+ std::vector<uint64_t> bv_node_pos(m_tree.size(), 0);
+ for (size_type v=0; v < m_tree.size(); ++v) {
+ bv_node_pos[v] = m_tree.bv_pos(v);
+ }
+ if (input_buf.size() < size) {
+ throw std::logic_error("Stream size is smaller than size!");
+ return;
+ }
+ value_type old_chr = input_buf[0];
+ uint32_t times = 0;
+ for (size_type i=0; i < m_size; ++i) {
+ value_type chr = input_buf[i];
+ if (chr != old_chr) {
+ insert_char(old_chr, bv_node_pos, times, temp_bv);
+ times = 1;
+ old_chr = chr;
+ } else { // chr == old_chr
+ ++times;
+ if (times == 64) {
+ insert_char(old_chr, bv_node_pos, times, temp_bv);
+ times = 0;
+ }
+ }
+ }
+ if (times > 0) {
+ insert_char(old_chr, bv_node_pos, times, temp_bv);
+ }
+ m_bv = bit_vector_type(std::move(temp_bv));
+ // 5. Initialize rank and select data structures for m_bv
+ construct_init_rank_select();
+ // 6. Finish inner nodes by precalculating the bv_pos_rank values
+ m_tree.init_node_ranks(m_bv_rank);
+ }
+
+
+ //! Copy constructor
+ wt_pc(const wt_pc& wt) { copy(wt); }
+
+ wt_pc(wt_pc&& wt) {
+ *this = std::move(wt);
+ }
+
+ //! Assignment operator
+ wt_pc& operator=(const wt_pc& wt) {
+ if (this != &wt) {
+ copy(wt);
+ }
+ return *this;
+ }
+
+ //! Assignment operator
+ wt_pc& operator=(wt_pc&& wt) {
+ if (this != &wt) {
+ m_size = wt.m_size;
+ m_sigma = wt.m_sigma;
+ m_bv = std::move(wt.m_bv);
+ m_bv_rank = std::move(wt.m_bv_rank);
+ m_bv_rank.set_vector(&m_bv);
+ m_bv_select1 = std::move(wt.m_bv_select1);
+ m_bv_select1.set_vector(&m_bv);
+ m_bv_select0 = std::move(wt.m_bv_select0);
+ m_bv_select0.set_vector(&m_bv);
+ m_tree = std::move(wt.m_tree);
+ }
+ return *this;
+ }
+
+
+ //! Swap operator
+ void swap(wt_pc& wt) {
+ if (this != &wt) {
+ std::swap(m_size, wt.m_size);
+ std::swap(m_sigma, wt.m_sigma);
+ m_bv.swap(wt.m_bv);
+ util::swap_support(m_bv_rank, wt.m_bv_rank,
+ &m_bv, &(wt.m_bv));
+
+ util::swap_support(m_bv_select1, wt.m_bv_select1,
+ &m_bv, &(wt.m_bv));
+ util::swap_support(m_bv_select0, wt.m_bv_select0,
+ &m_bv, &(wt.m_bv));
+ m_tree.swap(wt.m_tree);
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size()const { return m_size; }
+
+ //! Returns whether the wavelet tree contains no data.
+ bool empty()const { return m_size == 0; }
+
+ //! Recovers the i-th symbol of the original vector.
+ /*!
+ * \param i Index in the original vector.
+ * \return The i-th symbol of the original vector.
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$ on average, where \f$ H_0 \f$ is the
+ * zero order entropy of the sequence
+ *
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ // which stores how many of the next symbols are equal
+ // with the current char
+ node_type v = m_tree.root(); // start at root node
+ while (!m_tree.is_leaf(v)) { // while not a leaf
+ if (m_bv[ m_tree.bv_pos(v) + i]) { // goto right child
+ i = m_bv_rank(m_tree.bv_pos(v) + i)
+ - m_tree.bv_pos_rank(v);
+ v = m_tree.child(v,1);
+ } else { // goto the left child
+ i -= (m_bv_rank(m_tree.bv_pos(v) + i)
+ - m_tree.bv_pos_rank(v));
+ v = m_tree.child(v,0);
+ }
+ }
+ // if v is a leaf bv_pos_rank returns symbol itself
+ return m_tree.bv_pos_rank(v);
+ };
+
+ //! Calculates how many symbols c are in the prefix [0..i-1].
+ /*!
+ * \param i Exclusive right bound of the range.
+ * \param c Symbol c.
+ * \return Number of occurrences of symbol c in the prefix [0..i-1].
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$ on average, where \f$ H_0 \f$ is the
+ * zero order entropy of the sequence
+ *
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ */
+ size_type rank(size_type i, value_type c)const {
+ assert(i <= size());
+ if (!m_tree.is_valid(m_tree.c_to_leaf(c))) {
+ return 0; // if `c` was not in the text
+ }
+ if (m_sigma == 1) {
+ return i; // if m_sigma == 1 answer is trivial
+ }
+ uint64_t p = m_tree.bit_path(c);
+ uint32_t path_len = (p>>56);
+ size_type result = i;
+ node_type v = m_tree.root();
+ for (uint32_t l=0; l<path_len and result; ++l, p >>= 1) {
+ if (p&1) {
+ result = (m_bv_rank(m_tree.bv_pos(v)+result)
+ - m_tree.bv_pos_rank(v));
+ } else {
+ result -= (m_bv_rank(m_tree.bv_pos(v)+result)
+ - m_tree.bv_pos_rank(v));
+ }
+ v = m_tree.child(v, p&1); // goto child
+ }
+ return result;
+ };
+
+ //! Calculates how many times symbol wt[i] occurs in the prefix [0..i-1].
+ /*!
+ * \param i The index of the symbol.
+ * \return Pair (rank(wt[i],i),wt[i])
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$
+ *
+ * \par Precondition
+ * \f$ i < size() \f$
+ */
+ std::pair<size_type, value_type>
+ inverse_select(size_type i)const {
+ assert(i < size());
+ node_type v = m_tree.root();
+ while (!m_tree.is_leaf(v)) { // while not a leaf
+ if (m_bv[m_tree.bv_pos(v) + i]) { // goto right child
+ i = (m_bv_rank(m_tree.bv_pos(v) + i)
+ - m_tree.bv_pos_rank(v));
+ v = m_tree.child(v, 1);
+ } else { // goto left child
+ i -= (m_bv_rank(m_tree.bv_pos(v) + i)
+ - m_tree.bv_pos_rank(v));
+ v = m_tree.child(v,0);
+ }
+ }
+ // if v is a leaf bv_pos_rank returns symbol itself
+ return std::make_pair(i, (value_type)m_tree.bv_pos_rank(v));
+ }
+
+ //! Calculates the ith occurrence of the symbol c in the supported vector.
+ /*!
+ * \param i The ith occurrence.
+ * \param c The symbol c.
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$ on average, where \f$ H_0 \f$ is the zero order
+ * entropy of the sequence
+ *
+ * \par Precondition
+ * \f$ 1 \leq i \leq rank(size(), c) \f$
+ */
+ size_type select(size_type i, value_type c)const {
+ assert(1 <= i and i <= rank(size(), c));
+ node_type v = m_tree.c_to_leaf(c);
+ if (!m_tree.is_valid(v)) { // if c was not in the text
+ return m_size; // -> return a position right to the end
+ }
+ if (m_sigma == 1) {
+ return std::min(i-1,m_size);
+ }
+ size_type result = i-1; // otherwise
+ uint64_t p = m_tree.bit_path(c);
+ uint32_t path_len = (p>>56);
+ // path_len > 0, since we have handled m_sigma = 1.
+ p <<= (64-path_len);
+ for (uint32_t l=0; l<path_len; ++l, p <<= 1) {
+ if ((p & 0x8000000000000000ULL)==0) { // node was a left child
+ v = m_tree.parent(v);
+ result = m_bv_select0(m_tree.bv_pos(v)
+ - m_tree.bv_pos_rank(v) + result + 1)
+ - m_tree.bv_pos(v);
+ } else { // node was a right child
+ v = m_tree.parent(v);
+ result = m_bv_select1(m_tree.bv_pos_rank(v) + result + 1)
+ - m_tree.bv_pos(v);
+ }
+ }
+ return result;
+ };
+
+
+ //! For each symbol c in wt[i..j-1] get rank(i,c) and rank(j,c).
+ /*!
+ * \param i The start index (inclusive) of the interval.
+ * \param j The end index (exclusive) of the interval.
+ * \param k Reference for number of different symbols in [i..j-1].
+ * \param cs Reference to a vector that will contain in
+ * cs[0..k-1] all symbols that occur in [i..j-1] in
+ * arbitrary order (if lex_ordered = false) and ascending
+ * order (if lex_ordered = true).
+ * \param rank_c_i Reference to a vector which equals
+ * rank_c_i[p] = rank(i,cs[p]), for \f$ 0 \leq p < k \f$.
+ * \param rank_c_j Reference to a vector which equals
+ * rank_c_j[p] = rank(j,cs[p]), for \f$ 0 \leq p < k \f$.
+ * \par Time complexity
+ * \f$ \Order{\min{\sigma, k \log \sigma}} \f$
+ *
+ * \par Precondition
+ * \f$ i \leq j \leq size() \f$
+ * \f$ cs.size() \geq \sigma \f$
+ * \f$ rank_{c_i}.size() \geq \sigma \f$
+ * \f$ rank_{c_j}.size() \geq \sigma \f$
+ */
+ void interval_symbols(size_type i, size_type j, size_type& k,
+ std::vector<value_type>& cs,
+ std::vector<size_type>& rank_c_i,
+ std::vector<size_type>& rank_c_j) const {
+ assert(i <= j and j <= size());
+ if (i==j) {
+ k = 0;
+ } else if (1==m_sigma) {
+ k = 1;
+ cs[0] = m_tree.bv_pos_rank(m_tree.root());
+ rank_c_i[0] = std::min(i,m_size);
+ rank_c_j[0] = std::min(j,m_size);
+ } else if ((j-i)==1) {
+ k = 1;
+ auto rc = inverse_select(i);
+ rank_c_i[0] = rc.first; cs[0] = rc.second;
+ rank_c_j[0] = rank_c_i[0]+1;
+ } else if ((j-i)==2) {
+ auto rc = inverse_select(i);
+ rank_c_i[0] = rc.first; cs[0] = rc.second;
+ rc = inverse_select(i+1);
+ rank_c_i[1] = rc.first; cs[1] = rc.second;
+
+ if (cs[0]==cs[1]) {
+ k = 1;
+ rank_c_j[0] = rank_c_i[0]+2;
+ } else {
+ k = 2;
+ if (lex_ordered and cs[0] > cs[1]) {
+ std::swap(cs[0], cs[1]);
+ std::swap(rank_c_i[0], rank_c_i[1]);
+ }
+ rank_c_j[0] = rank_c_i[0]+1;
+ rank_c_j[1] = rank_c_i[1]+1;
+ }
+ } else {
+ k = 0;
+ _interval_symbols(i, j, k, cs, rank_c_i, rank_c_j, 0);
+ }
+ }
+
+
+ //! How many symbols are lexicographic smaller/greater than c in [i..j-1].
+ /*!
+ * \param i Start index (inclusive) of the interval.
+ * \param j End index (exclusive) of the interval.
+ * \param c Symbol c.
+ * \return A triple containing:
+ * * rank(i,c)
+ * * #symbols smaller than c in [i..j-1]
+ * * #symbols greater than c in [i..j-1]
+ *
+ * \par Precondition
+ * \f$ i \leq j \leq size() \f$
+ * \note
+ * This method is only available if lex_ordered = true
+ */
+ template<class t_ret_type = std::tuple<size_type, size_type, size_type>>
+ typename std::enable_if<shape_type::lex_ordered, t_ret_type>::type
+ lex_count(size_type i, size_type j, value_type c) const {
+ assert(i <= j and j <= size());
+ if (1==m_sigma) {
+ value_type _c = m_tree.bv_pos_rank(m_tree.root());
+ if (c == _c) { // c is the only symbol in the wt
+ return t_ret_type {i,0,0};
+ } else if (c < _c) {
+ return t_ret_type {0,0,j-i};
+ } else {
+ return t_ret_type {0,j-i,0};
+ }
+ }
+ if (i==j) {
+ return t_ret_type {rank(i,c),0,0};
+ }
+ uint64_t p = m_tree.bit_path(c);
+ uint32_t path_len = p>>56;
+ if (path_len == 0) { // path_len=0: => c is not present
+ value_type _c = (value_type)p;
+ if (c == _c) { // c is smaller than any symbol in wt
+ return t_ret_type {0, 0, j-i};
+ }
+ auto res = lex_count(i, j, _c);
+ return t_ret_type {0, j-i-std::get<2>(res),std::get<2>(res)};
+ }
+ size_type smaller = 0, greater = 0;
+ node_type v = m_tree.root();
+ for (uint32_t l=0; l<path_len; ++l, p >>= 1) {
+ size_type r1_1 = (m_bv_rank(m_tree.bv_pos(v)+i)
+ - m_tree.bv_pos_rank(v));
+ size_type r1_2 = (m_bv_rank(m_tree.bv_pos(v)+j)
+ - m_tree.bv_pos_rank(v));
+
+ if (p&1) {
+ smaller += j - r1_2 - i + r1_1;
+ i = r1_1;
+ j = r1_2;
+ } else {
+ greater += r1_2 - r1_1;
+ i -= r1_1;
+ j -= r1_2;
+ }
+ v = m_tree.child(v, p&1);
+ }
+ return t_ret_type {i, smaller, greater};
+ };
+
+ //! How many symbols are lexicographic smaller than c in [0..i-1].
+ /*!
+ * \param i Exclusive right bound of the range.
+ * \param c Symbol c.
+ * \return A tuple containing:
+ * * rank(i,c)
+ * * #symbols smaller than c in [0..i-1]
+ * \par Precondition
+ * \f$ i \leq size() \f$
+ * \note
+ * This method is only available if lex_ordered = true
+ */
+ template<class t_ret_type = std::tuple<size_type, size_type>>
+ typename std::enable_if<shape_type::lex_ordered, t_ret_type>::type
+ lex_smaller_count(size_type i, value_type c)const {
+ assert(i <= size());
+ if (1==m_sigma) {
+ value_type _c = m_tree.bv_pos_rank(m_tree.root());
+ if (c == _c) { // c is the only symbol in the wt
+ return t_ret_type {i,0};
+ } else if (c < _c) {
+ return t_ret_type {0,0};
+ } else {
+ return t_ret_type {0,i};
+ }
+ }
+
+ uint64_t p = m_tree.bit_path(c);
+ uint32_t path_len = p>>56;
+ if (path_len == 0) { // path_len=0: => c is not present
+ value_type _c = (value_type)p;
+ if (c == _c) { // c is smaller than any symbol in wt
+ return t_ret_type {0, 0};
+ }
+ auto res = lex_smaller_count(i, _c);
+ return t_ret_type {0, std::get<0>(res)+std::get<1>(res)};
+ }
+ size_type result = 0;
+ size_type all = i; // possible occurrences of c
+ node_type v = m_tree.root();
+ for (uint32_t l=0; l<path_len and all; ++l, p >>= 1) {
+ size_type ones = (m_bv_rank(m_tree.bv_pos(v)+all)
+ - m_tree.bv_pos_rank(v));
+ if (p&1) {
+ result += all - ones;
+ all = ones;
+ } else {
+ all -= ones;
+ }
+ v = m_tree.child(v, p&1);
+ }
+ return t_ret_type {all, result};
+ }
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="") const {
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size,out,child, "size");
+ written_bytes += write_member(m_sigma,out,child, "sigma");
+ written_bytes += m_bv.serialize(out,child,"bv");
+ written_bytes += m_bv_rank.serialize(out,child,"bv_rank");
+ written_bytes += m_bv_select1.serialize(out,child,"bv_select_1");
+ written_bytes += m_bv_select0.serialize(out,child,"bv_select_0");
+ written_bytes += m_tree.serialize(out,child,"tree");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ read_member(m_sigma, in);
+ m_bv.load(in);
+ m_bv_rank.load(in, &m_bv);
+ m_bv_select1.load(in, &m_bv);
+ m_bv_select0.load(in, &m_bv);
+ m_tree.load(in);
+ }
+
+ //! Checks if the node is a leaf node
+ bool is_leaf(const node_type& v) const {
+ return m_tree.is_leaf(v);
+ }
+
+ //! Symbol for a leaf
+ value_type sym(const node_type& v) const {
+ return m_tree.bv_pos_rank(v);
+ }
+
+ bool empty(const node_type&) const {
+ return true;
+ }
+
+ //! Returns the root node
+ node_type root() const {
+ return m_tree.root();
+ }
+
+ //! Returns the two child nodes of an inner node
+ /*! \param v An inner node of a wavelet tree.
+ * \return Return a pair of nodes (left child, right child).
+ * \pre !is_leaf(v)
+ */
+ std::pair<node_type, node_type>
+ expand(const node_type& v) const {
+ return std::make_pair(m_tree.child(v,0), m_tree.child(v,1));
+ }
+
+ //! Returns for each range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param ranges A vector of ranges. Each range [s,e]
+ * has to be contained in v=[v_s,v_e].
+ * \return A vector a range pairs. The first element of each
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_vec_type, range_vec_type>
+ expand(const node_type& v,
+ const range_vec_type& ranges) const {
+ auto ranges_copy = ranges;
+ return expand(v, std::move(ranges_copy));
+ }
+
+ //! Returns for each range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param ranges A vector of ranges. Each range [s,e]
+ * has to be contained in v=[v_s,v_e].
+ * \return A vector a range pairs. The first element of each
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_vec_type, range_vec_type>
+ expand(const node_type& v,
+ range_vec_type&& ranges) const {
+ auto v_sp_rank = m_tree.bv_pos_rank(v);
+ range_vec_type res(ranges.size());
+ size_t i = 0;
+ for (auto& r : ranges) {
+ auto sp_rank = m_bv_rank(m_tree.bv_pos(v) + r.first);
+ auto right_size = m_bv_rank(m_tree.bv_pos(v) + r.second + 1)
+ - sp_rank;
+ auto left_size = (r.second-r.first+1)-right_size;
+
+ auto right_sp = sp_rank - v_sp_rank;
+ auto left_sp = r.first - right_sp;
+
+ r = range_type(left_sp, left_sp + left_size - 1);
+ res[i++] = range_type(right_sp, right_sp + right_size - 1);
+ }
+ return make_pair(ranges, std::move(res));
+ }
+
+ //! Returns for a range its left and right child ranges
+ /*! \param v An inner node of an wavelet tree.
+ * \param r A ranges [s,e], such that [s,e] is
+ * contained in v=[v_s,v_e].
+ * \return A range pair. The first element of the
+ * range pair correspond to the original range
+ * mapped to the left child of v; the second element to the
+ * range mapped to the right child of v.
+ * \pre !is_leaf(v) and s>=v_s and e<=v_e
+ */
+ std::pair<range_type, range_type>
+ expand(const node_type& v, const range_type& r) const {
+ auto v_sp_rank = m_tree.bv_pos_rank(v);
+ auto sp_rank = m_bv_rank(m_tree.bv_pos(v) + r.first);
+ auto right_size = m_bv_rank(m_tree.bv_pos(v) + r.second + 1)
+ - sp_rank;
+ auto left_size = (r.second-r.first+1)-right_size;
+
+ auto right_sp = sp_rank - v_sp_rank;
+ auto left_sp = r.first - right_sp;
+
+ return make_pair(range_type(left_sp, left_sp + left_size - 1),
+ range_type(right_sp, right_sp + right_size - 1));
+ }
+
+ //! return the path to the leaf for a given symbol
+ std::pair<uint64_t,uint64_t> path(value_type c) const {
+ uint64_t path = m_tree.bit_path(c);
+ uint64_t path_len = path >> 56;
+ // reverse the path till we fix the ordering
+ path = bits::rev(path);
+ path = path >> (64-path_len); // remove the length
+ return {path_len,path};
+ }
+
+ //! Returns for a symbol c the next larger or equal symbol in the WT.
+ /*! \param c the symbol
+ * \return A pair. The first element of the pair consititues if
+ * a valid answer was found (true) or no valid answer (false)
+ * could be found. The second element contains the found symbol.
+ */
+ std::pair<bool, value_type> symbol_gte(value_type c) const {
+ return m_tree.symbol_gte(c);
+ }
+
+ //! Returns for a symbol c the previous smaller or equal symbol in the WT.
+ /*! \param c the symbol
+ * \return A pair. The first element of the pair consititues if
+ * a valid answer was found (true) or no valid answer (false)
+ * could be found. The second element contains the found symbol.
+ */
+ std::pair<bool, value_type> symbol_lte(value_type c) const {
+ return m_tree.symbol_lte(c);
+ }
+};
+
+}
+
+#endif
diff --git a/include/sdsl/wt_rlmn.hpp b/include/sdsl/wt_rlmn.hpp
new file mode 100644
index 0000000..d28d0d1
--- /dev/null
+++ b/include/sdsl/wt_rlmn.hpp
@@ -0,0 +1,438 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2011-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+/*! \file wt_rlmn.hpp
+ \brief wt_rlmn.hpp contains a class for a compressed wavelet tree.
+ Compression is achieved by exploiting runs in the input sequence.
+ \author Simon Gog
+*/
+#ifndef INCLUDED_SDSL_WT_RLMN
+#define INCLUDED_SDSL_WT_RLMN
+
+#include "sdsl_concepts.hpp"
+#include "int_vector.hpp"
+#include "sd_vector.hpp"// for standard initialisation of template parameters
+#include "util.hpp"
+#include "wt_huff.hpp"
+#include <algorithm> // for std::swap
+#include <stdexcept>
+#include <vector>
+#include <utility> // for pair
+#include <queue>
+#include <iostream>
+
+//! Namespace for the succinct data structure library.
+namespace sdsl
+{
+
+template<class t_alphabet_cat>
+struct wt_rlmn_trait {
+ enum { width = 0 };
+ typedef int_vector<> C_type;
+ typedef int_vector<> C_bf_rank_type;
+
+ static std::map<uint64_t,uint64_t> temp_C() {
+ return std::map<uint64_t, uint64_t>();
+ }
+
+ static C_type init_C(std::map<uint64_t,uint64_t>& C, uint64_t size) {
+ uint64_t max_symbol = (--C.end())->first;
+ return C_type(max_symbol+1, 0, bits::hi(size)+1);
+ }
+
+ static C_bf_rank_type init_C_bf_rank(const C_type& C, uint64_t size) {
+ return C_bf_rank_type(C.size(), 0, bits::hi(size)+1);
+ }
+};
+
+template<>
+struct wt_rlmn_trait<byte_alphabet_tag> {
+ enum {width = 8};
+ typedef int_vector<64> C_type;
+ typedef int_vector<64> C_bf_rank_type;
+
+ static int_vector<64> temp_C() {
+ return int_vector<64>(256, 0);
+ }
+
+ static C_type init_C(C_type& C, uint64_t) {
+ return C;
+ }
+
+ static C_bf_rank_type init_C_bf_rank(const C_type&, uint64_t) {
+ return int_vector<64>(256,0);
+ }
+};
+
+//! A Wavelet Tree class for byte sequences.
+/*!
+ * \par Space complexity
+ * \f$ nH_0 + 2|\Sigma|\log n + 2n + o(n) \f$ bits, where \f$n\f$
+ * is the size of the vector the wavelet tree was build for.
+ *
+ * @ingroup wt
+ *
+ * \tparam t_bitvector Type of the bitvector which is used to represent bf and
+ * bl which mark the head of each run in the original
+ * sequence.
+ * \tparam t_rank Type of the rank support for bitvectors bf and bl.
+ * \tparam t_select Type of the select support for bitvectors bf and lb.
+ * \tparam t_wt Type of the wavelet tree for the string consisting of
+ * the heads of the runs of the original sequence.
+ * \par Reference:
+ * Veli Mäkinen, Gonzalo Navarro:
+ * Succinct Suffix Arrays Based on Run-Length Encoding.
+ * CPM 2005: 45-56
+ */
+template<class t_bitvector = sd_vector<>,
+ class t_rank = typename t_bitvector::rank_1_type,
+ class t_select = typename t_bitvector::select_1_type,
+ class t_wt = wt_huff<> >
+class wt_rlmn
+{
+ public:
+
+ typedef t_wt wt_type;
+ typedef int_vector<>::size_type size_type;
+ typedef typename t_wt::value_type value_type;
+ typedef typename t_bitvector::difference_type difference_type;
+ typedef random_access_const_iterator<wt_rlmn> const_iterator;
+ typedef const_iterator iterator;
+ typedef t_bitvector bit_vector_type;
+ typedef t_rank rank_support_type;
+ typedef t_select select_support_type;
+ typedef wt_tag index_category;
+ typedef typename t_wt::alphabet_category alphabet_category;
+ enum { lex_ordered=false }; // TODO: is should be possible
+ enum { width = wt_rlmn_trait<alphabet_category>::width };
+ typedef typename wt_rlmn_trait<alphabet_category>::C_type
+ C_type;
+ typedef typename wt_rlmn_trait<alphabet_category>::C_bf_rank_type
+ C_bf_rank_type;
+ // to support all lex_ordered
+ // operations if t_wt::lex_ordered is
+ // true
+
+ private:
+
+ size_type m_size = 0; // size of the original input sequence
+ bit_vector_type m_bl; // bit vector for starts of runs in
+ // the BWT (or last column), i.e. _b_ _l_ast
+ bit_vector_type m_bf; // bit vector for starts of runs in
+ // the first column of the sorted suffixes, i.e _b_ _f_irst
+ wt_type m_wt; // wavelet tree for all levels
+ // two equal chars
+ rank_support_type m_bl_rank; // rank support for bit vector bl
+ rank_support_type m_bf_rank; // rank support for bit vector bf
+ select_support_type m_bl_select; // select support for bit vector bl
+ select_support_type m_bf_select; // select support for bit vector bf
+ C_type m_C; //
+ C_bf_rank_type m_C_bf_rank; // stores the number of 1s in m_bf for
+ // the prefixes m_bf[0..m_C[0]],m_bf[0..m_C[1]],....,m_bf[0..m_C[255]];
+ // named C_s in the original paper
+
+ void copy(const wt_rlmn& wt) {
+ m_size = wt.m_size;
+ m_bl = wt.m_bl;
+ m_bf = wt.m_bf;
+ m_wt = wt.m_wt;
+ m_bl_rank = wt.m_bl_rank;
+ m_bl_rank.set_vector(&m_bl);
+ m_bf_rank = wt.m_bf_rank;
+ m_bf_rank.set_vector(&m_bf);
+ m_bl_select = wt.m_bl_select;
+ m_bl_select.set_vector(&m_bl);
+ m_bf_select = wt.m_bf_select;
+ m_bf_select.set_vector(&m_bf);
+ m_C = wt.m_C;
+ m_C_bf_rank = wt.m_C_bf_rank;
+ }
+
+ public:
+
+ const size_type& sigma = m_wt.sigma;
+
+ // Default constructor
+ wt_rlmn() {};
+
+ //! Construct the wavelet tree from a file_buffer
+ /*! \param text_buf A int_vector_buffer to the original text.
+ * \param size The length of the prefix of the text, for which
+ * the wavelet tree should be build.
+ */
+ wt_rlmn(int_vector_buffer<width>& text_buf, size_type size):m_size(size) {
+ std::string temp_file = text_buf.filename() +
+ + "_wt_rlmn_" + util::to_string(util::pid())
+ + "_" + util::to_string(util::id());
+ {
+ if (0 == text_buf.size() or 0 == size)
+ return;
+ int_vector_buffer<width> condensed_wt(temp_file, std::ios::out);
+ // scope for bl and bf
+ bit_vector bl = bit_vector(size, 0);
+
+ auto C = wt_rlmn_trait<alphabet_category>::temp_C();
+ value_type last_c = (value_type)0;
+ for (size_type i=0; i < size; ++i) {
+ value_type c = text_buf[i];
+ if (last_c != c or i==0) {
+ bl[i] = 1;
+ condensed_wt.push_back(c);
+ }
+ ++C[c];
+ last_c = c;
+ }
+ condensed_wt.close();
+ m_C = wt_rlmn_trait<alphabet_category>::init_C(C, size);
+
+ for (size_type i=0, prefix_sum=0; i<m_C.size(); ++i) {
+ m_C[i] = prefix_sum;
+ prefix_sum += C[i];
+ }
+
+ C_type lf_map = m_C;
+ bit_vector bf = bit_vector(size+1, 0);
+ bf[size] = 1; // initialize last element
+ for (size_type i=0; i < size; ++i) {
+ value_type c = text_buf[i];
+ if (bl[i]) {
+ bf[lf_map[c]] = 1;
+ }
+ ++lf_map[c];
+ }
+ {
+ int_vector_buffer<width> temp_bwt_buf(temp_file);
+ m_wt = wt_type(temp_bwt_buf, temp_bwt_buf.size());
+ }
+ sdsl::remove(temp_file);
+ m_bl = bit_vector_type(std::move(bl));
+ m_bf = bit_vector_type(std::move(bf));
+ }
+
+ util::init_support(m_bl_rank, &m_bl);
+ util::init_support(m_bf_rank, &m_bf);
+ util::init_support(m_bf_select, &m_bf);
+ util::init_support(m_bl_select, &m_bl);
+
+ m_C_bf_rank = wt_rlmn_trait<alphabet_category>::init_C_bf_rank(m_C, size);
+ for (size_type i=0; i<m_C.size(); ++i) {
+ m_C_bf_rank[i] = m_bf_rank(m_C[i]);
+ }
+ }
+
+ //! Copy constructor
+ wt_rlmn(const wt_rlmn& wt) {
+ copy(wt);
+ }
+
+ //! Move constructor
+ wt_rlmn(wt_rlmn&& wt) {
+ *this = std::move(wt);
+ }
+
+ //! Assignment operator
+ wt_rlmn& operator=(const wt_rlmn& wt) {
+ if (this != &wt) {
+ copy(wt);
+ }
+ return *this;
+ }
+
+ //! Assignment move operator
+ wt_rlmn& operator=(wt_rlmn&& wt) {
+ if (this != &wt) {
+ m_size = std::move(wt.m_size);
+ m_bl = std::move(wt.m_bl);
+ m_bf = std::move(wt.m_bf);
+ m_wt = std::move(wt.m_wt);
+ m_bl_rank = std::move(wt.m_bl_rank);
+ m_bl_rank.set_vector(&m_bl);
+ m_bf_rank = std::move(wt.m_bf_rank);
+ m_bf_rank.set_vector(&m_bf);
+ m_bl_select = std::move(wt.m_bl_select);
+ m_bl_select.set_vector(&m_bl);
+ m_bf_select = std::move(wt.m_bf_select);
+ m_bf_select.set_vector(&m_bf);
+ m_C = std::move(wt.m_C);
+ m_C_bf_rank = std::move(wt.m_C_bf_rank);
+ }
+ return *this;
+ }
+
+ //! Swap operator
+ void swap(wt_rlmn& wt) {
+ if (this != &wt) {
+ std::swap(m_size, wt.m_size);
+ m_bl.swap(wt.m_bl);
+ m_bf.swap(wt.m_bf);
+ m_wt.swap(wt.m_wt);
+
+ m_bl_rank.swap(wt.m_bl_rank);
+ m_bl_rank.set_vector(&m_bl);
+ wt.m_bl_rank.set_vector(&(wt.m_bl));
+ m_bf_rank.swap(wt.m_bf_rank);
+ m_bf_rank.set_vector(&m_bf);
+ wt.m_bf_rank.set_vector(&(wt.m_bf));
+
+ m_bl_select.swap(wt.m_bl_select);
+ m_bl_select.set_vector(&m_bl);
+ wt.m_bl_select.set_vector(&(wt.m_bl));
+ m_bf_select.swap(wt.m_bf_select);
+ m_bf_select.set_vector(&m_bf);
+ wt.m_bf_select.set_vector(&(wt.m_bf));
+
+ m_C.swap(wt.m_C);
+ m_C_bf_rank.swap(wt.m_C_bf_rank);
+ }
+ }
+
+ //! Returns the size of the original vector.
+ size_type size()const {
+ return m_size;
+ }
+
+ //! Returns whether the wavelet tree contains no data.
+ bool empty()const {
+ return 0 == m_size;
+ }
+
+ //! Recovers the i-th symbol of the original vector.
+ /*! \param i Index in the original vector. \f$i \in [0..size()-1]\f$.
+ * \return The i-th symbol of the original vector.
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$ on average, where \f$ H_0 \f$ is the
+ * zero order entropy of the sequence
+ */
+ value_type operator[](size_type i)const {
+ assert(i < size());
+ return m_wt[m_bl_rank(i+1)-1];
+ };
+
+ //! Calculates how many symbols c are in the prefix [0..i-1].
+ /*!
+ * \param i Exclusive right bound of the range (\f$i\in[0..size()]\f$).
+ * \param c Symbol c.
+ * \return Number of occurrences of symbol c in the prefix [0..i-1].
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$ on average, where \f$ H_0 \f$ is the
+ * zero order entropy of the sequence
+ */
+ size_type rank(size_type i, value_type c)const {
+ assert(i <= size());
+ if (i == 0)
+ return 0;
+ size_type wt_ex_pos = m_bl_rank(i);
+ size_type c_runs = m_wt.rank(wt_ex_pos, c);
+ if (c_runs == 0)
+ return 0;
+ if (m_wt[wt_ex_pos-1] == c) {
+ size_type c_run_begin = m_bl_select(wt_ex_pos);
+ return m_bf_select(m_C_bf_rank[c]+c_runs)-m_C[c]+i-c_run_begin;
+ } else {
+ return m_bf_select(m_C_bf_rank[c] + c_runs + 1) - m_C[c];
+ }
+ };
+
+ //! Calculates how many times symbol wt[i] occurs in the prefix [0..i-1].
+ /*!
+ * \param i The index of the symbol.
+ * \return Pair (rank(wt[i],i),wt[i])
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$
+ */
+ std::pair<size_type, value_type>
+ inverse_select(size_type i)const {
+ assert(i < size());
+ if (i == 0) {
+ return std::make_pair(0, m_wt[0]);
+ }
+ size_type wt_ex_pos = m_bl_rank(i+1);
+ auto rc = m_wt.inverse_select(wt_ex_pos-1);
+ size_type c_runs = rc.first + 1;
+ value_type c = rc.second;
+ if (c_runs == 0)
+ return std::make_pair(0, c);
+ if (m_wt[wt_ex_pos-1] == c) {
+ size_type c_run_begin = m_bl_select(wt_ex_pos);
+ return std::make_pair(m_bf_select(m_C_bf_rank[c]+c_runs)-m_C[c]+i-c_run_begin, c);
+ } else {
+ return std::make_pair(m_bf_select(m_C_bf_rank[c]+c_runs+1)-m_C[c], c);
+ }
+ }
+
+ //! Calculates the ith occurrence of the symbol c in the supported vector.
+ /*!
+ * \param i The ith occurrence. \f$i\in [1..rank(size(),c)]\f$.
+ * \param c The symbol c.
+ * \par Time complexity
+ * \f$ \Order{H_0} \f$ on average, where \f$ H_0 \f$ is the zero order
+ * entropy of the sequence
+ */
+ size_type select(size_type i, value_type c)const {
+ assert(i > 0);
+ assert(i <= rank(size(), c));
+ size_type c_runs = m_bf_rank(m_C[c]+i) - m_C_bf_rank[c];
+ size_type offset = m_C[c]+i-1-m_bf_select(c_runs + m_C_bf_rank[c]);
+ return m_bl_select(m_wt.select(c_runs, c)+1) + offset;
+ };
+
+ //! Returns a const_iterator to the first element.
+ const_iterator begin()const {
+ return const_iterator(this, 0);
+ }
+
+ //! Returns a const_iterator to the element after the last element.
+ const_iterator end()const {
+ return const_iterator(this, size());
+ }
+
+ //! Serializes the data structure into the given ostream
+ size_type serialize(std::ostream& out, structure_tree_node* v=nullptr,
+ std::string name="")const {
+ structure_tree_node* child = structure_tree::add_child(
+ v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += write_member(m_size, out, child, "size");
+ written_bytes += m_bl.serialize(out, child, "bl");
+ written_bytes += m_bf.serialize(out, child, "bf");
+ written_bytes += m_wt.serialize(out, child, "wt");
+ written_bytes += m_bl_rank.serialize(out, child, "bl_rank");
+ written_bytes += m_bf_rank.serialize(out, child, "bf_rank");
+ written_bytes += m_bl_select.serialize(out, child, "bl_select");
+ written_bytes += m_bf_select.serialize(out, child, "bf_select");
+ written_bytes += m_C.serialize(out, child, "C");
+ written_bytes += m_C_bf_rank.serialize(out, child, "C_bf_rank");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+ }
+
+ //! Loads the data structure from the given istream.
+ void load(std::istream& in) {
+ read_member(m_size, in);
+ m_bl.load(in);
+ m_bf.load(in);
+ m_wt.load(in);
+ m_bl_rank.load(in, &m_bl);
+ m_bf_rank.load(in, &m_bf);
+ m_bl_select.load(in, &m_bl);
+ m_bf_select.load(in, &m_bf);
+ m_C.load(in);
+ m_C_bf_rank.load(in);
+ }
+};
+
+}// end namespace sdsl
+#endif
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..62867e6
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+# This script builds all dependencies of sdsl
+# and installs the library on a LINUX or Mac OS X system
+
+CUR_DIR=`pwd`
+SDSL_INSTALL_PREFIX=${HOME}
+if [ $# -ge 1 ]; then
+ SDSL_INSTALL_PREFIX=${1}
+fi
+
+# Get absolute path name of install directory
+mkdir -p "${SDSL_INSTALL_PREFIX}" 2> /dev/null
+cd "${SDSL_INSTALL_PREFIX}" > /dev/null 2>&1
+if [ $? != 0 ] ; then
+ echo "ERROR: directory '${SDSL_INSTALL_PREFIX}' does not exist nor could be created."
+ echo "Please choose another directory."
+ exit 1
+else
+ SDSL_INSTALL_PREFIX=`pwd -P`
+fi
+
+echo "Library will be installed in '${SDSL_INSTALL_PREFIX}'"
+
+cd "${CUR_DIR}"
+OLD_DIR="$( cd "$( dirname "$0" )" && pwd )" # gets the directory where the script is located in
+cd "${OLD_DIR}"
+OLD_DIR=`pwd`
+
+# (1) Copy pre-commit hook
+
+
+if [ -d ".git/hooks" ]; then
+ echo "Copy pre-commit into .git/hooks"
+ cp extras/pre-commit .git/hooks/
+ if [ $? != 0 ]; then
+ echo "WARNING: could not copy pre-commit script into .git/hooks"
+ fi
+ chmod u+x .git/hooks/pre-commit
+ if [ $? != 0 ]; then
+ echo "WARNING: could not make pre-commit script executable"
+ fi
+else
+ echo "WARNING: .git/hooks directory does not exists."
+ echo " The pre-commit hook is not installed."
+fi
+
+# (2) Install divsufsort, gtest, and sdsl
+
+HEADER=test/CompileTest.hpp # Make a header-file that contains all other header-files
+echo "#ifndef INCLUDED_SDSL_COMPILE_TEST" > ${HEADER}
+echo "#define INCLUDED_SDSL_COMPILE_TEST" >> ${HEADER}
+for HEADERFILE in include/sdsl/*.hpp
+do
+ FILENAME=`basename ${HEADERFILE}`
+ echo "#include \"sdsl/${FILENAME}\"" >> ${HEADER}
+done
+echo "#endif" >> ${HEADER}
+
+cd build # change into the build directory
+if [ $? != 0 ]; then
+ exit 1
+fi
+./clean.sh # clean-up build directory
+if [ $? != 0 ]; then
+ exit 1
+fi
+
+cmake -DCMAKE_INSTALL_PREFIX="${SDSL_INSTALL_PREFIX}" .. # run cmake
+if [ $? != 0 ]; then
+ echo "ERROR: CMake build failed."
+ exit 1
+fi
+make # run make
+if [ $? != 0 ]; then
+ echo "ERROR: Build failed."
+ exit 1
+fi
+echo "Removing old files"
+echo "rm -rf '${SDSL_INSTALL_PREFIX}/include/sdsl/*'"
+rm -rf "${SDSL_INSTALL_PREFIX}/include/sdsl/*"
+if [ $? != 0 ]; then
+ echo "WARNING: Could not remove old header files."
+fi
+echo "rm -f '${SDSL_INSTALL_PREFIX}/lib/libsdsl*'"
+rm -f "${SDSL_INSTALL_PREFIX}/lib/libsdsl*"
+if [ $? != 0 ]; then
+ echo "WARNING: Could not remove old library file."
+fi
+make install # install library
+if [ $? != 0 ]; then
+ echo "ERROR: Installation failed."
+ exit 1
+fi
+
+cd ..
+
+if [ "`pwd`" != "${OLD_DIR}" ]; then
+ echo "ERROR: we are not in the original dir ${OLD_DIR} now."
+ exit 1
+fi
+
+echo "SUCCESS: sdsl was installed successfully!"
+echo "The sdsl include files are located in '${SDSL_INSTALL_PREFIX}/include'."
+echo "The library files are located in '${SDSL_INSTALL_PREFIX}/lib'."
+echo " "
+echo "Sample programs can be found in the examples-directory."
+echo "A program 'example.cpp' can be compiled with the command: "
+echo "g++ -std=c++11 -DNDEBUG -O3 [-msse4.2] \\"
+echo " -I${SDSL_INSTALL_PREFIX}/include -L${SDSL_INSTALL_PREFIX}/lib \\"
+echo " example.cpp -lsdsl -ldivsufsort -ldivsufsort64"
+echo " "
+echo "Tests in the test-directory"
+echo "A cheat sheet in the extras/cheatsheet-directory."
+echo "Have fun!"
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644
index 0000000..32888b2
--- /dev/null
+++ b/lib/CMakeLists.txt
@@ -0,0 +1,23 @@
+include_directories(#"${CMAKE_CURRENT_SOURCE_DIR}/../include"
+ "${CMAKE_CURRENT_BINARY_DIR}/../include"
+ "${CMAKE_CURRENT_BINARY_DIR}/../external/libdivsufsort-2.0.1/include"
+ )
+
+
+file(GLOB libFiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") # select all .cpp-files
+
+set( sdsl_SRCS ${libFiles} )
+
+add_library( sdsl ${sdsl_SRCS} )
+
+install(TARGETS sdsl
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+
+set_target_properties(sdsl PROPERTIES
+ VERSION "${LIBRARY_VERSION_FULL}"
+ SOVERSION "${LIBRARY_VERSION_MAJOR}"
+# DEFINE_SYMBOL SDSL_BUILD_DLL
+# RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../examples"
+ )
diff --git a/lib/bits.cpp b/lib/bits.cpp
new file mode 100644
index 0000000..19bdfdf
--- /dev/null
+++ b/lib/bits.cpp
@@ -0,0 +1,562 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2008 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+#include "sdsl/bits.hpp"
+
+namespace sdsl
+{
+
+const uint8_t bits::lt_cnt[] = {
+ 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+
+
+const uint32_t bits::lt_deBruijn_to_idx[] = {
+ 0, 1, 2, 7, 3,13, 8,19,
+ 4,25,14,28, 9,34,20,40,
+ 5,17,26,38,15,46,29,48,
+ 10,31,35,54,21,50,41,57,
+ 63, 6,12,18,24,27,33,39,
+ 16,37,45,47,30,53,49,56,
+ 62,11,23,32,36,44,52,55,
+ 61,22,43,51,60,42,59,58
+};
+
+const uint32_t bits::lt_hi[] = {
+ 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+const uint64_t bits::lo_set[] = {
+ 0x0000000000000000ULL,
+ 0x0000000000000001ULL,
+ 0x0000000000000003ULL,
+ 0x0000000000000007ULL,
+ 0x000000000000000FULL,
+ 0x000000000000001FULL,
+ 0x000000000000003FULL,
+ 0x000000000000007FULL,
+ 0x00000000000000FFULL,
+ 0x00000000000001FFULL,
+ 0x00000000000003FFULL,
+ 0x00000000000007FFULL,
+ 0x0000000000000FFFULL,
+ 0x0000000000001FFFULL,
+ 0x0000000000003FFFULL,
+ 0x0000000000007FFFULL,
+ 0x000000000000FFFFULL,
+ 0x000000000001FFFFULL,
+ 0x000000000003FFFFULL,
+ 0x000000000007FFFFULL,
+ 0x00000000000FFFFFULL,
+ 0x00000000001FFFFFULL,
+ 0x00000000003FFFFFULL,
+ 0x00000000007FFFFFULL,
+ 0x0000000000FFFFFFULL,
+ 0x0000000001FFFFFFULL,
+ 0x0000000003FFFFFFULL,
+ 0x0000000007FFFFFFULL,
+ 0x000000000FFFFFFFULL,
+ 0x000000001FFFFFFFULL,
+ 0x000000003FFFFFFFULL,
+ 0x000000007FFFFFFFULL,
+ 0x00000000FFFFFFFFULL,
+ 0x00000001FFFFFFFFULL,
+ 0x00000003FFFFFFFFULL,
+ 0x00000007FFFFFFFFULL,
+ 0x0000000FFFFFFFFFULL,
+ 0x0000001FFFFFFFFFULL,
+ 0x0000003FFFFFFFFFULL,
+ 0x0000007FFFFFFFFFULL,
+ 0x000000FFFFFFFFFFULL,
+ 0x000001FFFFFFFFFFULL,
+ 0x000003FFFFFFFFFFULL,
+ 0x000007FFFFFFFFFFULL,
+ 0x00000FFFFFFFFFFFULL,
+ 0x00001FFFFFFFFFFFULL,
+ 0x00003FFFFFFFFFFFULL,
+ 0x00007FFFFFFFFFFFULL,
+ 0x0000FFFFFFFFFFFFULL,
+ 0x0001FFFFFFFFFFFFULL,
+ 0x0003FFFFFFFFFFFFULL,
+ 0x0007FFFFFFFFFFFFULL,
+ 0x000FFFFFFFFFFFFFULL,
+ 0x001FFFFFFFFFFFFFULL,
+ 0x003FFFFFFFFFFFFFULL,
+ 0x007FFFFFFFFFFFFFULL,
+ 0x00FFFFFFFFFFFFFFULL,
+ 0x01FFFFFFFFFFFFFFULL,
+ 0x03FFFFFFFFFFFFFFULL,
+ 0x07FFFFFFFFFFFFFFULL,
+ 0x0FFFFFFFFFFFFFFFULL,
+ 0x1FFFFFFFFFFFFFFFULL,
+ 0x3FFFFFFFFFFFFFFFULL,
+ 0x7FFFFFFFFFFFFFFFULL,
+ 0xFFFFFFFFFFFFFFFFULL
+};
+
+const uint64_t bits::lo_unset[] = {
+ 0xFFFFFFFFFFFFFFFFULL,
+ 0xFFFFFFFFFFFFFFFEULL,
+ 0xFFFFFFFFFFFFFFFCULL,
+ 0xFFFFFFFFFFFFFFF8ULL,
+ 0xFFFFFFFFFFFFFFF0ULL,
+ 0xFFFFFFFFFFFFFFE0ULL,
+ 0xFFFFFFFFFFFFFFC0ULL,
+ 0xFFFFFFFFFFFFFF80ULL,
+ 0xFFFFFFFFFFFFFF00ULL,
+ 0xFFFFFFFFFFFFFE00ULL,
+ 0xFFFFFFFFFFFFFC00ULL,
+ 0xFFFFFFFFFFFFF800ULL,
+ 0xFFFFFFFFFFFFF000ULL,
+ 0xFFFFFFFFFFFFE000ULL,
+ 0xFFFFFFFFFFFFC000ULL,
+ 0xFFFFFFFFFFFF8000ULL,
+ 0xFFFFFFFFFFFF0000ULL,
+ 0xFFFFFFFFFFFE0000ULL,
+ 0xFFFFFFFFFFFC0000ULL,
+ 0xFFFFFFFFFFF80000ULL,
+ 0xFFFFFFFFFFF00000ULL,
+ 0xFFFFFFFFFFE00000ULL,
+ 0xFFFFFFFFFFC00000ULL,
+ 0xFFFFFFFFFF800000ULL,
+ 0xFFFFFFFFFF000000ULL,
+ 0xFFFFFFFFFE000000ULL,
+ 0xFFFFFFFFFC000000ULL,
+ 0xFFFFFFFFF8000000ULL,
+ 0xFFFFFFFFF0000000ULL,
+ 0xFFFFFFFFE0000000ULL,
+ 0xFFFFFFFFC0000000ULL,
+ 0xFFFFFFFF80000000ULL,
+ 0xFFFFFFFF00000000ULL,
+ 0xFFFFFFFE00000000ULL,
+ 0xFFFFFFFC00000000ULL,
+ 0xFFFFFFF800000000ULL,
+ 0xFFFFFFF000000000ULL,
+ 0xFFFFFFE000000000ULL,
+ 0xFFFFFFC000000000ULL,
+ 0xFFFFFF8000000000ULL,
+ 0xFFFFFF0000000000ULL,
+ 0xFFFFFE0000000000ULL,
+ 0xFFFFFC0000000000ULL,
+ 0xFFFFF80000000000ULL,
+ 0xFFFFF00000000000ULL,
+ 0xFFFFE00000000000ULL,
+ 0xFFFFC00000000000ULL,
+ 0xFFFF800000000000ULL,
+ 0xFFFF000000000000ULL,
+ 0xFFFE000000000000ULL,
+ 0xFFFC000000000000ULL,
+ 0xFFF8000000000000ULL,
+ 0xFFF0000000000000ULL,
+ 0xFFE0000000000000ULL,
+ 0xFFC0000000000000ULL,
+ 0xFF80000000000000ULL,
+ 0xFF00000000000000ULL,
+ 0xFE00000000000000ULL,
+ 0xFC00000000000000ULL,
+ 0xF800000000000000ULL,
+ 0xF000000000000000ULL,
+ 0xE000000000000000ULL,
+ 0xC000000000000000ULL,
+ 0x8000000000000000ULL,
+ 0x0000000000000000ULL
+};
+
+const uint64_t bits::ps_overflow[] = {
+ 0x8080808080808080ULL,
+ 0x7f7f7f7f7f7f7f7fULL,
+ 0x7e7e7e7e7e7e7e7eULL,
+ 0x7d7d7d7d7d7d7d7dULL,
+ 0x7c7c7c7c7c7c7c7cULL,
+ 0x7b7b7b7b7b7b7b7bULL,
+ 0x7a7a7a7a7a7a7a7aULL,
+ 0x7979797979797979ULL,
+ 0x7878787878787878ULL,
+ 0x7777777777777777ULL,
+ 0x7676767676767676ULL,
+ 0x7575757575757575ULL,
+ 0x7474747474747474ULL,
+ 0x7373737373737373ULL,
+ 0x7272727272727272ULL,
+ 0x7171717171717171ULL,
+ 0x7070707070707070ULL,
+ 0x6f6f6f6f6f6f6f6fULL,
+ 0x6e6e6e6e6e6e6e6eULL,
+ 0x6d6d6d6d6d6d6d6dULL,
+ 0x6c6c6c6c6c6c6c6cULL,
+ 0x6b6b6b6b6b6b6b6bULL,
+ 0x6a6a6a6a6a6a6a6aULL,
+ 0x6969696969696969ULL,
+ 0x6868686868686868ULL,
+ 0x6767676767676767ULL,
+ 0x6666666666666666ULL,
+ 0x6565656565656565ULL,
+ 0x6464646464646464ULL,
+ 0x6363636363636363ULL,
+ 0x6262626262626262ULL,
+ 0x6161616161616161ULL,
+ 0x6060606060606060ULL,
+ 0x5f5f5f5f5f5f5f5fULL,
+ 0x5e5e5e5e5e5e5e5eULL,
+ 0x5d5d5d5d5d5d5d5dULL,
+ 0x5c5c5c5c5c5c5c5cULL,
+ 0x5b5b5b5b5b5b5b5bULL,
+ 0x5a5a5a5a5a5a5a5aULL,
+ 0x5959595959595959ULL,
+ 0x5858585858585858ULL,
+ 0x5757575757575757ULL,
+ 0x5656565656565656ULL,
+ 0x5555555555555555ULL,
+ 0x5454545454545454ULL,
+ 0x5353535353535353ULL,
+ 0x5252525252525252ULL,
+ 0x5151515151515151ULL,
+ 0x5050505050505050ULL,
+ 0x4f4f4f4f4f4f4f4fULL,
+ 0x4e4e4e4e4e4e4e4eULL,
+ 0x4d4d4d4d4d4d4d4dULL,
+ 0x4c4c4c4c4c4c4c4cULL,
+ 0x4b4b4b4b4b4b4b4bULL,
+ 0x4a4a4a4a4a4a4a4aULL,
+ 0x4949494949494949ULL,
+ 0x4848484848484848ULL,
+ 0x4747474747474747ULL,
+ 0x4646464646464646ULL,
+ 0x4545454545454545ULL,
+ 0x4444444444444444ULL,
+ 0x4343434343434343ULL,
+ 0x4242424242424242ULL,
+ 0x4141414141414141ULL,
+ 0x4040404040404040ULL
+};
+
+const uint8_t bits::lt_sel[] = {
+ 0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+
+ 0,0,0,1,0,2,2,1,0,3,3,1,3,2,2,1,
+ 0,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 0,5,5,1,5,2,2,1,5,3,3,1,3,2,2,1,
+ 5,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 0,6,6,1,6,2,2,1,6,3,3,1,3,2,2,1,
+ 6,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 6,5,5,1,5,2,2,1,5,3,3,1,3,2,2,1,
+ 5,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 0,7,7,1,7,2,2,1,7,3,3,1,3,2,2,1,
+ 7,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 7,5,5,1,5,2,2,1,5,3,3,1,3,2,2,1,
+ 5,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 7,6,6,1,6,2,2,1,6,3,3,1,3,2,2,1,
+ 6,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+ 6,5,5,1,5,2,2,1,5,3,3,1,3,2,2,1,
+ 5,4,4,1,4,2,2,1,4,3,3,1,3,2,2,1,
+
+ 0,0,0,0,0,0,0,2,0,0,0,3,0,3,3,2,
+ 0,0,0,4,0,4,4,2,0,4,4,3,4,3,3,2,
+ 0,0,0,5,0,5,5,2,0,5,5,3,5,3,3,2,
+ 0,5,5,4,5,4,4,2,5,4,4,3,4,3,3,2,
+ 0,0,0,6,0,6,6,2,0,6,6,3,6,3,3,2,
+ 0,6,6,4,6,4,4,2,6,4,4,3,4,3,3,2,
+ 0,6,6,5,6,5,5,2,6,5,5,3,5,3,3,2,
+ 6,5,5,4,5,4,4,2,5,4,4,3,4,3,3,2,
+ 0,0,0,7,0,7,7,2,0,7,7,3,7,3,3,2,
+ 0,7,7,4,7,4,4,2,7,4,4,3,4,3,3,2,
+ 0,7,7,5,7,5,5,2,7,5,5,3,5,3,3,2,
+ 7,5,5,4,5,4,4,2,5,4,4,3,4,3,3,2,
+ 0,7,7,6,7,6,6,2,7,6,6,3,6,3,3,2,
+ 7,6,6,4,6,4,4,2,6,4,4,3,4,3,3,2,
+ 7,6,6,5,6,5,5,2,6,5,5,3,5,3,3,2,
+ 6,5,5,4,5,4,4,2,5,4,4,3,4,3,3,2,
+
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,
+ 0,0,0,0,0,0,0,4,0,0,0,4,0,4,4,3,
+ 0,0,0,0,0,0,0,5,0,0,0,5,0,5,5,3,
+ 0,0,0,5,0,5,5,4,0,5,5,4,5,4,4,3,
+ 0,0,0,0,0,0,0,6,0,0,0,6,0,6,6,3,
+ 0,0,0,6,0,6,6,4,0,6,6,4,6,4,4,3,
+ 0,0,0,6,0,6,6,5,0,6,6,5,6,5,5,3,
+ 0,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,3,
+ 0,0,0,7,0,7,7,4,0,7,7,4,7,4,4,3,
+ 0,0,0,7,0,7,7,5,0,7,7,5,7,5,5,3,
+ 0,7,7,5,7,5,5,4,7,5,5,4,5,4,4,3,
+ 0,0,0,7,0,7,7,6,0,7,7,6,7,6,6,3,
+ 0,7,7,6,7,6,6,4,7,6,6,4,6,4,4,3,
+ 0,7,7,6,7,6,6,5,7,6,6,5,6,5,5,3,
+ 7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
+
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
+ 0,0,0,0,0,0,0,5,0,0,0,5,0,5,5,4,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+ 0,0,0,0,0,0,0,6,0,0,0,6,0,6,6,4,
+ 0,0,0,0,0,0,0,6,0,0,0,6,0,6,6,5,
+ 0,0,0,6,0,6,6,5,0,6,6,5,6,5,5,4,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,4,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,5,
+ 0,0,0,7,0,7,7,5,0,7,7,5,7,5,5,4,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,6,
+ 0,0,0,7,0,7,7,6,0,7,7,6,7,6,6,4,
+ 0,0,0,7,0,7,7,6,0,7,7,6,7,6,6,5,
+ 0,7,7,6,7,6,6,5,7,6,6,5,6,5,5,4,
+
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+ 0,0,0,0,0,0,0,6,0,0,0,6,0,6,6,5,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,5,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,6,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,6,
+ 0,0,0,7,0,7,7,6,0,7,7,6,7,6,6,5,
+
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,
+ 0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,6,
+
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7
+};
+
+const uint64_t bits::lt_fib[] = {
+ 1,
+ 2,
+ 3,
+ 5,
+ 8,
+ 13,
+ 21,
+ 34,
+ 55,
+ 89,
+ 144,
+ 233,
+ 377,
+ 610,
+ 987,
+ 1597,
+ 2584,
+ 4181,
+ 6765,
+ 10946,
+ 17711,
+ 28657,
+ 46368,
+ 75025,
+ 121393,
+ 196418,
+ 317811,
+ 514229,
+ 832040,
+ 1346269,
+ 2178309,
+ 3524578,
+ 5702887,
+ 9227465,
+ 14930352,
+ 24157817,
+ 39088169,
+ 63245986,
+ 102334155,
+ 165580141,
+ 267914296,
+ 433494437,
+ 701408733,
+ 1134903170,
+ 1836311903,
+ 2971215073ULL,
+ 0x11e8d0a40ULL,
+ 0x1cfa62f21ULL,
+ 0x2ee333961ULL,
+ 0x4bdd96882ULL,
+ 0x7ac0ca1e3ULL,
+ 0xc69e60a65ULL,
+ 0x1415f2ac48ULL,
+ 0x207fd8b6adULL,
+ 0x3495cb62f5ULL,
+ 0x5515a419a2ULL,
+ 0x89ab6f7c97ULL,
+ 0xdec1139639ULL,
+ 0x1686c8312d0ULL,
+ 0x2472d96a909ULL,
+ 0x3af9a19bbd9ULL,
+ 0x5f6c7b064e2ULL,
+ 0x9a661ca20bbULL,
+ 0xf9d297a859dULL,
+ 0x19438b44a658ULL,
+ 0x28e0b4bf2bf5ULL,
+ 0x42244003d24dULL,
+ 0x6b04f4c2fe42ULL,
+ 0xad2934c6d08fULL,
+ 0x1182e2989ced1ULL,
+ 0x1c5575e509f60ULL,
+ 0x2dd8587da6e31ULL,
+ 0x4a2dce62b0d91ULL,
+ 0x780626e057bc2ULL,
+ 0xc233f54308953ULL,
+ 0x13a3a1c2360515ULL,
+ 0x1fc6e116668e68ULL,
+ 0x336a82d89c937dULL,
+ 0x533163ef0321e5ULL,
+ 0x869be6c79fb562ULL,
+ 0xd9cd4ab6a2d747ULL,
+ 0x16069317e428ca9ULL,
+ 0x23a367c34e563f0ULL,
+ 0x39a9fadb327f099ULL,
+ 0x5d4d629e80d5489ULL,
+ 0x96f75d79b354522ULL,
+ 0xf444c01834299abULL,
+ 0x18b3c1d91e77decdULL,
+ 0x27f80ddaa1ba7878ULL,
+ 0x40abcfb3c0325745ULL,
+ 0x68a3dd8e61eccfbdULL,
+ 0xa94fad42221f2702ULL
+};
+
+const uint8_t bits::lt_lo[]= {
+ 0x00,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x05,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x06,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x05,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x07,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x05,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x06,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x05,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x04,0x00,0x01,0x00,0x02,0x00,0x01,0x00,
+ 0x03,0x00,0x01,0x00,0x02,0x00,0x01,0x00
+};
+
+} // end namespace sdsl
+
diff --git a/lib/bp_support_algorithm.cpp b/lib/bp_support_algorithm.cpp
new file mode 100644
index 0000000..40a9a0c
--- /dev/null
+++ b/lib/bp_support_algorithm.cpp
@@ -0,0 +1,443 @@
+#include "sdsl/bp_support_algorithm.hpp"
+
+namespace sdsl
+{
+excess::impl excess::data;
+
+bit_vector
+calculate_pioneers_bitmap(const bit_vector& bp, uint64_t block_size)
+{
+ bit_vector pioneer_bitmap(bp.size(), 0);
+
+ std::stack<uint64_t> opening_parenthesis;
+ uint64_t blocks = (bp.size()+block_size-1)/block_size;
+ // calculate positions of findclose and findopen pioneers
+ for (uint64_t block_nr = 0; block_nr < blocks; ++block_nr) {
+ std::map<uint64_t, uint64_t> block_and_position; // for find_open and find_close
+ std::map<uint64_t, uint64_t> matching_position; // for find_open and find_close
+ for (uint64_t i=0, j=block_nr*block_size; i < block_size and j < bp.size(); ++i, ++j) {
+ if (bp[j]) {//opening parenthesis
+ opening_parenthesis.push(j);
+ } else { // closing parenthesis
+ uint64_t position = opening_parenthesis.top();
+ uint64_t blockpos = position/block_size;
+ opening_parenthesis.pop();
+ block_and_position[blockpos] = position;
+ matching_position[blockpos] = j; // greatest j is pioneer
+ }
+ }
+ for (std::map<uint64_t, uint64_t>::const_iterator it = block_and_position.begin(),
+ end = block_and_position.end(),
+ mit = matching_position.begin(); it != end and it->first != block_nr; ++it, ++mit) {
+ // opening and closing pioneers are symmetric
+ pioneer_bitmap[it->second] = 1;
+ pioneer_bitmap[mit->second] = 1;
+ }
+ }
+ // assert that the sequence is balanced
+ assert(opening_parenthesis.empty());
+ return pioneer_bitmap;
+}
+
+bit_vector
+calculate_pioneers_bitmap_succinct(const bit_vector& bp, uint64_t block_size)
+{
+ bit_vector pioneer_bitmap(bp.size(), 0);
+
+ sorted_stack_support opening_parenthesis(bp.size());
+ uint64_t cur_pioneer_block = 0, last_start = 0, last_j = 0, cur_block=0, first_index_in_block=0;
+ // calculate positions of findclose and findopen pioneers
+ for (uint64_t j=0, new_block=block_size; j < bp.size(); ++j, --new_block) {
+ if (!(new_block)) {
+ cur_pioneer_block = j/block_size;
+ ++cur_block;
+ first_index_in_block = j;
+ new_block = block_size;
+ }
+
+ if (bp[j]) { // opening parenthesis
+ if (/*j < bp.size() is not necessary as the last parenthesis is always a closing one*/
+ new_block>1 and !bp[j+1]) {
+ ++j; --new_block;
+ continue;
+ }
+ opening_parenthesis.push(j);
+ } else {
+ assert(!opening_parenthesis.empty());
+ uint64_t start = opening_parenthesis.top();
+ opening_parenthesis.pop();
+ if (start < first_index_in_block) {
+ if ((start/block_size)==cur_pioneer_block) {
+ pioneer_bitmap[last_start] = pioneer_bitmap[last_j] = 0; // override false pioneer
+ }
+ pioneer_bitmap[start] = pioneer_bitmap[j] = 1;
+ cur_pioneer_block = start/block_size;
+ last_start = start;
+ last_j = j;
+ }
+ }
+ }
+ // assert that the sequence is balanced
+ assert(opening_parenthesis.empty());
+ return pioneer_bitmap;
+}
+
+uint64_t
+near_find_close(const bit_vector& bp, const uint64_t i,
+ const uint64_t block_size)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type excess=1;
+
+ const uint64_t end = ((i+1)/block_size+1)*block_size;
+ const uint64_t l = (((i+1)+7)/8)*8;
+ const uint64_t r = (end/8)*8;
+ for (uint64_t j=i+1; j < std::min(end,l); ++j) {
+ if (bp[j])
+ ++excess;
+ else {
+ --excess;
+ if (excess == 0) {
+ return j;
+ }
+ }
+ }
+ const uint64_t* b = bp.data();
+ for (uint64_t j=l; j<r; j+=8) {
+ if (excess <= 8) {
+ assert(excess>0);
+ uint32_t x = excess::data.min_match_pos_packed[((*(b+(j>>6)))>>(j&0x3F))&0xFF ];
+ uint8_t p = (x >> ((excess-1)<<2))&0xF;
+ if (p < 9) {
+ return j+p;
+ }
+ }
+ excess += excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF ];
+ }
+ for (uint64_t j=std::max(l,r); j < end; ++j) {
+ if (bp[j])
+ ++excess;
+ else {
+ --excess;
+ if (excess == 0) {
+ return j;
+ }
+ }
+ }
+ return i;
+}
+
+uint64_t
+near_find_closing(const bit_vector& bp, uint64_t i,
+ uint64_t closings,
+ const uint64_t block_size)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type excess=0;
+ difference_type succ_excess=-closings;
+
+ const uint64_t end = (i/block_size+1)*block_size;
+ const uint64_t l = (((i)+7)/8)*8;
+ const uint64_t r = (end/8)*8;
+ for (uint64_t j=i; j < std::min(end,l); ++j) {
+ if (bp[j])
+ ++excess;
+ else {
+ --excess;
+ if (excess == succ_excess) {
+ return j;
+ }
+ }
+ }
+ const uint64_t* b = bp.data();
+ for (uint64_t j=l; j<r; j+=8) {
+ if (excess-succ_excess <= 8) {
+ uint32_t x = excess::data.min_match_pos_packed[((*(b+(j>>6)))>>(j&0x3F))&0xFF ];
+ uint8_t p = (x >> (((excess-succ_excess)-1)<<2))&0xF;
+ if (p < 9) {
+ return j+p;
+ }
+ }
+ excess += excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF ];
+ }
+ for (uint64_t j=std::max(l,r); j < end; ++j) {
+ if (bp[j])
+ ++excess;
+ else {
+ --excess;
+ if (excess == succ_excess) {
+ return j;
+ }
+ }
+ }
+ return i-1;
+}
+
+uint64_t
+near_fwd_excess(const bit_vector& bp, uint64_t i, bit_vector::difference_type rel, const uint64_t block_size)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type excess = rel;
+
+ const uint64_t end = (i/block_size+1)*block_size;
+ const uint64_t l = (((i)+7)/8)*8;
+ const uint64_t r = (end/8)*8;
+ for (uint64_t j=i; j < std::min(end,l); ++j) {
+ excess += 1-2*bp[j];
+ if (!excess) {
+ return j;
+ }
+ }
+ excess += 8;
+ const uint64_t* b = bp.data();
+ for (uint64_t j=l; j < r; j+=8) {
+ if (excess >= 0 and excess <= 16) {
+ uint32_t x = excess::data.near_fwd_pos[(excess<<8) + (((*(b+(j>>6)))>>(j&0x3F))&0xFF) ];
+ if (x < 8) {
+ return j+x;
+ }
+ }
+ excess -= excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF ];
+ }
+ excess -= 8;
+ for (uint64_t j=std::max(l,r); j < end; ++j) {
+ excess += 1-2*bp[j];
+ if (!excess) {
+ return j;
+ }
+ }
+ return i-1;
+}
+
+uint64_t
+near_rmq(const bit_vector& bp, uint64_t l, uint64_t r, bit_vector::difference_type& min_rel_ex)
+{
+ typedef bit_vector::difference_type difference_type;
+ const uint64_t l8 = (((l+1)+7)/8)*8;
+ const uint64_t r8 = (r/8)*8;
+ difference_type excess = 0;
+ difference_type min_pos=l;
+ min_rel_ex = 0;
+ for (uint64_t j=l+1; j < std::min(l8,r+1); ++j) {
+ if (bp[j])
+ ++excess;
+ else {
+ --excess;
+ if (excess <= min_rel_ex) {
+ min_rel_ex = excess;
+ min_pos = j;
+ }
+ }
+ }
+
+ const uint64_t* b = bp.data();
+ for (uint64_t j=l8; j < r8; j+=8) {
+ int8_t x = excess::data.min[(((*(b+(j>>6)))>>(j&0x3F))&0xFF)];
+ if ((excess+x) <= min_rel_ex) {
+ min_rel_ex = excess+x;
+ min_pos = j + excess::data.min_pos_max[(((*(b+(j>>6)))>>(j&0x3F))&0xFF)];
+ }
+ excess += excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF];
+ }
+ for (uint64_t j=std::max(l8,r8); j<r+1; ++j) {
+ if (bp[j])
+ ++excess;
+ else {
+ --excess;
+ if (excess <= min_rel_ex) {
+ min_rel_ex = excess;
+ min_pos = j;
+ }
+ }
+ }
+ return min_pos;
+}
+
+uint64_t
+near_bwd_excess(const bit_vector& bp, uint64_t i, bit_vector::difference_type rel, const uint64_t block_size)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type excess = rel;
+ const difference_type begin = ((difference_type)(i)/block_size)*block_size;
+ const difference_type r = ((difference_type)(i)/8)*8;
+ const difference_type l = ((difference_type)((begin+7)/8))*8;
+ for (difference_type j=i+1; j >= /*begin*/std::max(r,begin); --j) {
+ if (bp[j])
+ ++excess;
+ else
+ --excess;
+ if (!excess) return j-1;
+ }
+
+ excess += 8;
+ const uint64_t* b = bp.data();
+ for (difference_type j=r-8; j >= l; j-=8) {
+ if (excess >= 0 and excess <= 16) {
+ uint32_t x = excess::data.near_bwd_pos[(excess<<8) + (((*(b+(j>>6)))>>(j&0x3F))&0xFF)];
+ if (x < 8) {
+ return j+x-1;
+ }
+ }
+ excess += excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF];
+ }
+ excess -= 8;
+ for (difference_type j=std::min(l, r); j > begin; --j) {
+ if (bp[j])
+ ++excess;
+ else
+ --excess;
+ if (!excess) return j-1;
+ }
+ if (0==begin and -1==rel) {
+ return -1;
+ }
+ return i+1;
+}
+
+uint64_t
+near_find_open(const bit_vector& bp, uint64_t i, const uint64_t block_size)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type excess = -1;
+ const difference_type begin = ((difference_type)(i-1)/block_size)*block_size;
+ const difference_type r = ((difference_type)(i-1)/8)*8;
+ const difference_type l = ((difference_type)((begin+7)/8))*8;
+ for (difference_type j=i-1; j >= std::max(r,begin); --j) {
+ if (bp[j]) {
+ if (++excess == 0) {
+ return j;
+ }
+ } else
+ --excess;
+ }
+ const uint64_t* b = bp.data();
+ for (difference_type j=r-8; j >= l; j-=8) {
+ if (excess >= -8) {
+ assert(excess<0);
+ uint32_t x = excess::data.max_match_pos_packed[((*(b+(j>>6)))>>(j&0x3F))&0xFF];
+ uint8_t p = (x >> ((-excess-1)<<2))&0xF;
+ if (p < 9) {
+ return j+p;
+ }
+ }
+ excess += excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF];
+ }
+ for (difference_type j=std::min(l, r)-1; j >= begin; --j) {
+ if (bp[j]) {
+ if (++excess == 0) {
+ return j;
+ }
+ } else
+ --excess;
+ }
+ return i;
+}
+
+
+uint64_t
+near_find_opening(const bit_vector& bp, uint64_t i, const uint64_t openings,const uint64_t block_size)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type excess = 0;
+ difference_type succ_excess = openings;
+
+ const difference_type begin = ((difference_type)(i)/block_size)*block_size;
+ const difference_type r = ((difference_type)(i)/8)*8;
+ const difference_type l = ((difference_type)((begin+7)/8))*8;
+ for (difference_type j=i; j >= std::max(r,begin); --j) {
+ if (bp[j]) {
+ if (++excess == succ_excess) {
+ return j;
+ }
+ } else
+ --excess;
+ }
+ const uint64_t* b = bp.data();
+ for (difference_type j=r-8; j >= l; j-=8) {
+ if (succ_excess-excess <= 8) {
+ assert(succ_excess-excess>0);
+ uint32_t x = excess::data.max_match_pos_packed[((*(b+(j>>6)))>>(j&0x3F))&0xFF];
+ uint8_t p = (x >> ((succ_excess-excess-1)<<2))&0xF;
+ if (p < 9) {
+ return j+p;
+ }
+ }
+ excess += excess::data.word_sum[((*(b+(j>>6)))>>(j&0x3F))&0xFF];
+ }
+ for (difference_type j=std::min(l, r)-1; j >= begin; --j) {
+ if (bp[j]) {
+ if (++excess == succ_excess) {
+ return j;
+ }
+ } else
+ --excess;
+ }
+ return i+1;
+}
+
+uint64_t
+near_enclose(const bit_vector& bp, uint64_t i, const uint64_t block_size)
+{
+ uint64_t opening_parentheses = 1;
+ for (uint64_t j=i; j+block_size-1 > i and j>0; --j) {
+ if (bp[j-1]) {
+ ++opening_parentheses;
+ if (opening_parentheses == 2) {
+ return j-1;
+ }
+ } else
+ --opening_parentheses;
+ }
+ return i;
+}
+
+uint64_t
+near_rmq_open(const bit_vector& bp, const uint64_t begin, const uint64_t end)
+{
+ typedef bit_vector::difference_type difference_type;
+ difference_type min_excess = end-begin+1, ex = 0;
+ uint64_t result = end;
+
+ const uint64_t l = ((begin+7)/8)*8;
+ const uint64_t r = (end/8)*8;
+
+ for (uint64_t k=begin; k < std::min(end,l); ++k) {
+ if (bp[k]) {
+ ++ex;
+ if (ex <= min_excess) {
+ result = k;
+ min_excess = ex;
+ }
+ } else {
+ --ex;
+ }
+ }
+ const uint64_t* b = bp.data();
+ for (uint64_t k = l; k < r; k+=8) {
+ uint16_t x = excess::data.min_open_excess_info[((*(b+(k>>6)))>>(k&0x3F))&0xFF];
+ int8_t ones = (x>>12);
+ if (ones) {
+ int8_t min_ex = (x&0xFF)-8;
+ if (ex+min_ex <= min_excess) {
+ result = k + ((x>>8)&0xF);
+ min_excess = ex+min_ex;
+ }
+ }
+ ex += ((ones<<1)-8);
+ }
+ for (uint64_t k=std::max(r,l); k < end; ++k) {
+ if (bp[k]) {
+ ++ex;
+ if (ex <= min_excess) {
+ result = k;
+ min_excess = ex;
+ }
+ } else {
+ --ex;
+ }
+ }
+ if (min_excess <= ex)
+ return result;
+ return end;
+}
+}
diff --git a/lib/coder_elias_delta.cpp b/lib/coder_elias_delta.cpp
new file mode 100644
index 0000000..ccc445c
--- /dev/null
+++ b/lib/coder_elias_delta.cpp
@@ -0,0 +1,297 @@
+#include "sdsl/coder_elias_delta.hpp"
+
+namespace sdsl
+{
+
+namespace coder
+{
+
+elias_delta::impl elias_delta::data;
+
+uint64_t elias_delta::decode_prefix_sum(const uint64_t* data, const size_type start_idx, const size_type end_idx, size_type n)
+{
+ if (n==0)
+ return 0;
+ const uint64_t* lastdata = data + ((end_idx+63) >> 6);
+ data += (start_idx >> 6);
+ uint64_t w = 0, value = 0;
+ int16_t buffered = 0, read = start_idx & 0x3F;
+ size_type i = 0;
+ if (n + read <= 64) {
+ if (((*data >> read)&bits::lo_set[n]) == bits::lo_set[n])
+ return n;
+ } else { // n+read > 64
+ if ((*data >> read) == bits::lo_set[64-read]) {// all bits are set to 1
+ value = 64-read;
+ ++data;
+ n -= (64-read);
+ read = 0;
+ while (n >= 64) {
+ if (*data == 0xFFFFFFFFFFFFFFFFULL) {
+ value += 64;
+ ++data;
+ n -= 64;
+ } else
+ goto start_decoding;
+ }
+ // 0 <= n <= 64
+ if ((*data&bits::lo_set[n]) == bits::lo_set[n])
+ return value + n;
+ }
+ }
+
+start_decoding:
+ while (i<n) {
+ while (buffered < 64 and data < lastdata) {
+fill_buffer:
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else { // read buffered
+ read += 64-buffered;
+ buffered = 64;
+ }
+ }
+ /* if(w==0xFFFFFFFFFFFFFFFFULL){
+ i += 64;
+ value += 64;
+ if(i >= n)
+ return value - (i-n);
+ buffered = 0;
+ w = 0;
+ // continue;
+ goto fill_buffer;
+ }
+ */
+// uint32_t rbp = (w == 0xFFFFFFFFFFFFFFFFULL)?64:bits::lo(~w);
+ uint32_t rbp = bits::lo(~w);
+ if (rbp > 0) {
+ i += rbp;
+ value += rbp;
+ if (i >= n) { // decoded too much
+ return value - (i-n); // return corrected value
+ }
+ assert(buffered >= rbp);
+ buffered -= rbp;
+ w >>= rbp;
+ if (buffered<16)
+// continue;
+ goto fill_buffer;
+ }
+// assert(w!=0xFFFFFFFFFFFFFFFFULL);
+// else
+ {
+ // i < n
+begin_decode:
+ uint32_t psum = elias_delta::data.prefixsum[w&0x0000FFFF];
+ if (!psum or i+((psum>>16)&0x00FF) > n) {
+ if (w==0) {// buffer is not full
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ if (!w) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ }
+ }
+// assert(w>0);
+ uint16_t len_1_len = bits::lo(w); // read length of length
+ buffered -= (len_1_len+1);
+ w >>= (len_1_len+1);
+ if (len_1_len > buffered) {// buffer is not full
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ if (len_1_len > buffered) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ }
+ }
+// assert(len_1_len <= buffered);
+ uint16_t len_1 = (w&bits::lo_set[len_1_len]) + (1ULL << len_1_len) - 1;
+ buffered -= len_1_len;
+ w >>= len_1_len;
+ if (len_1 > buffered) {// buffer is not full
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ if (len_1 > buffered) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ }
+ }
+// if( len_1 > buffered ){
+// std::cerr<<"len_1="<<len_1<<" buffered = "<<buffered<<std::endl;
+// }
+// assert(len_1 <= buffered);
+ value += (w&bits::lo_set[len_1]) + (len_1<64) * (1ULL << (len_1));
+ buffered -= len_1;
+ if (len_1 < 64) {
+ w >>= len_1;
+ } else {
+ w = 0;
+ }
+ ++i;
+ if (i==n)
+ return value;
+ if (buffered>=16)
+ goto begin_decode;
+ } else {
+ value += (psum&0x0000FFFF);
+ i += ((psum>>16)&0x00FF);
+ if (i==n)
+ return value;
+ buffered -= (psum>>24);
+ w >>= (psum>>24);
+ if (buffered>=16)
+ goto begin_decode;
+ }
+ }
+// std::cerr<<i<<" / "<<n<<std::endl;
+ };
+// std::cerr<<value<<std::endl;
+ return value;
+}
+
+
+uint64_t elias_delta::decode_prefix_sum(const uint64_t* data, const size_type start_idx, size_type n)
+{
+ if (n==0)
+ return 0;
+ data += (start_idx >> 6);
+ uint64_t value = 0;
+ size_type i = 0;
+ uint8_t offset = start_idx & 0x3F;
+
+ if (n < 24) {
+ if (n + offset <= 64) {
+ if (((*data >> offset)&bits::lo_set[n]) == bits::lo_set[n])
+ return n;
+ } else { // n+offset > 64
+ if ((*data >> offset) == bits::lo_set[64-offset]) {// all bits are set to 1
+ value = 64-offset;
+ ++data;
+ n -= (64-offset);
+ offset = 0;
+ while (n >= 64) {
+ if (*data == 0xFFFFFFFFFFFFFFFFULL) {
+ value += 64;
+ ++data;
+ n -= 64;
+ } else {
+ uint8_t temp = bits::lo(~(*data));
+ value += temp;
+ n -= temp;
+ offset = temp;
+ goto start_decoding;
+ }
+ }
+ // 0 <= n <= 64
+ if ((*data&bits::lo_set[n]) == bits::lo_set[n])
+ return value + n;
+ }
+ }
+ }
+
+start_decoding:
+
+ while (i < n) {// while not all values are decoded
+ // n-i values to decode
+ if (((*data>>offset)&0xF)==0xF) {
+ uint8_t maxdecode = n-i > 63 ? 63 : n-i;
+ uint8_t rbp = bits::lo(~bits::read_int(data, offset,maxdecode));
+ i += rbp;
+ value += rbp;
+ if (rbp+offset>=64) {
+ ++data;
+ offset = (rbp+offset)&0x3F;
+ } else {
+ offset += rbp;
+ }
+ if (rbp == maxdecode)
+ continue;
+ }
+ while (i < n) {
+ uint32_t psum = elias_delta::data.prefixsum[bits::read_int(data, offset, 16)];
+// if( psum == 0 or i+((psum>>16)&0x00FF) > n ){ // value does not fit in 16 bits
+ if (psum == 0) { // value does not fit in 16 bits
+ goto decode_single;
+ } else if (i+((psum>>16)&0x00FF) > n) { // decoded too much
+ if (n-i <= 8) {
+ psum = elias_delta::data.prefixsum_8bit[bits::read_int(data, offset, 8) | ((n-i-1)<<8)];
+ if (psum > 0) {
+ value += (psum&0xF);
+ i += ((psum>>4)&0xF);
+ offset += (psum>>8);
+ if (offset>=64) {
+ offset&=0x3F;
+ ++data;
+ }
+ }
+ }
+ break;
+ } else {
+ value += (psum&0x0000FFFF);
+ i += ((psum>>16)&0x00FF);
+ offset += (psum>>24);
+ if (offset>=64) {
+ offset&=0x3F;
+ ++data;
+ }
+ }
+ }
+ if (i<n) {
+decode_single:
+ i++;
+ uint16_t len_1_len = bits::read_unary_and_move(data, offset); // read length of length of x
+ uint16_t len_1 = bits::read_int_and_move(data, offset, len_1_len) + (1ULL << len_1_len) - 1;
+ value += bits::read_int_and_move(data, offset, len_1) + (len_1<64) * (1ULL << (len_1));
+// std::cout<<"decode single ("<<len_1_len<<","<<len_1<<","<<value<<")"<<std::endl;
+ }
+ }
+ return value;
+}
+
+} // end namespace sdsl
+} // end namespace coder
diff --git a/lib/coder_elias_gamma.cpp b/lib/coder_elias_gamma.cpp
new file mode 100644
index 0000000..0fc76f1
--- /dev/null
+++ b/lib/coder_elias_gamma.cpp
@@ -0,0 +1,249 @@
+#include "sdsl/coder_elias_gamma.hpp"
+
+namespace sdsl
+{
+
+namespace coder
+{
+
+elias_gamma::impl elias_gamma::data;
+
+uint64_t elias_gamma::decode_prefix_sum(const uint64_t* data, const size_type start_idx, const size_type end_idx, size_type n)
+{
+ if (n==0)
+ return 0;
+ const uint64_t* lastdata = data + ((end_idx+63) >> 6);
+ data += (start_idx >> 6);
+ uint64_t w = 0, value = 0;
+ int16_t buffered = 0, read = start_idx & 0x3F;
+ size_type i = 0;
+ if (n + read <= 64) {
+ if (((*data >> read)&bits::lo_set[n]) == bits::lo_set[n])
+ return n;
+ } else { // n+read > 64
+ if ((*data >> read) == bits::lo_set[64-read]) {// all bits are set to 1
+ value = 64-read;
+ ++data;
+ n -= (64-read);
+ read = 0;
+ while (n >= 64) {
+ if (*data == 0xFFFFFFFFFFFFFFFFULL) {
+ value += 64;
+ ++data;
+ n -= 64;
+ } else
+ goto start_decoding;
+ }
+ // 0 <= n <= 64
+ if ((*data&bits::lo_set[n]) == bits::lo_set[n])
+ return value + n;
+ }
+ }
+
+start_decoding:
+ while (i<n) {
+ while (buffered < 64 and data < lastdata) {
+fill_buffer:
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else { // read buffered
+ read += 64-buffered;
+ buffered = 64;
+ }
+ }
+ uint32_t rbp = bits::lo(~w);
+ if (rbp > 0) {
+ i += rbp;
+ value += rbp;
+ if (i >= n) { // decoded too much
+ return value - (i-n); // return corrected value
+ }
+ assert(buffered >= rbp);
+ buffered -= rbp;
+ w >>= rbp;
+ if (buffered<16)
+ goto fill_buffer;
+ }
+ {
+ // i < n
+begin_decode:
+ uint32_t psum = elias_gamma::data.prefixsum[w&0x0000FFFF];
+ if (!psum or i+((psum>>16)&0x00FF) > n) {
+ if (w==0) {// buffer is not full
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ if (!w) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ }
+ }
+// assert(w>0);
+ uint16_t len_1 = bits::lo(w); // read length of length
+ buffered -= (len_1+1);
+ w >>= (len_1+1);
+ if (len_1 > buffered) {// buffer is not full
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ if (len_1 > buffered) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ read = 0;
+ } else {
+ read += 64-buffered;
+ buffered = 64;
+ };
+ }
+ }
+ value += (w&bits::lo_set[len_1]) + (len_1<64) * (1ULL << len_1);
+ buffered -= len_1;
+ if (len_1 < 64) {
+ w >>= len_1;
+ } else {
+ w = 0;
+ }
+ ++i;
+ if (i==n)
+ return value;
+ if (buffered>=16)
+ goto begin_decode;
+ } else {
+ value += (psum&0x0000FFFF);
+ i += ((psum>>16)&0x00FF);
+ if (i==n)
+ return value;
+ buffered -= (psum>>24);
+ w >>= (psum>>24);
+ if (buffered>=16)
+ goto begin_decode;
+ }
+ }
+ };
+ return value;
+}
+
+
+uint64_t elias_gamma::decode_prefix_sum(const uint64_t* data, const size_type start_idx, size_type n)
+{
+ if (n==0)
+ return 0;
+ data += (start_idx >> 6);
+ uint64_t value = 0;
+ size_type i = 0;
+ uint8_t offset = start_idx & 0x3F;
+
+ if (n < 24) {
+ if (n + offset <= 64) {
+ if (((*data >> offset)&bits::lo_set[n]) == bits::lo_set[n])
+ return n;
+ } else { // n+offset > 64
+ if ((*data >> offset) == bits::lo_set[64-offset]) {// all bits are set to 1
+ value = 64-offset;
+ ++data;
+ n -= (64-offset);
+ offset = 0;
+ while (n >= 64) {
+ if (*data == 0xFFFFFFFFFFFFFFFFULL) {
+ value += 64;
+ ++data;
+ n -= 64;
+ } else {
+ uint8_t temp = bits::lo(~(*data));
+ value += temp;
+ n -= temp;
+ offset = temp;
+ goto start_decoding;
+ }
+ }
+ // 0 <= n <= 64
+ if ((*data&bits::lo_set[n]) == bits::lo_set[n])
+ return value + n;
+ }
+ }
+ }
+
+start_decoding:
+ while (i < n) {// while not all values are decoded
+ // n-i values to decode
+
+ if (((*data>>offset)&0xF)==0xF) {
+ uint8_t maxdecode = n-i > 63 ? 63 : n-i;
+ uint8_t rbp = bits::lo(~bits::read_int(data, offset,maxdecode));
+ i += rbp;
+ value += rbp;
+ if (rbp+offset>=64) {
+ ++data;
+ offset = (rbp+offset)&0x3F;
+ } else {
+ offset += rbp;
+ }
+ if (rbp == maxdecode)
+ continue;
+ }
+
+ while (i < n) {
+ uint32_t psum = elias_gamma::data.prefixsum[bits::read_int(data, offset, 16)];
+ if (psum == 0) { // value does not fit in 16 bits
+ goto decode_single;
+ } else if (i+((psum>>16)&0x00FF) > n) { // decoded too much
+ if (n-i <= 8) {
+ psum = elias_gamma::data.prefixsum_8bit[bits::read_int(data, offset, 8) | ((n-i-1)<<8)];
+ if (psum > 0) {
+ value += (psum&0xFF);
+ i += ((psum>>8)&0xF);
+ offset += (psum>>12);
+ if (offset>=64) {
+ offset&=0x3F;
+ ++data;
+ }
+ }
+ }
+ break;
+ } else {
+ value += (psum&0x0000FFFF);
+ i += ((psum>>16)&0x00FF);
+ offset += (psum>>24);
+ if (offset>=64) {
+ offset&=0x3F;
+ ++data;
+ }
+ }
+ }
+ if (i<n) {
+decode_single:
+ i++;
+ uint16_t len_1 = bits::read_unary_and_move(data, offset); // read length of length of x
+ value += bits::read_int_and_move(data, offset, len_1) + (len_1<64) * (1ULL << len_1);
+ }
+ }
+ return value;
+}
+
+
+} // end namespace sdsl
+} // end namespace coder
diff --git a/lib/coder_fibonacci.cpp b/lib/coder_fibonacci.cpp
new file mode 100644
index 0000000..9049a73
--- /dev/null
+++ b/lib/coder_fibonacci.cpp
@@ -0,0 +1,109 @@
+#include "sdsl/coder_fibonacci.hpp"
+
+namespace sdsl
+{
+
+namespace coder
+{
+
+fibonacci::impl fibonacci::data;
+
+uint64_t fibonacci::decode_prefix_sum(const uint64_t* data, const size_type start_idx, size_type n)
+{
+ if (n==0)
+ return 0;
+// return decode<true,false,int*>(data, start_idx, n);
+ data += (start_idx >> 6);
+ size_type i = 0;
+ int32_t bits_to_decode = 0;
+ uint64_t w = 0, value = 0;
+ int16_t buffered = 0, read = start_idx & 0x3F, shift = 0;
+ uint16_t temp=0;
+ uint64_t carry=0;
+ i = bits::cnt11(*data & ~bits::lo_set[read], carry);
+ if (i<n) {
+ uint64_t oldcarry;
+ w = 0;
+ do {
+ oldcarry = carry;
+ i += (temp = bits::cnt11(*(data+(++w)), carry));
+ } while (i<n);
+ bits_to_decode += ((w-1)<<6) + bits::sel11(*(data+w), n-(i-temp), oldcarry) + 65 - read;
+ w = 0;
+ } else { // i>=n
+ bits_to_decode = bits::sel11(*data >> read, n)+1;
+ }
+ if (((size_type)bits_to_decode) == n<<1)
+ return n;
+ if (((size_type)bits_to_decode) == (n<<1)+1)
+ return n+1;
+ i = 0;
+// while( bits_to_decode > 0 or buffered > 0){// while not all values are decoded
+ do {
+ while (buffered < 64 and bits_to_decode > 0) {
+ w |= (((*data)>>read)<<buffered);
+ if (read >= buffered) {
+ ++data;
+ buffered += 64-read;
+ bits_to_decode -= (64-read);
+ read = 0;
+ } else { // read buffered
+ read += 64-buffered;
+ bits_to_decode -= (64-buffered);
+ buffered = 64;
+ }
+ if (bits_to_decode < 0) {
+ buffered += bits_to_decode;
+ w &= bits::lo_set[buffered];
+ bits_to_decode = 0;
+ }
+ }
+ if (!i) { // try do decode multiple values
+ if ((w&0xFFFFFF)==0xFFFFFF) {
+ value += 12;
+ w >>= 24;
+ buffered -= 24;
+ if ((w&0xFFFFFF)==0xFFFFFF) {
+ value += 12;
+ w >>= 24;
+ buffered -= 24;
+ }
+ }
+ do {
+ temp = fibonacci::data.fib2bin_16_greedy[w&0xFFFF];
+ if ((shift=(temp>>11)) > 0) {
+ value += (temp & 0x7FFULL);
+ w >>= shift;
+ buffered -= shift;
+ } else {
+ value += fibonacci::data.fib2bin_0_95[w&0xFFF];
+ w >>= 12;
+ buffered -= 12;
+ i = 1;
+ break;
+ }
+ } while (buffered>15);
+ } else { // i > 0
+ value += fibonacci::data.fib2bin_0_95[(i<<12) | (w&0xFFF)];
+ shift = fibonacci::data.fib2bin_shift[w&0x1FFF];
+ if (shift > 0) { // if end of decoding
+ w >>= shift;
+ buffered -= shift;
+ i = 0;
+ } else { // not end of decoding
+ w >>= 12;
+ buffered -= 12;
+ ++i;
+ }
+ }
+ } while (bits_to_decode > 0 or buffered > 0);
+ return value;
+}
+
+uint64_t fibonacci::decode_prefix_sum(const uint64_t* data, const size_type start_idx, SDSL_UNUSED const size_type end_idx, size_type n)
+{
+ return decode_prefix_sum(data, start_idx, n);
+}
+
+} // end namespace coder
+} // end namespace sdsl
diff --git a/lib/config.cpp b/lib/config.cpp
new file mode 100644
index 0000000..66ae826
--- /dev/null
+++ b/lib/config.cpp
@@ -0,0 +1,23 @@
+#include "sdsl/config.hpp"
+#include "sdsl/util.hpp"
+
+namespace sdsl
+{
+cache_config::cache_config(bool f_delete_files, std::string f_dir, std::string f_id, tMSS f_file_map) : delete_files(f_delete_files), dir(f_dir), id(f_id), file_map(f_file_map)
+{
+ if ("" == id) {
+ id = util::to_string(util::pid())+"_"+util::to_string(util::id());
+ }
+}
+
+template<>
+const char* key_text_trait<0>::KEY_TEXT = conf::KEY_TEXT_INT;
+template<>
+const char* key_text_trait<8>::KEY_TEXT = conf::KEY_TEXT;
+
+template<>
+const char* key_bwt_trait<0>::KEY_BWT = conf::KEY_BWT_INT;
+template<>
+const char* key_bwt_trait<8>::KEY_BWT = conf::KEY_BWT;
+
+}// end namespace sdsl
diff --git a/lib/construct.cpp b/lib/construct.cpp
new file mode 100644
index 0000000..84b6d97
--- /dev/null
+++ b/lib/construct.cpp
@@ -0,0 +1,6 @@
+#include "sdsl/construct.hpp"
+
+namespace sdsl
+{
+
+}
diff --git a/lib/construct_config.cpp b/lib/construct_config.cpp
new file mode 100644
index 0000000..6ea09a9
--- /dev/null
+++ b/lib/construct_config.cpp
@@ -0,0 +1,8 @@
+#include "sdsl/construct_config.hpp"
+
+namespace sdsl
+{
+
+byte_sa_algo_type construct_config::byte_algo_sa = LIBDIVSUFSORT;
+
+}
diff --git a/lib/construct_isa.cpp b/lib/construct_isa.cpp
new file mode 100644
index 0000000..451e2c6
--- /dev/null
+++ b/lib/construct_isa.cpp
@@ -0,0 +1,26 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2010 Simon Gog
+*/
+#include "sdsl/construct_isa.hpp"
+#include <string>
+
+namespace sdsl
+{
+
+void construct_isa(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+ if (!cache_file_exists(conf::KEY_ISA, config)) { // if isa is not already on disk => calculate it
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config));
+ if (!sa_buf.is_open()) {
+ throw std::ios_base::failure("cst_construct: Cannot load SA from file system!");
+ }
+ int_vector<> isa(sa_buf.size());
+ for (size_type i=0; i < isa.size(); ++i) {
+ isa[ sa_buf[i] ] = i;
+ }
+ store_to_cache(isa, conf::KEY_ISA, config);
+ }
+}
+
+}// end namespace
diff --git a/lib/construct_lcp.cpp b/lib/construct_lcp.cpp
new file mode 100644
index 0000000..0b89787
--- /dev/null
+++ b/lib/construct_lcp.cpp
@@ -0,0 +1,1094 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012-2013 Simon Gog
+ Copyright (C) 2013 Timo Beller
+*/
+
+#include "sdsl/construct_lcp.hpp"
+#include "sdsl/construct.hpp"
+#include <stdexcept>
+#include <algorithm>
+
+namespace sdsl
+{
+
+void construct_lcp_semi_extern_PHI(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config));
+ size_type n = sa_buf.size();
+ if (1==n) {
+ int_vector<> lcp(1, 0);
+ store_to_cache(lcp, conf::KEY_LCP, config);
+ return;
+ }
+ const uint8_t log_q = 6; // => q=64
+ const uint32_t q = 1<<log_q;
+ const uint64_t modq = bits::lo_set[log_q];
+
+ // n-1 is the maximum entry in SA
+ int_vector<64> plcp((n-1+q)>>log_q);
+
+ for (size_type i=0, sai_1=0; i < n; ++i) { // we can start at i=0. if SA[i]%q==0
+ // we set PHI[(SA[i]=n-1)%q]=0, since T[0]!=T[n-1]
+ size_type sai = sa_buf[i];
+ if ((sai & modq) == 0) {
+ if ((sai>>log_q) >= plcp.size()) {
+// std::cerr<<"sai="<<sai<<" log_q="<<log_q<<" sai>>log_q="<<(sai>>log_q)<<" "<<sai_1<<std::endl;
+// std::cerr<<"n="<<n<<" "<<" plcp.size()="<<plcp.size();
+ }
+ plcp[sai>>log_q] = sai_1;
+ }
+ sai_1 = sai;
+ }
+
+ int_vector<8> text;
+ load_from_cache(text, conf::KEY_TEXT, config);
+
+ for (size_type i=0,j,k,l=0; i < plcp.size(); ++i) {
+ j = i<<log_q; // j=i*q
+ k = plcp[i];
+ while (text[j+l] == text[k+l])
+ ++l;
+ plcp[i] = l;
+ if (l >= q) {
+ l -= q;
+ } else {
+ l = 0;
+ }
+ }
+
+ size_type buffer_size = 4000000; // buffer_size is a multiple of 8!
+ sa_buf.buffersize(buffer_size);
+ int_vector_buffer<> lcp_out_buf(cache_file_name(conf::KEY_LCP, config), std::ios::out, buffer_size, sa_buf.width()); // open buffer for plcp
+
+ for (size_type i=0, sai_1=0,l=0, sai=0,iq=0; i < n; ++i) {
+ /*size_type*/ sai = sa_buf[i];
+// std::cerr<<"i="<<i<<" sai="<<sai<<std::endl;
+ if ((sai & modq) == 0) { // we have already worked the value out ;)
+ lcp_out_buf[i] = l=plcp[sai>>log_q];
+ } else {
+ /*size_type*/ iq = sai & bits::lo_unset[log_q];
+ l = plcp[sai>>log_q];
+ if (l > (sai-iq))
+ l -= (sai-iq);
+ else
+ l=0;
+ while (text[ sai+l ] == text[ sai_1+l ])
+ ++l;
+ lcp_out_buf[i] = l;
+ }
+#ifdef CHECK_LCP
+ size_type j=0;
+ for (j=0; j<l; ++j) {
+ if (text[sai+j] !=text[sai_1+j]) {
+ std::cout<<"lcp["<<i<<"]="<<l<<" is two big! "<<j<<" is right!"<<" sai="<<sai<<std::endl;
+ if ((sai&modq)!=0)
+ std::cout<<" plcp[sai>>log_q]="<<plcp[sai>>log_q]<<" sai-iq="<<sai-iq<<" sai="<<sai<<" sai-iq="<<sai-iq<<std::endl;
+ break;
+ }
+ }
+#endif
+ sai_1 = sai;
+ }
+ lcp_out_buf.close();
+ register_cache_file(conf::KEY_LCP, config);
+ return;
+}
+
+void construct_lcp_go(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+#ifdef STUDY_INFORMATIONS
+ size_type racs = 0; // random accesses to the text
+ size_type matches = 0;
+ size_type comps2 = 0; // comparisons the second phase
+#endif
+ int_vector<8> text;
+ load_from_cache(text, conf::KEY_TEXT, config);
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config)); // initialize buffer for suffix array
+ const size_type n = sa_buf.size();
+ const size_type m = 254; // LCP[i] == m+1 corresp. to LCP[i]>= m+1; LCP[i] <= m corresp. to LCP[i] was calculated
+
+ if (1==n) {
+ int_vector<> lcp(1, 0);
+ store_to_cache(lcp, conf::KEY_LCP, config);
+ return;
+ }
+
+ size_type cnt_c[257] = {0}; // counter for each character in the text
+ size_type cnt_cc[257] = {0}; // prefix sum of the counter cnt_c
+ size_type cnt_cc2[257] = {0}; //
+ size_type omitted_c[257] = {0}; // counts the omitted occurrences for the second phase
+ size_type prev_occ_in_bwt[256] = {0}; // position of the previous occurrence of each character c in the bwt
+ for (size_type i=0; i<256; ++i) prev_occ_in_bwt[i] = (size_type)-1; // initialize the array with -1
+ unsigned char alphabet[257] = {0};
+ uint8_t sigma = 0;
+
+ tLI m_list[2][256];
+ size_type m_char_count[2] = {0};
+ uint8_t m_chars[2][256] = {{0},{0}};
+
+ size_type nn = 0; // n' for phase 2
+ // phase 1: calculate lcp_sml; memory consumption: 2n bytes (lcp_sml=n bytes, text=n bytes)
+ {
+
+ int_vector<8> lcp_sml(n, 0); // initialize array for small values of first phase; note lcp[0]=0
+ size_type done_cnt=0;
+
+ for (size_type i=0; i<n; ++i) { // initialize cnt_c
+ ++cnt_c[text[i]+1];
+ }
+ for (int i=1; i<257; ++i) { // calculate sigma and initailize cnt_cc
+ if (cnt_c[i] > 0) {
+ alphabet[sigma++] = (unsigned char)(i-1);
+ }
+ cnt_cc[i] = cnt_c[i] + cnt_cc[i-1];
+ }
+ alphabet[sigma] = '\0';
+ {
+ int_vector_buffer<8> bwt_buf(cache_file_name(conf::KEY_BWT, config)); // initialize buffer of bwt
+ size_type sai_1 = sa_buf[0]; // store value of sa[i-1]
+ uint8_t bwti_1 = bwt_buf[0]; // store value of BWT[i-1]
+ lcp_sml[ cnt_cc[bwti_1]++ ] = 0; // lcp_sml[ LF[0] ] = 0
+ prev_occ_in_bwt[bwti_1] = 0; // init previous occurence of character BWT[0]
+ ++omitted_c[alphabet[0]]; //
+
+ int_vector<64> rmq_stack(2*(m+10)); // initialize stack for m+10 elements representing (position, value)
+ rmq_stack[0] = 0; rmq_stack[1] = 0; // first element (-1, -1)
+ rmq_stack[2] = 1; rmq_stack[3] = 0; // second element (0, -1)
+ size_type rmq_end=3; // index of the value of the topmost element
+
+ const size_type m_mod2 = m%2;
+ uint8_t cur_c = alphabet[1];
+ size_type big_val = 0;
+ for (size_type i=1, sai, cur_c_idx=1, cur_c_cnt=cnt_c[alphabet[1]+1]; i < n; ++i, --cur_c_cnt) {
+ uint8_t bwti = bwt_buf[i];
+ sai = sa_buf[i];
+ size_type lf = cnt_cc[bwti];
+ if (!cur_c_cnt) {// cur_c_cnt==0, if there is no more occurence of the current character
+ if (cur_c_cnt < sigma) {
+ cur_c_cnt = cnt_c[(cur_c=alphabet[++cur_c_idx])+1];
+ }
+ }
+ size_type l=0;
+ if (i >= cnt_cc[cur_c]) { // if the current lcp entry is not already done TODO: schleife von i bis cnt_cc[cur_c]
+ if (bwti == bwti_1 and lf < i) { // BWT[i]==BWT[i-1]
+ l = lcp_sml[lf] ? lcp_sml[lf]-1 : 0; // l = LCP[LF[i]]-1; l < m+1
+ if (l == m) { // if LCP[LF[i]] == m+1; otherwise LCP[LF[i]] < m+1 the result is correct
+ l += (text[sai_1+m] == text[sai+m]);
+#ifdef STUDY_INFORMATIONS
+ if ((sai_1^sai)>>6) // if i and phii are in the same cache line
+ ++racs;
+#endif
+ }
+ lcp_sml[i] = l;
+ ++done_cnt;
+ } else { // BWT[i] != BWT[i-1] or LF[i] > i
+ if (lf < i)
+ l = lcp_sml[lf] ? lcp_sml[lf]-1 : 0;
+#ifdef STUDY_INFORMATIONS
+ if ((sai_1^sai)>>6) // if i and phii are in the same cache line
+ ++racs;
+#endif
+ while (text[sai_1+l] == text[sai+l] and l < m+1) {
+ ++l;
+#ifdef STUDY_INFORMATIONS
+ ++matches;
+#endif
+ }
+ lcp_sml[i] = l;
+ }
+ } else { // if already done
+ l = lcp_sml[i]; // load LCP value
+ }
+ if (l > m) {
+ ++big_val;
+ if (i > 10000 and i < 10500 and big_val > 3000) { // if most of the values are big: switch to PHI algorithm
+ util::clear(text);
+ util::clear(lcp_sml);
+ construct_lcp_PHI<8>(config);
+ return;
+ }
+ }
+ // invariant: l <= m+1
+ // begin update rmq_stack
+ size_type x = l+1;
+ size_type j = rmq_end;
+ while (x <= rmq_stack[j]) j-=2; // pop all elements with value >= l
+ rmq_stack[++j] = i+1; // push position i
+ rmq_stack[++j] = x; // push value l
+ rmq_end = j; // update index of the value of the topmost element
+ if (lf > i) { // if LF[i] > i, we can calculate LCP[LF[i]] in constant time with rmq
+ ++done_cnt;
+ // rmq query for lcp-values in the interval I=[prev_occ_in_bwt[BWT[i]]+1..i]
+ // rmq is linear in the stack size; can also be implemented with binary search on the stack
+ size_type x_pos = prev_occ_in_bwt[bwti]+2;
+ size_type j = rmq_end-3;
+ while (x_pos <= rmq_stack[j]) j-=2; // search smallest value in the interval I
+ lcp_sml[lf] = rmq_stack[j+3] - (rmq_stack[j+3]==m+2); // if lcp-value equals m+1, we subtract 1
+ }
+ if (l >= m) {
+ if (l == m)
+ push_front_m_index(nn, cur_c, m_list[m_mod2], m_chars[m_mod2], m_char_count[m_mod2]);
+ ++nn;
+ } else
+ ++omitted_c[cur_c];
+
+ prev_occ_in_bwt[bwti] = i; // update previous position information for character BWT[i]
+ ++cnt_cc[bwti]; // update counter and therefore the LF information
+ sai_1 = sai; // update SA[i-1]
+ bwti_1 = bwti; // update BWT[i-1]
+ }
+ }
+ util::clear(text);
+
+ if (n > 1000 and nn > 5*(n/6)) { // if we would occupy more space than the PHI algorithm => switch to PHI algorithm
+ util::clear(lcp_sml);
+ construct_lcp_PHI<8>(config);
+ return;
+ }
+ store_to_cache(lcp_sml, "lcp_sml", config);
+ }
+#ifdef STUDY_INFORMATIONS
+ std::cout<<"# n="<<n<<" nn="<<nn<<" nn/n="<<((double)nn)/n<<std::endl;
+#endif
+
+ // phase 2: calculate lcp_big
+ {
+// std::cout<<"# begin calculating LF' values"<<std::endl;
+ int_vector<> lcp_big(nn, 0, bits::hi(n-1)+1); // lcp_big first contains adapted LF values and finally the big LCP values
+ {
+ // initialize lcp_big with adapted LF values
+ bit_vector todo(n,0); // bit_vector todo indicates which values are >= m in lcp_sml
+ {
+ // initialize bit_vector todo
+ int_vector_buffer<8> lcp_sml_buf(cache_file_name("lcp_sml", config)); // load lcp_sml
+ for (size_type i=0; i < n; ++i) {
+ if (lcp_sml_buf[i] >= m) {
+ todo[i] = 1;
+ }
+ }
+ }
+
+ cnt_cc2[0] = cnt_cc[0]= 0;
+ for (size_type i=1, omitted_sum=0; i<257; ++i) { // initialize cnt_cc and cnt_cc2
+ cnt_cc[i] = cnt_c[i] + cnt_cc[i-1];
+ omitted_sum += omitted_c[i-1];
+ cnt_cc2[i] = cnt_cc[i] - omitted_sum;
+ }
+
+ int_vector_buffer<8> bwt_buf(cache_file_name(conf::KEY_BWT, config)); // load BWT
+ for (size_type i=0, i2=0; i < n; ++i) {
+ uint8_t b = bwt_buf[i]; // store BWT[i]
+ size_type lf_i = cnt_cc[b]; // LF[i]
+ if (todo[i]) { // LCP[i] is a big value
+ if (todo[lf_i]) { // LCP[LF[i]] is a big entry
+ lcp_big[i2] = cnt_cc2[b]; // LF'[i]
+ }/*else{
+ lcp_big[i2] = 0;
+ }*/
+ ++i2;
+ }
+ if (todo[lf_i]) { // LCP[LF[i]] is a big entry
+ ++cnt_cc2[b]; // increment counter for adapted LF
+ }
+ ++cnt_cc[b]; // increment counter for LF
+ }
+ }
+
+// std::cout<<"# begin initializing bwt2, shift_bwt2, run2"<<std::endl;
+ int_vector<8> bwt2(nn), shift_bwt2(nn); // BWT of big LCP values, and shifted BWT of big LCP values
+ bit_vector run2(nn+1); // indicates for each entry i, if i and i-1 are both big LCP values
+ run2[nn] = 0; // index nn is not a big LCP value
+ {
+ // initialize bwt2, shift_bwt2, adj2
+ int_vector_buffer<8> lcp_sml_buf(cache_file_name("lcp_sml", config)); // load lcp_sml
+ int_vector_buffer<8> bwt_buf(cache_file_name(conf::KEY_BWT, config)); // load BWT
+ uint8_t b_1 = '\0'; // BWT[i-1]
+ bool is_run = false;
+ for (size_type i=0, i2=0; i < n; ++i) {
+ uint8_t b = bwt_buf[i];
+ if (lcp_sml_buf[i] >= m) {
+ bwt2[i2] = b;
+ shift_bwt2[i2] = b_1;
+ run2[i2] = is_run;
+ is_run = true;
+ ++i2;
+ } else {
+ is_run = false;
+ }
+ b_1 = b;
+ }
+ }
+
+ bit_vector todo2(nn+1, 1); // init all values with 1, except
+ todo2[nn] = 0; // the last one! (handels case "i < nn")
+
+// std::cout<<"# begin calculating m-indices"<<std::endl;
+ {
+ // calculate m-indices, (m+1)-indices,... until we are done
+ size_type m2 = m;
+ size_type char_ex[256]; for (size_type i=0; i<256; ++i) char_ex[i] = nn;
+ size_type char_occ=0;
+ size_type m_mod2 = m2%2, mm1_mod2 = (m2+1)%2;
+ while (m_char_count[m_mod2] > 0) { // while there are m-indices, calculate (m+1)-indices and write m-indices
+ // For all values LCP[i] >= m2 it follows that todo2[i] == 1
+ // list m_list[mm1_mod2][b] is sorted in decreasing order
+ ++m2;
+ mm1_mod2 = (m2+1)%2, m_mod2 = m2%2;
+ m_char_count[m_mod2] = 0;
+
+ std::sort(m_chars[mm1_mod2], m_chars[mm1_mod2]+m_char_count[mm1_mod2]); // TODO: ersetzen?
+
+ for (size_type mc=0; mc<m_char_count[mm1_mod2]; ++mc) { // for every character
+ tLI& mm1_mc_list = m_list[mm1_mod2][m_chars[mm1_mod2][ m_char_count[mm1_mod2]-1- mc ]];
+// size_type old_i = nn;
+ while (!mm1_mc_list.empty()) {
+ size_type i = mm1_mc_list.front(); // i in [0..n-1]
+ mm1_mc_list.pop_front();
+ // For all values LCP[i] >= m-1 it follows that todo2[i] == 1
+ for (size_type k=i; todo2[k]; --k) {
+#ifdef STUDY_INFORMATIONS
+ ++comps2;
+#endif
+ uint8_t b = shift_bwt2[k];
+ if (char_ex[b] != i) {
+ char_ex[b] = i;
+ ++char_occ;
+ }
+ if (!run2[k])
+ break;
+ }
+ for (size_type k=i; todo2[k] and char_occ; ++k) {
+#ifdef STUDY_INFORMATIONS
+ ++comps2;
+#endif
+ uint8_t b = bwt2[k];
+ if (char_ex[b] == i) {
+ size_type p = lcp_big[k];
+ push_back_m_index(p, b, m_list[m_mod2], m_chars[m_mod2], m_char_count[m_mod2]);
+ char_ex[b] = nn;
+ --char_occ;
+ }
+ if (!run2[k+1])
+ break;
+ }
+ lcp_big[ i ] = m2-1;
+ todo2[ i ] = 0;
+// old_i = i;
+ }
+ }
+ }
+
+ }
+
+ store_to_cache(lcp_big, "lcp_big", config);
+ } // end phase 2
+
+// std::cout<<"# merge lcp_sml and lcp_big"<<std::endl;
+ // phase 3: merge lcp_sml and lcp_big and save to disk
+ {
+ const size_type buffer_size = 1000000; // buffer_size has to be a multiple of 8!
+ int_vector_buffer<> lcp_big_buf(cache_file_name("lcp_big", config)); // file buffer containing the big LCP values
+ int_vector_buffer<8> lcp_sml_buf(cache_file_name("lcp_sml", config), std::ios::in, buffer_size); // file buffer containing the small LCP values
+ int_vector_buffer<> lcp_buf(cache_file_name(conf::KEY_LCP, config), std::ios::out, buffer_size, lcp_big_buf.width()); // buffer for the resulting LCP array
+ for (size_type i=0, i2=0; i < n; ++i) {
+ size_type l = lcp_sml_buf[i];
+ if (l >= m) { // if l >= m it is stored in lcp_big
+ l = lcp_big_buf[i2];
+ ++i2;
+ }
+ lcp_buf[i] = l;
+ }
+ lcp_buf.close();
+ }
+ register_cache_file(conf::KEY_LCP, config);
+
+#ifdef STUDY_INFORMATIONS
+ std::cout<<"# racs: "<<racs<<std::endl;
+ std::cout<<"# matches: "<<matches<<std::endl;
+ std::cout<<"# comps2: "<<comps2<<std::endl;
+#endif
+ return;
+}
+
+void construct_lcp_goPHI(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+ int_vector<8> text;
+ load_from_cache(text, conf::KEY_TEXT, config); // load text from file system
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config)); // initialize buffer for suffix array
+ const size_type n = sa_buf.size();
+ const size_type m = 254; // LCP[i] == m+1 corresp. to LCP[i]>= m+1; LCP[i] <= m corresp. to LCP[i] was calculated
+
+ if (1==n) {
+ int_vector<> lcp(1, 0);
+ store_to_cache(lcp, conf::KEY_LCP, config);
+ return;
+ }
+
+ size_type cnt_c[257] = {0}; // counter for each character in the text
+ size_type cnt_cc[257] = {0}; // prefix sum of the counter cnt_c
+ size_type omitted_c[257] = {0}; // counts the omitted occurrences for the second phase
+ size_type prev_occ_in_bwt[256] = {0}; // position of the previous occurrence of each character c in the bwt
+ for (size_type i=0; i<256; ++i) prev_occ_in_bwt[i] = (size_type)-1; // initialize the array with -1
+ unsigned char alphabet[257] = {0};
+ uint8_t sigma = 0;
+
+ size_type nn = 0; // n' for phase 2
+ // phase 1: calculate lcp_sml; memory consumption: 2n bytes (lcp_sml=n bytes, text=n bytes)
+ {
+
+ int_vector<8> lcp_sml(n, 0); // initialize array for small values of first phase; note lcp[0]=0
+ size_type done_cnt=0;
+
+ for (size_type i=0; i<n; ++i) { // initialize cnt_c
+ ++cnt_c[text[i]+1];
+ }
+ for (int i=1; i<257; ++i) { // calculate sigma and initailize cnt_cc
+ if (cnt_c[i] > 0) {
+ alphabet[sigma++] = (unsigned char)(i-1);
+ }
+ cnt_cc[i] = cnt_c[i] + cnt_cc[i-1];
+ }
+ alphabet[sigma] = '\0';
+ {
+ int_vector_buffer<8> bwt_buf(cache_file_name(conf::KEY_BWT, config)); // initialize buffer of bwt
+ size_type sai_1 = sa_buf[0]; // store value of sa[i-1]
+ uint8_t bwti_1 = bwt_buf[0]; // store value of BWT[i-1]
+ lcp_sml[ cnt_cc[bwti_1]++ ] = 0; // lcp_sml[ LF[0] ] = 0
+ prev_occ_in_bwt[bwti_1] = 0; // init previous occurence of character BWT[0]
+ ++omitted_c[alphabet[0]]; //
+
+ int_vector<64> rmq_stack(2*(m+10)); // initialize stack for m+10 elements representing (position, value)
+ rmq_stack[0] = 0; rmq_stack[1] = 0; // first element (-1, -1)
+ rmq_stack[2] = 1; rmq_stack[3] = 0; // second element (0, -1)
+ size_type rmq_end=3; // index of the value of the topmost element
+
+ uint8_t cur_c = alphabet[1];
+ for (size_type i=1, sai, cur_c_idx=1, cur_c_cnt=cnt_c[alphabet[1]+1]; i < n; ++i, --cur_c_cnt) {
+ uint8_t bwti = bwt_buf[i];
+ sai = sa_buf[i];
+ size_type lf = cnt_cc[bwti];
+ if (!cur_c_cnt) {// cur_c_cnt==0, if there is no more occurence of the current character
+ if (cur_c_cnt < sigma) {
+ cur_c_cnt = cnt_c[(cur_c=alphabet[++cur_c_idx])+1];
+ }
+ }
+ size_type l=0;
+ if (i >= cnt_cc[cur_c]) { // if the current lcp entry is not already done TODO: schleife von i bis cnt_cc[cur_c]
+ if (bwti == bwti_1 and lf < i) { // BWT[i]==BWT[i-1]
+ l = lcp_sml[lf] ? lcp_sml[lf]-1 : 0; // l = LCP[LF[i]]-1; l < m+1
+ if (l == m) { // if LCP[LF[i]] == m+1; otherwise LCP[LF[i]] < m+1 the result is correct
+ l += (text[sai_1+m] == text[sai+m]);
+ }
+ lcp_sml[i] = l;
+ ++done_cnt;
+ } else { // BWT[i] != BWT[i-1] or LF[i] > i
+ if (lf < i)
+ l = lcp_sml[lf] ? lcp_sml[lf]-1 : 0;
+ while (text[sai_1+l] == text[sai+l] and l < m+1) {
+ ++l;
+ }
+ lcp_sml[i] = l;
+ }
+ } else { // if already done
+ l = lcp_sml[i]; // load LCP value
+ }
+ // invariant: l <= m+1
+ // begin update rmq_stack
+ size_type x = l+1;
+ size_type j = rmq_end;
+ while (x <= rmq_stack[j]) j-=2; // pop all elements with value >= l
+ rmq_stack[++j] = i+1; // push position i
+ rmq_stack[++j] = x; // push value l
+ rmq_end = j; // update index of the value of the topmost element
+ if (lf > i) { // if LF[i] > i, we can calculate LCP[LF[i]] in constant time with rmq
+ ++done_cnt;
+ // rmq query for lcp-values in the interval I=[prev_occ_in_bwt[BWT[i]]+1..i]
+ // rmq is linear in the stack size; can also be implemented with binary search on the stack
+ size_type x_pos = prev_occ_in_bwt[bwti]+2;
+ size_type j = rmq_end-3;
+ while (x_pos <= rmq_stack[j]) j-=2; // search smallest value in the interval I
+ lcp_sml[lf] = rmq_stack[j+3] - (rmq_stack[j+3]==m+2); // if lcp-value equals m+1, we subtract 1
+ }
+ if (l > m) {
+ ++nn;
+ } else
+ ++omitted_c[cur_c];
+
+ prev_occ_in_bwt[bwti] = i; // update previous position information for character BWT[i]
+ ++cnt_cc[bwti]; // update counter and therefore the LF information
+ sai_1 = sai; // update SA[i-1]
+ bwti_1 = bwti; // update BWT[i-1]
+ }
+ }
+ store_to_cache(lcp_sml, "lcp_sml", config);
+ }
+
+ // phase 2: calculate lcp_big with PHI algorithm on remaining entries of LCP
+ {
+ int_vector<> lcp_big(0, 0, bits::hi(n-1)+1);//nn, 0, bits::hi(n-1)+1);
+ {
+
+ memory_monitor::event("lcp-init-phi-begin");
+ size_type sa_n_1 = 0; // value for SA[n-1]
+ bit_vector todo(n,0); // bit_vector todo indicates which values are > m in lcp_sml
+ {
+ // initialize bit_vector todo
+ int_vector_buffer<8> lcp_sml_buf(cache_file_name("lcp_sml", config)); // load lcp_sml
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config)); // load sa
+ for (size_type i=0; i < n; ++i) {
+ if (lcp_sml_buf[i] > m) {
+ todo[sa_buf[i]] = 1;
+ }
+ }
+ sa_n_1 = sa_buf[n-1];
+ }
+ rank_support_v<> todo_rank(&todo); // initialize rank for todo
+
+ const size_type bot = sa_n_1;
+ int_vector<> phi(nn, bot, bits::hi(n-1)+1); // phi
+
+ int_vector_buffer<8> bwt_buf(cache_file_name(conf::KEY_BWT, config)); // load BWT
+ int_vector_buffer<> sa_buf(cache_file_name(conf::KEY_SA, config)); // load sa
+ int_vector_buffer<8> lcp_sml_buf(cache_file_name("lcp_sml", config)); // load lcp_sml
+ uint8_t b_1 = 0;
+ for (size_type i=0,sai_1=0; i < n; ++i) { // initialize phi
+ uint8_t b = bwt_buf[i]; // store BWT[i]
+ size_type sai = sa_buf[i];
+ if (lcp_sml_buf[i] > m and b != b_1) { // if i is a big irreducable value
+ phi[todo_rank(sai)] = sai_1;
+ } // otherwise phi is equal to bot
+ b_1 = b;
+ sai_1 = sai;
+ }
+ memory_monitor::event("lcp-init-phi-end");
+
+ memory_monitor::event("lcp-calc-plcp-begin");
+ for (size_type i=0, ii=0, l=m+1,p=0; i < n and ii<nn; ++i) { // execute compact Phi algorithm
+ if (todo[i]) {
+ if (i > 0 and todo[i-1])
+ l = l-1;
+ else
+ l = m+1;
+ if ((p=phi[ii]) != bot) {
+ while (text[i+l] == text[p+l]) ++l;
+ }
+ phi[ii++] = l;
+ }
+ }
+ memory_monitor::event("lcp-calc-plcp-end");
+ util::clear(text);
+
+ memory_monitor::event("lcp-calc-lcp-begin");
+ lcp_big.resize(nn);
+ for (size_type i = 0, ii = 0; i < n and ii<nn; ++i) {
+ if (lcp_sml_buf[i] > m) {
+ lcp_big[ii++] = phi[todo_rank(sa_buf[i])];
+ }
+ }
+ memory_monitor::event("lcp-calc-lcp-end");
+ }
+ store_to_cache(lcp_big, "lcp_big", config);
+ } // end phase 2
+
+// std::cout<<"# merge lcp_sml and lcp_big"<<std::endl;
+ // phase 3: merge lcp_sml and lcp_big and save to disk
+ {
+ const size_type buffer_size = 1000000; // buffer_size has to be a multiple of 8!
+ int_vector_buffer<> lcp_big_buf(cache_file_name("lcp_big", config)); // file buffer containing the big LCP values
+ int_vector_buffer<8> lcp_sml_buf(cache_file_name("lcp_sml", config), std::ios::in, buffer_size); // file buffer containing the small LCP values
+ int_vector_buffer<> lcp_buf(cache_file_name(conf::KEY_LCP, config), std::ios::out, buffer_size, lcp_big_buf.width()); // file buffer for the resulting LCP array
+
+ for (size_type i=0, i2=0; i < n; ++i) {
+ size_type l = lcp_sml_buf[i];
+ if (l > m) { // if l > m it is stored in lcp_big
+ l = lcp_big_buf[i2];
+ ++i2;
+ }
+ lcp_buf[i] = l;
+ }
+ lcp_big_buf.close(true); // close buffer and remove file
+ lcp_sml_buf.close(true); // close buffer and remove file
+ }
+ register_cache_file(conf::KEY_LCP, config);
+ return;
+}
+
+void construct_lcp_bwt_based(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+ std::string lcp_file = cache_file_name(conf::KEY_LCP, config);
+
+ // create WT
+ memory_monitor::event("lcp-bwt-create-wt-huff-begin");
+ wt_huff<bit_vector, rank_support_v<>, select_support_scan<1>, select_support_scan<0>> wt_bwt;
+ construct(wt_bwt, cache_file_name(conf::KEY_BWT, config));
+ uint64_t n = wt_bwt.size();
+ memory_monitor::event("lcp-bwt-create-wt-huff-end");
+
+ // init
+ memory_monitor::event("lcp-bwt-init-begin");
+ size_type lcp_value = 0; // current LCP value
+ size_type lcp_value_offset = 0; // Largest LCP value in LCP array, that was written on disk
+ size_type phase = 0; // Count how often the LCP array was written on disk
+
+ size_type intervals = 0; // number of intervals which are currently stored
+ size_type intervals_new = 0; // number of new intervals
+
+ std::queue<size_type> q; // Queue for storing the intervals
+ std::vector<bit_vector> dict(2); // bit_vector for storing the intervals
+ size_type source = 0, target = 1; // Defines which bit_vector is source and which is target
+ bool queue_used = true;
+ size_type use_queue_and_wt = n/2048; // if intervals < use_queue_and_wt, then use queue and wavelet tree
+ // else use dictionary and wavelet tree
+
+ size_type quantity; // quantity of characters in interval
+ std::vector<unsigned char> cs(wt_bwt.sigma); // list of characters in the interval
+ std::vector<size_type> rank_c_i(wt_bwt.sigma);// number of occurrence of character in [0 .. i-1]
+ std::vector<size_type> rank_c_j(wt_bwt.sigma);// number of occurrence of character in [0 .. j-1]
+
+ // Calculate how many bit are for each lcp value available, to limit the memory usage to 20n bit = 2,5n byte, use at moste 8 bit
+ size_type bb = (n*20-size_in_bytes(wt_bwt)*8*1.25-5*n)/n; // 20n - size of wavelet tree * 1.25 for rank support - 5n for bit arrays - n for index_done array
+ if (n*20 < size_in_bytes(wt_bwt)*8*1.25+5*n) {
+ bb = 6;
+ }
+ bb = std::min(bb, (size_type)8);
+
+ size_type lcp_value_max = (1ULL<<bb)-1; // Largest LCP value that can be stored into the LCP array
+ size_type space_in_bit_for_lcp = n*bb; // Space for the LCP array in main memory
+
+#ifdef STUDY_INFORMATIONS
+ std::cout << "# l=" << n << " b=" << (int)bb << " lcp_value_max=" << lcp_value_max << " size_in_bytes(wt_bwt<v,bs,bs>)=" << size_in_bytes(wt_bwt) << std::endl;
+#endif
+
+ // init partial_lcp
+ int_vector<> partial_lcp(n, 0, bb); // LCP array
+
+ // init index_done
+ bit_vector index_done(n+1, false); // bit_vector indicates if entry LCP[i] is amend
+ rank_support_v<> ds_rank_support; // Rank support for bit_vector index_done
+
+ // create C-array
+ std::vector<size_type> C; // C-Array: C[i] = number of occurrences of characters < i in the input
+ create_C_array(C, wt_bwt);
+ memory_monitor::event("lcp-bwt-init-begin-end");
+ // calculate lcp
+ memory_monitor::event("lcp-bwt-calc-values-begin");
+
+ // calculate first intervals
+ partial_lcp[0] = 0;
+ index_done[0] = true;
+ interval_symbols(wt_bwt, 0, n, quantity, cs, rank_c_i, rank_c_j);
+ for (size_type i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ size_type a_new = C[c] + rank_c_i[i];
+ size_type b_new = C[c] + rank_c_j[i];
+
+ // Save LCP value if not seen before
+ if (!index_done[b_new]) {
+ if (b_new < n) partial_lcp[b_new] = lcp_value;
+ index_done[b_new] = true;
+ // Save interval
+ q.push(a_new); q.push(b_new);
+ ++intervals;
+ }
+ }
+ ++lcp_value;
+
+ // calculate LCP values phase by phase
+ while (intervals) {
+ if (intervals < use_queue_and_wt && !queue_used) {
+ memory_monitor::event("lcp-bwt-bitvec2queue-begin");
+ util::clear(dict[target]);
+
+ // copy from bitvector to queue
+ size_type a2 = util::next_bit(dict[source], 0);
+ size_type b2 = util::next_bit(dict[source], a2+1);
+ while (b2 < dict[source].size()) {
+ q.push((a2-1)>>1); q.push(b2>>1);
+ // get next interval
+ a2 = util::next_bit(dict[source], b2+1);
+ b2 = util::next_bit(dict[source], a2+1);
+ }
+ util::clear(dict[source]);
+ memory_monitor::event("lcp-bwt-bitvec2queue-end");
+ }
+ if (intervals >= use_queue_and_wt && queue_used) {
+ memory_monitor::event("lcp-bwt-queue2bitvec-begin");
+ dict[source].resize(2*(n+1));
+
+ util::set_to_value(dict[source], 0);
+ // copy from queue to bitvector
+ while (!q.empty()) {
+ dict[source][(q.front()<<1)+1 ] = 1; q.pop();
+ dict[source][(q.front()<<1) ] = 1; q.pop();
+ }
+ dict[target].resize(2*(n+1));
+
+ util::set_to_value(dict[target], 0);
+ memory_monitor::event("lcp-bwt-queue2bitvec-end");
+ }
+
+ if (intervals < use_queue_and_wt) {
+ queue_used = true;
+ intervals_new = 0;
+ while (intervals) {
+ // get next interval
+ size_type a = q.front(); q.pop();
+ size_type b = q.front(); q.pop();
+ --intervals;
+
+ interval_symbols(wt_bwt, a, b, quantity, cs, rank_c_i, rank_c_j);
+ for (size_type i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ size_type a_new = C[c] + rank_c_i[i];
+ size_type b_new = C[c] + rank_c_j[i];
+
+ // Save LCP value if not seen before
+ if (!index_done[b_new] and phase == 0) {
+ partial_lcp[b_new] = lcp_value;
+ index_done[b_new] = true;
+ // Save interval
+ q.push(a_new); q.push(b_new);
+ ++intervals_new;
+ } else if (!index_done[b_new]) {
+ size_type insert_pos = b_new-ds_rank_support.rank(b_new);
+ if (!partial_lcp[insert_pos]) {
+ partial_lcp[insert_pos] = lcp_value-lcp_value_offset;
+ // Save interval
+ q.push(a_new); q.push(b_new);
+ ++intervals_new;
+ }
+ }
+ }
+ }
+ intervals = intervals_new;
+ } else {
+ queue_used = false;
+ intervals = 0;
+
+ // get next interval
+ size_type a2 = util::next_bit(dict[source], 0);
+ size_type b2 = util::next_bit(dict[source], a2+1);
+
+ while (b2 < dict[source].size()) {
+ interval_symbols(wt_bwt, ((a2-1)>>1), (b2>>1), quantity, cs, rank_c_i, rank_c_j);
+ for (size_type i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ size_type a_new = C[c] + rank_c_i[i];
+ size_type b_new = C[c] + rank_c_j[i];
+ // Save LCP value if not seen before
+ if (!index_done[b_new] and phase == 0) {
+ partial_lcp[b_new] = lcp_value;
+ index_done[b_new] = true;
+ // Save interval
+ dict[target][(a_new<<1)+1] = 1;
+ dict[target][(b_new<<1) ] = 1;
+ ++intervals;
+ } else if (!index_done[b_new]) {
+ size_type insert_pos = b_new-ds_rank_support.rank(b_new);
+ if (!partial_lcp[insert_pos]) {
+ partial_lcp[insert_pos] = lcp_value-lcp_value_offset;
+ // Save interval
+ dict[target][(a_new<<1)+1] = 1;
+ dict[target][(b_new<<1) ] = 1;
+ ++intervals;
+ }
+ }
+ }
+ // get next interval
+ a2 = util::next_bit(dict[source], b2+1);
+ b2 = util::next_bit(dict[source], a2+1);
+ }
+ std::swap(source, target);
+ util::set_to_value(dict[target], 0);
+ }
+ ++lcp_value;
+ if (lcp_value>=lcp_value_max) {
+ memory_monitor::event("lcp-bwt-write-to-file-begin");
+ if (phase) {
+ insert_lcp_values(partial_lcp, index_done, lcp_file, lcp_value, lcp_value_offset);
+ } else {
+ store_to_file(partial_lcp, lcp_file);
+ }
+ memory_monitor::event("lcp-bwt-write-to-file-end");
+ memory_monitor::event("lcp-bwt-resize-variables-begin");
+ util::init_support(ds_rank_support, &index_done); // Create rank support
+
+ // Recalculate lcp_value_max and resize partial_lcp
+ lcp_value_offset = lcp_value_max-1;
+ size_type remaining_lcp_values = index_done.size()-ds_rank_support.rank(index_done.size());
+
+ uint8_t int_width_new = std::max(space_in_bit_for_lcp / remaining_lcp_values , (size_type)bits::hi(n-1)+1);
+ lcp_value_max = lcp_value_offset + (1ULL<<int_width_new);
+#ifdef STUDY_INFORMATIONS
+ std::cout << "# l=" << remaining_lcp_values << " b=" << (int)int_width_new << " lcp_value_max=" << lcp_value_max << std::endl;
+#endif
+ partial_lcp.width(int_width_new);
+ partial_lcp.resize(remaining_lcp_values);
+ util::set_to_value(partial_lcp, 0);
+ ++phase;
+ memory_monitor::event("lcp-bwt-resize-variables-end");
+ }
+ }
+ memory_monitor::event("lcp-bwt-calc-values-end");
+
+ // merge to file
+ memory_monitor::event("lcp-bwt-merge-to-file-begin");
+ if (phase) {
+ insert_lcp_values(partial_lcp, index_done, lcp_file, lcp_value, lcp_value_offset);
+ } else {
+ store_to_file(partial_lcp, lcp_file);
+ }
+ register_cache_file(conf::KEY_LCP, config);
+ memory_monitor::event("lcp-bwt-merge-to-file-end");
+}
+
+void construct_lcp_bwt_based2(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+
+ uint64_t n; // Input length
+ size_type buffer_size=1000000; // Size of the buffer
+ size_type lcp_value = 0; // current LCP value
+ std::string tmp_lcp_file = cache_file_name(conf::KEY_LCP, config)+"_tmp";
+// (1) Calculate LCP-Positions-Array: For each lcp_value (in ascending order) all its occurrences (in any order) in the lcp array
+ {
+ memory_monitor::event("lcp-bwt2-create-wt-huff-begin");
+ wt_huff<bit_vector, rank_support_v<>, select_support_scan<1>, select_support_scan<0>> wt_bwt;
+ construct(wt_bwt, cache_file_name(conf::KEY_BWT, config));
+ n = wt_bwt.size();
+ memory_monitor::event("lcp-bwt2-create-wt-huff-begin");
+
+ // Declare needed variables
+ memory_monitor::event("lcp-bwt2-init-begin");
+ size_type intervals = 0; // Number of intervals which are currently stored
+ size_type intervals_new = 0; // Number of new intervals
+
+ std::queue<size_type> q; // Queue for storing the intervals
+ std::vector<bit_vector> dict(2); // bit_vector for storing the intervals
+ size_type source = 0, target = 1; // Defines which bit_vector is source and which is target
+ bool queue_used = true; // Defines whether a queue (true) or the bit_vectors (false) was used to store intervals
+ size_type use_queue_and_wt = n/2048; // if intervals < use_queue_and_wt, then use queue and wavelet tree
+ // else use dictionary and wavelet tree
+
+ size_type quantity; // quantity of characters in interval
+ std::vector<unsigned char> cs(wt_bwt.sigma); // list of characters in the interval
+ std::vector<size_type> rank_c_i(wt_bwt.sigma); // number of occurrence of character in [0 .. i-1]
+ std::vector<size_type> rank_c_j(wt_bwt.sigma); // number of occurrence of character in [0 .. j-1]
+
+ // External storage of LCP-Positions-Array
+ bool new_lcp_value = false;
+ uint8_t int_width = bits::hi(n)+2;
+ int_vector_buffer<> lcp_positions_buf(tmp_lcp_file, std::ios::out, buffer_size, int_width); // Create buffer for positions of LCP entries
+ size_type idx_out_buf = 0;
+ bit_vector index_done(n+1, 0); // Bitvector which is true, if corresponding LCP value was already calculated
+
+ // Create C-array
+ std::vector<size_type> C; // C-Array: C[i] = number of occurrences of characters < i in the input
+ create_C_array(C, wt_bwt);
+ memory_monitor::event("lcp-bwt2-init-end");
+ // Calculate LCP-Positions-Array
+ memory_monitor::event("lcp-bwt2-calc-values-begin");
+
+ // Save position of first LCP-value
+ lcp_positions_buf[idx_out_buf++] = 0;
+ if (new_lcp_value) {
+ lcp_positions_buf[idx_out_buf-1] = lcp_positions_buf[idx_out_buf-1] + n;
+ new_lcp_value = false;
+ }
+ index_done[0] = true;
+
+ // calculate first intervals
+ interval_symbols(wt_bwt, 0, n, quantity, cs, rank_c_i, rank_c_j);
+ for (size_type i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ size_type a_new = C[c] + rank_c_i[i];
+ size_type b_new = C[c] + rank_c_j[i];
+
+ // Save LCP value and corresponding interval if not seen before
+ if (!index_done[b_new]) {
+ if (b_new < n) {
+ // Save position of LCP-value
+ lcp_positions_buf[idx_out_buf++] = b_new;
+ }
+ index_done[b_new] = true;
+
+ // Save interval
+ q.push(a_new);
+ q.push(b_new);
+ ++intervals;
+ }
+ }
+ ++lcp_value;
+ new_lcp_value = true;
+
+ // Calculate LCP positions
+ while (intervals) {
+ if (intervals < use_queue_and_wt && !queue_used) {
+ memory_monitor::event("lcp-bwt2-bitvec2queue-begin");
+ util::clear(dict[target]);
+
+ // Copy from bitvector to queue
+ size_type a2 = util::next_bit(dict[source], 0);
+ size_type b2 = util::next_bit(dict[source], a2+1);
+ while (b2 < dict[source].size()) {
+ q.push((a2-1)>>1);
+ q.push(b2>>1);
+ // Get next interval
+ a2 = util::next_bit(dict[source], b2+1);
+ b2 = util::next_bit(dict[source], a2+1);
+ }
+ util::clear(dict[source]);
+ memory_monitor::event("lcp-bwt2-bitvec2queue-end");
+ }
+ if (intervals >= use_queue_and_wt && queue_used) {
+ memory_monitor::event("lcp-bwt2-queue2bitvec-begin");
+ dict[source].resize(2*(n+1));
+ util::set_to_value(dict[source], 0);
+ // Copy from queue to bitvector
+ while (!q.empty()) {
+ dict[source][(q.front()<<1)+1 ] = 1; q.pop();
+ dict[source][(q.front()<<1) ] = 1; q.pop();
+ }
+ dict[target].resize(2*(n+1));
+ util::set_to_value(dict[target], 0);
+ memory_monitor::event("lcp-bwt2-queue2bitvec-end");
+ }
+
+ if (intervals < use_queue_and_wt) {
+ queue_used = true;
+ intervals_new = 0;
+ while (intervals) {
+ // Get next interval
+ size_type a = q.front(); q.pop();
+ size_type b = q.front(); q.pop();
+ --intervals;
+
+ interval_symbols(wt_bwt, a, b, quantity, cs, rank_c_i, rank_c_j);
+ for (size_type i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ size_type a_new = C[c] + rank_c_i[i];
+ size_type b_new = C[c] + rank_c_j[i];
+
+ // Save LCP value and corresponding interval if not seen before
+ if (!index_done[b_new]) {
+ // Save position of LCP-value
+ lcp_positions_buf[idx_out_buf++] = b_new;
+ if (new_lcp_value) {
+ // Mark new LCP-value
+ lcp_positions_buf[idx_out_buf-1] = lcp_positions_buf[idx_out_buf-1]+n;
+ new_lcp_value = false;
+ }
+ index_done[b_new] = true;
+
+ // Save interval
+ q.push(a_new);
+ q.push(b_new);
+ ++intervals_new;
+ }
+ }
+ }
+ intervals = intervals_new;
+ } else {
+ queue_used = false;
+ intervals = 0;
+ // get next interval
+ size_type a2 = util::next_bit(dict[source], 0);
+ size_type b2 = util::next_bit(dict[source], a2+1);
+
+ while (b2 < dict[source].size()) {
+ interval_symbols(wt_bwt, ((a2-1)>>1), (b2>>1), quantity, cs, rank_c_i, rank_c_j);
+ for (size_type i=0; i<quantity; ++i) {
+ unsigned char c = cs[i];
+ size_type a_new = C[c] + rank_c_i[i];
+ size_type b_new = C[c] + rank_c_j[i];
+ // Save LCP value if not seen before
+ if (!index_done[b_new]) {
+ // Save position of LCP-value
+ lcp_positions_buf[idx_out_buf++] = b_new;
+ if (new_lcp_value) {
+ // Mark new LCP-value
+ lcp_positions_buf[idx_out_buf-1] = lcp_positions_buf[idx_out_buf-1]+n;
+ new_lcp_value = false;
+ }
+ index_done[b_new] = true;
+ // Save interval
+ dict[target][(a_new<<1)+1] = 1;
+ dict[target][(b_new<<1) ] = 1;
+ ++intervals;
+ }
+ }
+ // get next interval
+ a2 = util::next_bit(dict[source], b2+1);
+ b2 = util::next_bit(dict[source], a2+1);
+ }
+ std::swap(source, target);
+ util::set_to_value(dict[target], 0);
+ }
+ ++lcp_value;
+ new_lcp_value = true;
+ }
+ memory_monitor::event("lcp-bwt2-calc-values-end");
+ lcp_positions_buf.close();
+ }
+// (2) Insert LCP entires into LCP array
+ {
+ memory_monitor::event("lcp-bwt2-reordering-begin");
+
+ int_vector_buffer<> lcp_positions(tmp_lcp_file, std::ios::in, buffer_size);
+
+ uint8_t int_width = bits::hi(lcp_value+1)+1; // How many bits are needed for one lcp_value?
+
+ // Algorithm does r=ceil(int_width/8) runs over LCP-Positions-Array.
+ // So in each run k>=(n/r) values of the lcp array must be calculated.
+ // Because k has to be a multiple of 8, we choose number_of_values = (k+16) - ((k+16)%8)
+ size_type number_of_values = ((n / ((int_width-1ULL)/8 + 1) + 16) & (~(0x7ULL)));
+ std::string lcp_file = cache_file_name(conf::KEY_LCP, config);
+ int_vector_buffer<> lcp_array(lcp_file, std::ios::out, number_of_values*int_width/8, int_width); // Create Output Buffer
+ number_of_values = lcp_array.buffersize()*8/int_width;
+
+ for (size_type position_begin=0, position_end = number_of_values; position_begin<n and number_of_values>0; position_begin=position_end, position_end+=number_of_values) {
+#ifdef STUDY_INFORMATIONS
+ std::cout << "# number_of_values=" << number_of_values << " fill lcp_values with " << position_begin << " <= position <" << position_end << ", each lcp-value has " << (int)int_width << " bit, lcp_value_max=" << lcp_value << " n=" << n << std::endl;
+#endif
+ size_type lcp_value = 0;
+ for (size_type i=0; i < n; ++i) {
+ size_type position = lcp_positions[i];
+ if (position>n) {
+ position -= n;
+ ++lcp_value;
+ }
+ if (position_begin <= position and position < position_end) {
+ lcp_array[position] = lcp_value;
+ }
+ }
+ }
+ // Close file
+ lcp_array.close();
+ register_cache_file(conf::KEY_LCP, config);
+ lcp_positions.close(true); // close buffer and remove file
+ memory_monitor::event("lcp-bwt2-reordering-end");
+ } // End of phase 2
+}
+
+//void check_lcp(std::string lcpI, std::string lcpII, std::string id)
+//{
+// typedef int_vector<>::size_type size_type;
+// int_vector<> lcp1,lcp2;
+// load_from_file(lcp1, (lcpI+"_"+id));
+// load_from_file(lcp2, (lcpII+"_"+id));
+// if (lcp1 != lcp2) {
+// std::cout<<"lcp results of "<< lcpI << "and " <<lcpII<<" differ"<<std::endl;
+// for (size_type i=0, cnt=0; i<lcp1.size() and cnt<10; ++i) {
+// if (lcp1[i] != lcp2[i]) {
+// std::cout<<"i="<<i<<" "<<lcpI<<"[i]="<<lcp1[i]<<" "<<lcpII<<"[i]="<<lcp2[i]<<std::endl;
+// ++cnt;
+// }
+// }
+// }
+//}
+//
+} // end namespace sdsl
diff --git a/lib/construct_lcp_helper.cpp b/lib/construct_lcp_helper.cpp
new file mode 100644
index 0000000..49d3f2a
--- /dev/null
+++ b/lib/construct_lcp_helper.cpp
@@ -0,0 +1,119 @@
+#include "sdsl/construct_lcp_helper.hpp"
+#include "sdsl/int_vector.hpp"
+#include <algorithm>
+
+namespace sdsl
+{
+
+//! Merges a partial LCP array into the LCP array on disk.
+/*!
+ * \param partial_lcp Vector containing LCP values for all indexes \f$i\f$ with
+ * index_done[i] == 0. Let x=partail_lcp[rank(index_done, i, 0)];
+ * LCP[i]=x if x!=0 and index_done[i] == 0
+ * \param lcp_file Path to the LCP array on disk.
+ * \param index_done Entry index_done[i] indicates if LCP[i] is already calculated.
+ * \param max_lcp_value Maximum known LCP value
+ * \param lcp_value_offset Largest LCP value in lcp_file
+ */
+void insert_lcp_values(int_vector<>& partial_lcp, bit_vector& index_done, std::string lcp_file, uint64_t max_lcp_value, uint64_t lcp_value_offset)
+{
+ std::string tmp_lcp_file = lcp_file+"_TMP";
+ const uint64_t buffer_size = 1000000; // has to be a multiple of 64
+ typedef int_vector<>::size_type size_type;
+ int_vector_buffer<> lcp_buffer(lcp_file, std::ios::in, buffer_size); // open lcp_file
+ uint64_t n = lcp_buffer.size();
+
+ // open tmp_lcp_file
+ uint8_t int_width = bits::hi(max_lcp_value-1)+1;
+ int_vector_buffer<> out_buf(tmp_lcp_file, std::ios::out, buffer_size, int_width); // Output buffer
+ // Write values into buffer
+ for (size_type i=0, calc_idx=0; i < n; ++i) {
+ if (index_done[i]) { // If value was already calculated
+ out_buf[i] = lcp_buffer[i]; // Copy value
+ } else {
+ if (partial_lcp[calc_idx]) { // If value was calculated now
+ // Insert value
+ out_buf[i] = partial_lcp[calc_idx]+lcp_value_offset;
+ index_done[i] = true;
+ }
+ ++calc_idx;
+ }
+ }
+ // Close file and replace old file with new one
+ out_buf.close();
+ sdsl::rename(tmp_lcp_file, lcp_file);
+}
+
+buffered_char_queue::buffered_char_queue():m_widx(0), m_ridx(0), m_sync(true), m_disk_buffered_blocks(0), m_c('?'),m_rb(0), m_wb(0) {};
+
+void buffered_char_queue::init(const std::string& dir, char c)
+{
+ m_c = c;
+ m_file_name = dir+"buffered_char_queue_"+util::to_string(util::pid());
+// m_stream.rdbuf()->pubsetbuf(0, 0);
+}
+
+buffered_char_queue::~buffered_char_queue()
+{
+ m_stream.close();
+ sdsl::remove(m_file_name);
+}
+
+void buffered_char_queue::push_back(uint8_t x)
+{
+ m_write_buf[m_widx] = x;
+ if (m_sync) {
+ m_read_buf[m_widx] = x;
+ }
+ ++m_widx;
+ if (m_widx == m_buffer_size) {
+ if (!m_sync) { // if not sync, write block to disk
+ if (!m_stream.is_open()) {
+ m_stream.open(m_file_name, std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc);
+ }
+ m_stream.seekp(m_buffer_size * (m_wb++), std::ios::beg);
+ m_stream.write((char*) m_write_buf, m_buffer_size);
+ ++m_disk_buffered_blocks;
+ }
+ m_sync = 0;
+ m_widx = 0;
+ }
+}
+
+uint8_t buffered_char_queue::pop_front()
+{
+ uint8_t x = m_read_buf[m_ridx];
+ ++m_ridx;
+ if (m_ridx == m_buffer_size) {
+ if (m_disk_buffered_blocks > 0) {
+ m_stream.seekg(m_buffer_size * (m_rb++), std::ios::beg);
+ m_stream.read((char*) m_read_buf, m_buffer_size);
+ --m_disk_buffered_blocks;
+ } else { // m_disk_buffered_blocks == 0
+ m_sync = 1;
+ memcpy(m_read_buf, m_write_buf, m_widx+1);
+ }
+ m_ridx = 0;
+ }
+ return x;
+}
+
+void lcp_info(cache_config& config)
+{
+ typedef int_vector<>::size_type size_type;
+ int_vector_buffer<> lcp_buf(cache_file_name(conf::KEY_LCP, config));
+ size_type n = lcp_buf.size();
+
+ size_type max_lcp = 0;
+ size_type sum_lcp = 0;
+ for (size_type i=0; i < n; ++i) {
+ if (lcp_buf[i] > max_lcp)
+ max_lcp = lcp_buf[i];
+ sum_lcp += lcp_buf[i];
+ }
+ std::cout<<"# max lcp = " << max_lcp << std::endl;
+ std::cout<<"# sum lcp = " << sum_lcp << std::endl;
+ std::cout<<"# avg lcp = " << sum_lcp/(double)n << std::endl;
+}
+
+} // end namespace sdsl
diff --git a/lib/construct_sa.cpp b/lib/construct_sa.cpp
new file mode 100644
index 0000000..9686ca7
--- /dev/null
+++ b/lib/construct_sa.cpp
@@ -0,0 +1,24 @@
+#include "sdsl/construct_sa.hpp"
+
+namespace sdsl
+{
+
+void construct_sa_se(cache_config& config)
+{
+ int_vector<8> text;
+ load_from_file(text, cache_file_name(conf::KEY_TEXT, config));
+
+ if (text.size() <= 2) {
+ // If text is c$ or $ write suffix array [1, 0] or [0]
+ int_vector_buffer<> sa(cache_file_name(conf::KEY_SA, config), std::ios::out, 8, 2);
+ if (text.size() == 2) {
+ sa.push_back(1);
+ }
+ sa.push_back(0);
+ } else {
+ _construct_sa_se<int_vector<8>>(text, cache_file_name(conf::KEY_SA, config), 256, 0);
+ }
+ register_cache_file(conf::KEY_SA, config);
+}
+
+}
diff --git a/lib/construct_sa_se.cpp b/lib/construct_sa_se.cpp
new file mode 100644
index 0000000..e055d30
--- /dev/null
+++ b/lib/construct_sa_se.cpp
@@ -0,0 +1,202 @@
+#include "sdsl/construct_sa_se.hpp"
+
+namespace sdsl
+{
+
+void _construct_sa_IS(int_vector<> &text, int_vector<> &sa, std::string& filename_sa, size_t n, size_t text_offset, size_t sigma, uint64_t recursion)
+{
+ uint64_t buffersize = 1024*1024/8;
+
+ size_t name = 0;
+ size_t number_of_lms_strings = 0;
+ std::string filename_c_array = tmp_file(filename_sa, "_c_array"+util::to_string(recursion));
+ // Phase 1
+ {
+ std::vector<uint64_t> bkt(sigma, 0);
+ // Step 1 - Count characters into c array
+ // TODO: better create this in higher recursion-level
+ for (size_t i=0; i<n; ++i) {
+ ++bkt[text[text_offset+i]];
+ }
+
+ // Step 1.5 save them into cached_external_array
+ int_vector_buffer<> c_array(filename_c_array, std::ios::out, buffersize, 64);
+ for (size_t c=0; c<sigma; ++c) {
+ c_array[c] = bkt[c];
+ }
+
+ // Step 2 Calculate End-Pointer of Buckets
+ bkt[0] = 0;
+ for (size_t c=1; c<sigma; ++c) {
+ bkt[c] = bkt[c-1]+bkt[c];
+ }
+
+ // Step 3 - Insert S*-positions into correct bucket of SA but not in correct order inside the buckets
+ for (size_t i=n-2, was_s_typ = 1; i<n; --i) {
+ if (text[text_offset+i]>text[text_offset+i+1]) {
+ if (was_s_typ) {
+ sa[bkt[text[text_offset+i+1]]--] = i+1;
+ ++number_of_lms_strings;
+ was_s_typ = 0;
+ }
+ } else if (text[text_offset+i]<text[text_offset+i+1]) {
+ was_s_typ = 1;
+ }
+ }
+
+ // Step 4 - Calculate Begin-Pointer of Buckets
+ bkt[0] = 0;
+ for (size_t c=1; c<sigma; ++c) {
+ bkt[c] = bkt[c-1]+c_array[c-1];
+ }
+
+ // Step 5 - Scan from Left-To-Right to induce L-Types
+ for (size_t i=0; i<n; ++i) {
+ if (sa[i] > 0 and text[text_offset+ sa[i] ] <= text[text_offset+ sa[i]-1 ]) { // faster than if(sa[i]>0 and bkt_beg[text[ sa[i]-1 ]] > i)
+ sa[bkt[text[text_offset+ sa[i]-1 ]]++] = sa[i]-1;
+ sa[i] = 0;
+ }
+ }
+
+ // Step 6 - Scan from Right-To-Left to induce S-Types
+ bkt[0] = 0;
+ for (size_t c=1; c<sigma; ++c) {
+ bkt[c] = bkt[c-1]+c_array[c];
+ }
+ c_array.close();
+ c_array.buffersize(0);
+
+ for (size_t i=n-1, endpointer=n; i<n; --i) {
+ if (sa[i]>0) {
+ if (text[text_offset+ sa[i]-1 ] <= text[text_offset+ sa[i] ]) { // faster than if(bkt_end[text[ sa[i]-1 ]] < i)
+ sa[bkt[text[text_offset+ sa[i]-1 ]]--] = sa[i]-1;
+ } else {
+ sa[--endpointer] = sa[i];
+ }
+ sa[i] = 0;
+ }
+ }
+
+ // Step 7 - Determine length of LMS-Strings
+ for (size_t i=n-2, end=n-2, was_s_typ = 1; i<n; --i) {
+ if (text[text_offset+i]>text[text_offset+i+1]) {
+ if (was_s_typ) {
+ sa[(i+1)>>1] = end-i;
+ end = i+1;
+ was_s_typ = 0;
+ }
+ } else if (text[text_offset+i]<text[text_offset+i+1]) {
+ was_s_typ = 1;
+ }
+ }
+
+ // Step 8 - Rename
+ for (size_t i=n-number_of_lms_strings+1, cur_pos=0, cur_len=0, last_pos=n-1, last_len=1; i<n; ++i) {
+ cur_pos = sa[i];
+ cur_len = sa[(cur_pos>>1)];
+ if (cur_len == last_len) {
+ size_t l = 0;
+ while (l < cur_len and text[text_offset+cur_pos+l] == text[text_offset+last_pos+l]) {
+ ++l;
+ }
+ if (l >= cur_len) {
+ --name;
+ }
+ }
+ sa[(cur_pos>>1)] = ++name;
+ last_pos = cur_pos;
+ last_len = cur_len;
+ }
+ }
+
+ // Step 9 - Calculate SA of new string - in most cases recursive
+ if (name+1 < number_of_lms_strings) {
+ // Move Names to the end
+ for (size_t i=0, t=n-number_of_lms_strings; i<(n>>1); ++i) {
+ if (sa[i] > 0) {
+ sa[t++] = sa[i];
+ sa[i] = 0;
+ }
+ }
+ sa[n-1] = 0;
+
+ // Recursive call
+ std::string filename_sa_rec = tmp_file(filename_sa, "_sa_rec"+util::to_string(recursion+1));
+ _construct_sa_IS(sa, sa, filename_sa_rec, number_of_lms_strings, n-number_of_lms_strings, name+1, recursion+1);
+
+ for (size_t i=n-2, endpointer = n-1, was_s_typ = 1; i<n; --i) {
+ if (text[text_offset+i]>text[text_offset+i+1]) {
+ if (was_s_typ) {
+ sa[endpointer--] = i+1;
+ was_s_typ = 0;
+ }
+ } else if (text[text_offset+i]<text[text_offset+i+1]) {
+ was_s_typ = 1;
+ }
+ }
+
+ // Sort S*-positions in correct order into SA
+ for (size_t i=0; i<number_of_lms_strings; ++i) {
+ size_t pos = sa[i];
+ sa[i] = sa[n-number_of_lms_strings+pos];
+ sa[n-number_of_lms_strings+pos] = 0;
+ }
+ } else {
+ // Move s*-Positions to front
+ sa[0] = n-1;
+ for (size_t i=1; i<number_of_lms_strings; ++i) {
+ sa[i] = sa[n-number_of_lms_strings+i];
+ sa[n-number_of_lms_strings+i] = 0;
+ }
+ // Clear lex. names
+ for (size_t i=number_of_lms_strings; i<(n>>1); ++i) {
+ sa[i] = 0;
+ }
+ }
+
+ // Phase 3
+ {
+ // Step 10 - Count characters into c array
+
+ // Step 11 - Calculate End-Pointer of Buckets
+ int_vector_buffer<> c_array(filename_c_array, std::ios::in, buffersize, 64);
+ std::vector<uint64_t> bkt(sigma, 0);
+ for (size_t c=1; c<sigma; ++c) {
+ bkt[c] = bkt[c-1]+c_array[c];
+ }
+
+ // Step 12 - Move S*-positions in correct order into SA
+ for (size_t i=number_of_lms_strings-1; i<n; --i) {
+ size_t pos = sa[i];
+ sa[i] = 0;
+ sa[ bkt[text[text_offset+pos]]-- ] = pos;
+ }
+
+ // Step 13 - Calculate Begin-Pointer of Buckets
+ bkt[0] = 0;
+ for (size_t c=1; c<sigma; ++c) {
+ bkt[c] = bkt[c-1]+c_array[c-1];
+ }
+
+ // Step 14 - Scan from Left-To-Right to induce L-Types
+ for (size_t i=0; i<n; ++i) {
+ if (sa[i] > 0 and text[text_offset+ sa[i] ] <= text[text_offset+ sa[i]-1 ]) { // faster than if(sa[i]>0 and bkt_beg[text[ sa[i]-1 ]] > i)
+ sa[bkt[text[text_offset+ sa[i]-1 ]]++] = sa[i]-1;
+ }
+ }
+
+ // Step 15 - Scan from Right-To-Left to induce S-Types
+ bkt[0] = 0;
+ for (size_t c=1; c<sigma; ++c) {
+ bkt[c] = bkt[c-1]+c_array[c];
+ }
+ for (size_t i=n-1; i<n; --i) {
+ if (sa[i] > 0 and text[text_offset+sa[i]-1] <= text[text_offset+sa[i]]) {
+ sa[bkt[text[text_offset+ sa[i]-1 ]]--] = sa[i]-1;
+ }
+ }
+ c_array.close(true);
+ }
+}
+
+}
diff --git a/lib/csa_alphabet_strategy.cpp b/lib/csa_alphabet_strategy.cpp
new file mode 100644
index 0000000..eb76a93
--- /dev/null
+++ b/lib/csa_alphabet_strategy.cpp
@@ -0,0 +1,122 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2012 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+#include "sdsl/csa_alphabet_strategy.hpp"
+
+namespace sdsl
+{
+
+const char* key_trait<8>::KEY_BWT = conf::KEY_BWT;
+const char* key_trait<8>::KEY_TEXT = conf::KEY_TEXT;
+
+byte_alphabet::byte_alphabet(int_vector_buffer<8>& text_buf, int_vector_size_type len):
+ char2comp(m_char2comp), comp2char(m_comp2char), C(m_C), sigma(m_sigma)
+{
+ m_sigma = 0;
+ if (0 == len or 0 == text_buf.size())
+ return;
+ assert(len <= text_buf.size());
+ // initialize vectors
+ util::assign(m_C , int_vector<64>(257, 0));
+ util::assign(m_char2comp, int_vector<8>(256,0));
+ util::assign(m_comp2char, int_vector<8>(256,0));
+ // count occurrences of each symbol
+ for (size_type i=0; i < len; ++i) {
+ ++m_C[text_buf[i]];
+ }
+ assert(1 == m_C[0]); // null-byte should occur exactly once
+ m_sigma = 0;
+ for (int i=0; i<256; ++i)
+ if (m_C[i]) {
+ m_char2comp[i] = m_sigma;
+ m_comp2char[sigma] = i;
+ m_C[m_sigma] = m_C[i];
+ ++m_sigma;
+ }
+ m_comp2char.resize(m_sigma);
+ m_C.resize(m_sigma+1);
+ for (int i=(int)m_sigma; i > 0; --i) m_C[i] = m_C[i-1];
+ m_C[0] = 0;
+ for (int i=1; i <= (int)m_sigma; ++i) m_C[i] += m_C[i-1];
+ assert(C[sigma]==len);
+}
+
+
+byte_alphabet::byte_alphabet(): char2comp(m_char2comp), comp2char(m_comp2char), C(m_C), sigma(m_sigma)
+{
+ m_sigma = 0;
+}
+
+void byte_alphabet::copy(const byte_alphabet& bas)
+{
+ m_char2comp = bas.m_char2comp;
+ m_comp2char = bas.m_comp2char;
+ m_C = bas.m_C;
+ m_sigma = bas.m_sigma;
+}
+
+byte_alphabet::byte_alphabet(const byte_alphabet& bas): char2comp(m_char2comp), comp2char(m_comp2char), C(m_C), sigma(m_sigma)
+{
+ copy(bas);
+}
+
+byte_alphabet& byte_alphabet::operator=(const byte_alphabet& bas)
+{
+ if (this != &bas) {
+ copy(bas);
+ }
+ return *this;
+}
+
+byte_alphabet& byte_alphabet::operator=(byte_alphabet&& bas)
+{
+ if (this != &bas) {
+ m_char2comp = std::move(bas.m_char2comp);
+ m_comp2char = std::move(bas.m_comp2char);
+ m_C = std::move(bas.m_C);
+ m_sigma = std::move(bas.m_sigma);
+ }
+ return *this;
+}
+
+void byte_alphabet::swap(byte_alphabet& bas)
+{
+ m_char2comp.swap(bas.m_char2comp);
+ m_comp2char.swap(bas.m_comp2char);
+ m_C.swap(bas.m_C);
+ std::swap(m_sigma, bas.m_sigma);
+}
+
+byte_alphabet::size_type byte_alphabet::serialize(std::ostream& out, structure_tree_node* v, std::string name)const
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(*this));
+ size_type written_bytes = 0;
+ written_bytes += m_char2comp.serialize(out, child, "m_char2comp");
+ written_bytes += m_comp2char.serialize(out, child, "m_comp2char");
+ written_bytes += m_C.serialize(out, child, "m_C");
+ written_bytes += write_member(m_sigma, out, child, "m_sigma");
+ structure_tree::add_size(child, written_bytes);
+ return written_bytes;
+}
+
+void byte_alphabet::load(std::istream& in)
+{
+ m_char2comp.load(in);
+ m_comp2char.load(in);
+ m_C.load(in);
+ read_member(m_sigma, in);
+}
+}
diff --git a/lib/int_vector.cpp b/lib/int_vector.cpp
new file mode 100644
index 0000000..9eb7c61
--- /dev/null
+++ b/lib/int_vector.cpp
@@ -0,0 +1,26 @@
+#include "sdsl/int_vector.hpp"
+
+namespace sdsl
+{
+
+
+template<>
+void int_vector<0>::width(const uint8_t new_int_width)
+{
+ if (0 < new_int_width and new_int_width <= 64)
+ m_width = new_int_width;
+ else
+ m_width = 64;
+}
+
+template<>
+void bit_vector::flip()
+{
+ if (!empty()) {
+ for (uint64_t i=0; i<(capacity()>>6); ++i) {
+ m_data[i] = ~m_data[i];
+ }
+ }
+}
+
+}
diff --git a/lib/io.cpp b/lib/io.cpp
new file mode 100644
index 0000000..7b84468
--- /dev/null
+++ b/lib/io.cpp
@@ -0,0 +1,114 @@
+#include "sdsl/io.hpp"
+#include "sdsl/sfstream.hpp"
+#include "sdsl/util.hpp"
+#include <vector>
+
+namespace sdsl
+{
+
+
+bool store_to_file(const char* v, const std::string& file)
+{
+ osfstream out(file, std::ios::binary | std::ios::trunc | std::ios::out);
+ if (!out) {
+ if (util::verbose) {
+ std::cerr<<"ERROR: store_to_file(const char *v, const std::string&)"<<std::endl;
+ return false;
+ }
+ }
+ uint64_t n = strlen((const char*)v);
+ out.write(v, n);
+ out.close();
+ return true;
+}
+
+bool store_to_checked_file(const char* v, const std::string& file)
+{
+ std::string checkfile = file+"_check";
+ osfstream out(checkfile, std::ios::binary | std::ios::trunc | std::ios::out);
+ if (!out) {
+ if (util::verbose) {
+ std::cerr<<"ERROR: store_to_checked_file(const char *v, const std::string&)"<<std::endl;
+ return false;
+ }
+ }
+ add_hash(v, out);
+ out.close();
+ return store_to_file(v, file);
+}
+
+
+template<>
+size_t write_member<std::string>(const std::string& t, std::ostream& out, structure_tree_node* v, std::string name)
+{
+ structure_tree_node* child = structure_tree::add_child(v, name, util::class_name(t));
+ size_t written_bytes = 0;
+ written_bytes += write_member(t.size(), out, child, "length");
+ out.write(t.c_str(), t.size());
+ written_bytes += t.size();
+ structure_tree::add_size(v, written_bytes);
+ return written_bytes;
+}
+
+template<>
+void read_member<std::string>(std::string& t, std::istream& in)
+{
+ std::string::size_type size;
+ read_member(size, in);
+ char* buf = new char[size];
+ in.read(buf, size);
+ std::string temp(buf, size);
+ delete [] buf;
+ t.swap(temp);
+}
+
+uint64_t _parse_number(std::string::const_iterator& c, const std::string::const_iterator& end)
+{
+ std::string::const_iterator s = c;
+ while (c != end and isdigit(*c)) ++c;
+ if (c > s) {
+ return stoull(std::string(s,c));
+ } else {
+ return 0;
+ }
+}
+
+std::string cache_file_name(const std::string& key, const cache_config& config)
+{
+ return config.dir+"/"+key+"_"+config.id+".sdsl";
+}
+
+void register_cache_file(const std::string& key, cache_config& config)
+{
+ std::string file_name = cache_file_name(key, config);
+ isfstream in(file_name);
+ if (in) { // if file exists, register it.
+ config.file_map[key] = file_name;
+ }
+}
+
+
+bool cache_file_exists(const std::string& key, const cache_config& config)
+{
+ std::string file_name = cache_file_name(key, config);
+ isfstream in(file_name);
+ if (in) {
+ in.close();
+ return true;
+ }
+ return false;
+}
+
+std::string tmp_file(const cache_config& config, std::string name_part)
+{
+ return config.dir+"/"+ util::to_string(util::pid()) + "_" + util::to_string(util::id()) + name_part + ".sdsl";
+}
+
+std::string tmp_file(const std::string& filename, std::string name_part)
+{
+ return util::dirname(filename) + "/" + util::to_string(util::pid()) + "_" +
+ util::to_string(util::id()) + name_part + ".sdsl";
+}
+
+}// end namespace sdsl
+
diff --git a/lib/lcp_support_tree.cpp b/lib/lcp_support_tree.cpp
new file mode 100644
index 0000000..4076156
--- /dev/null
+++ b/lib/lcp_support_tree.cpp
@@ -0,0 +1,43 @@
+#include "sdsl/lcp_support_tree.hpp"
+
+namespace sdsl
+{
+
+void construct_first_child_lcp(int_vector_buffer<>& lcp_buf, int_vector<>& fc_lcp)
+{
+ typedef int_vector_size_type size_type;
+ size_type n = lcp_buf.size();
+ if (n == 0) { // if n == 0 we are done
+ fc_lcp = int_vector<>(0);
+ }
+ {
+ int_vector<> tmp(n, 0, bits::hi(n)+1);
+ fc_lcp.swap(tmp);
+ }
+
+ size_type fc_cnt=0; // first child counter
+ sorted_multi_stack_support vec_stack(n);
+ size_type y;
+ for (size_type i=0, x; i < n; ++i) {
+ x = lcp_buf[i];
+ while (!vec_stack.empty() and x < vec_stack.top()) {
+ y = vec_stack.top();
+ if (vec_stack.pop()) {
+ fc_lcp[fc_cnt++] = y;
+ }
+ }
+ vec_stack.push(x);
+ }
+
+ while (!vec_stack.empty()) {
+ y = vec_stack.top();
+ if (vec_stack.pop()) {
+ fc_lcp[fc_cnt++] = y;
+ }
+ }
+ if (fc_cnt < fc_lcp.size()) {
+ fc_lcp.resize(fc_cnt);
+ }
+}
+
+}
diff --git a/lib/louds_tree.cpp b/lib/louds_tree.cpp
new file mode 100644
index 0000000..fe51b76
--- /dev/null
+++ b/lib/louds_tree.cpp
@@ -0,0 +1,10 @@
+#include "sdsl/louds_tree.hpp"
+
+namespace sdsl
+{
+std::ostream& operator<<(std::ostream& os, const louds_node& v)
+{
+ os<<"("<<v.nr<<","<<v.pos<<")";
+ return os;
+}
+}
diff --git a/lib/memory_management.cpp b/lib/memory_management.cpp
new file mode 100644
index 0000000..6bebad2
--- /dev/null
+++ b/lib/memory_management.cpp
@@ -0,0 +1,648 @@
+#include <chrono>
+#include <algorithm>
+#include "sdsl/memory_management.hpp"
+
+using namespace std::chrono;
+
+namespace sdsl
+{
+
+void output_event_json(std::ostream& out,const memory_monitor::mm_event& ev,const memory_monitor& m)
+{
+ out << "\t\t" << "\"name\" : " << "\"" << ev.name << "\",\n";
+ out << "\t\t" << "\"usage\" : [" << "\n";
+ for (size_t j=0; j<ev.allocations.size(); j++) {
+ out << "\t\t\t[" << duration_cast<milliseconds>(ev.allocations[j].timestamp-m.start_log).count()
+ << "," << ev.allocations[j].usage << "]";
+ if (j+1<ev.allocations.size()) {
+ out << ",\n";
+ } else {
+ out << "\n";
+ }
+ }
+ out << "\t\t" << "]\n";
+}
+
+template<>
+void write_mem_log<JSON_FORMAT>(std::ostream& out,const memory_monitor& m)
+{
+ auto events = m.completed_events;
+ std::sort(events.begin(),events.end());
+
+ // output
+ out << "[\n";
+ for (size_t i=0; i<events.size(); i++) {
+ out << "\t{\n";
+ output_event_json(out,events[i],m);
+ if (i<events.size()-1) {
+ out << "\t},\n";
+ } else {
+ out << "\t}\n";
+ }
+ }
+ out << "]\n";
+}
+
+std::string create_mem_html_header()
+{
+ std::stringstream jsonheader;
+ jsonheader
+ << "<html>\n"
+ << "<head>\n"
+ << "<meta charset=\"utf-8\">\n"
+ << "<style>\n"
+ << " body { font: 11px sans-serif; }\n"
+ << " .rule { height: 90%; position: absolute; border-right: 1px dotted #000; text-align: right; }\n"
+ << "</style>\n"
+ << "<title>sdsl memory usage visualization</title>\n"
+ << "<script src=\"http://d3js.org/d3.v3.js\"></script>\n"
+ << "</head>\n"
+ << "<body marginwidth=\"0\" marginheight=\"0\">\n"
+ << "<button><a id=\"download\">Save as SVG</a></button>\n"
+ << "<div class=\"chart\"><div id=\"visualization\"></div></div><script>\n";
+ return jsonheader.str();
+}
+
+std::string create_mem_js_body(const std::string& jsonObject)
+{
+ std::stringstream jsonbody;
+ jsonbody
+ << "var events = " << jsonObject << ";\n"
+ << "var w = window,d = document,e = d.documentElement,g = d.getElementsByTagName('body')[0],\n"
+ << " xw = w.innerWidth || e.clientWidth || g.clientWidth,\n"
+ << " yh = w.innerHeight || e.clientHeight || g.clientHeight;\n\n"
+ << "var margin = {top: 20,right: 80,bottom: 120,left: 120},\n"
+ << " width = xw - margin.left - margin.right,height = yh - margin.top - margin.bottom;\n"
+ << "var x = d3.scale.linear().range([0, width]);\n"
+ << "var y = d3.scale.linear().range([height, 0]);\n"
+ << "var xAxis = d3.svg.axis().scale(x).orient(\"bottom\");\n"
+ << "var yAxis = d3.svg.axis().scale(y).orient(\"left\").ticks(5);\n"
+ << "var color = d3.scale.category10();\n"
+ << "var x_max = d3.max(events, function (d) { return d3.max(d.usage, function (u) { return u[0] / 1000;})})\n"
+ << "var y_max = d3.max(events, function (d) { return d3.max(d.usage, function (u) { return 1.1 * u[1] / (1024 * 1024);})})\n"
+ << "var peak = d3.max(events, function (d) { return d3.max(d.usage, function (u) { return u[1]; })})\n"
+ << "var data = []\nevents.forEach(function (d) { data = data.concat(d.usage); });\n"
+ << "var peakelem = data.filter(function (a) { return a[1] == peak; });\n"
+ << "var peakelem = peakelem.splice(0,1);\n"
+ << "x.domain([0, x_max]);\n y.domain([0, y_max]);\n"
+ << "var svg = d3.select(\"#visualization\").append(\"svg\")\n"
+ << " .attr(\"width\", width + margin.left + margin.right)\n"
+ << " .attr(\"height\", height + margin.top + margin.bottom)\n"
+ << " .attr(\"xmlns\", \"http://www.w3.org/2000/svg\")\n"
+ << " .append(\"g\").attr(\"transform\",\"translate(\" + margin.left + \",\" + margin.top + \")\");\n\n"
+ << " svg.append(\"g\").attr(\"class\", \"xaxis\").attr(\"transform\", \"translate(0,\" + height + \")\")\n"
+ << " .call(xAxis).append(\"text\").attr(\"text-anchor\", \"end\")\n"
+ << " .attr(\"shape-rendering\", \"crispEdges\").attr(\"x\", width / 2 + 50).attr(\"y\", 70).attr(\"shape-rendering\", \"crispEdges\")\n"
+ << " .attr(\"font-family\", \"sans-serif\").attr(\"font-size\", \"20px\").text(\"Time (seconds)\");\n\n"
+ << "svg.append(\"g\").attr(\"class\", \"yaxis\").call(yAxis).append(\"text\").attr(\"transform\", \"rotate(-90)\").attr(\"x\", -height / 2 + 50)\n"
+ << " .attr(\"y\", -80).attr(\"shape-rendering\", \"crispEdges\").attr(\"font-family\", \"sans-serif\").attr(\"font-size\", \"20px\").style(\"text-anchor\", \"end\")\n"
+ << " .text(\"Memory Usage (MiB)\");\n\n"
+ << "svg.selectAll(\".tick text\").style(\"font-size\", \"20px\");\n"
+ << "svg.selectAll(\".xaxis .tick text\").attr(\"dy\", 23);\nsvg.selectAll(\".yaxis .tick text\").attr(\"dx\", -10);\n"
+ << "svg.selectAll(\"line\").attr(\"fill\", \"none\").attr(\"stroke\", \"black\")\nsvg.selectAll(\"path\").attr(\"fill\", \"none\").attr(\"stroke\", \"black\")\n\n"
+ << "svg.selectAll(\"line.horizontalGrid\").data(y.ticks(5)).enter().append(\"line\")\n"
+ << " .attr({\"class\": \"horizontalGrid\",\"x1\": 0,\"x2\": width,\"y1\": function (d) { return y(d);},\n"
+ << " \"y2\": function (d) { return y(d); }, \"fill\": \"none\", \"shape-rendering\": \"crispEdges\",\n"
+ << " \"stroke\": \"lightgrey\",\"stroke-dasharray\": \"10,10\",\"stroke-width\": \"1.5px\"});\n\n"
+ << "var area = d3.svg.area().x(function (d) { return x(d[0] / 1000);}).y0(height).y1(function (d) { return y(d[1] / (1024 * 1024))});\n\n"
+ << "var ev = svg.selectAll(\".event\").data(events).enter().append(\"svg:path\").attr(\"class\", \"area\")\n"
+ << " .attr(\"fill\", function (d) { return d3.rgb(color(d.name)); })\n"
+ << " .attr(\"d\", function (d) { return area(d.usage) })\n"
+ << " .style(\"stroke\", function (d) { return d3.rgb(color(d.name)).darker(2);}).style(\"stroke-width\", \"2px\")\n\n"
+ << "svg.selectAll(\".dot\").data(peakelem).enter().append(\"circle\").attr(\"r\", 3).attr(\"fill\", \"red\")\n"
+ << " .attr(\"cx\", function (d) {return x(d[0] / 1000)})\n"
+ << " .attr(\"cy\", function (d) {return y(d[1] / (1024 * 1024))})\n"
+ << " .attr(\"fill\", \"red\").attr(\"stroke-width\", 2).attr(\"stroke\", \"#cc0000\")\n\n"
+ << "svg.selectAll(\".dot\").data(peakelem).enter().append(\"svg:text\")\n"
+ << " .attr(\"x\", function (d) {return x(d[0] / 1000)}).attr(\"y\", function (d) {return y(d[1] / (1024 * 1024) * 1.025)})\n"
+ << " .text(function (d) {return \"Peak Usage: \" + Math.round(d[1] / (1024 * 1024)) + \" MB\"})\n"
+ << " .attr(\"font-size\", 12).attr(\"fill\", \"red\");\n\n"
+ << "svg.selectAll(\".dot\").data(peakelem).enter().append(\"circle\")\n"
+ << " .attr(\"r\", 5).attr(\"fill\", \"red\")\n"
+ << " .attr(\"cx\", function (d) {return x(d[0] / 1000)})\n"
+ << " .attr(\"cy\", function (d) {return y(d[1] / (1024 * 1024))})\n"
+ << " .attr(\"fill\", \"none\").attr(\"stroke-width\", 2).attr(\"stroke\", \"#cc0000\").each(pulsepeak());\n\n"
+ << "function pulsepeak() { return function (d, i, j) {\n"
+ << " d3.select(this).attr(\"r\", 5).style(\"stroke-opacity\", 1.0).transition()\n"
+ << " .ease(\"linear\").duration(1000).attr(\"r\", 10).style(\"stroke-opacity\", 0.0).each(\"end\", pulsepeak());};}\n\n"
+ << "var vertical = d3.select(\".chart\").append(\"div\").attr(\"class\", \"remove\")\n"
+ << " .style(\"position\", \"absolute\").style(\"z-index\", \"19\").style(\"width\", \"1px\")\n"
+ << " .style(\"height\", height - margin).style(\"top\", \"30px\").style(\"bottom\", \"50px\")\n"
+ << " .style(\"left\", \"0px\").style(\"opacity\", \"0.4\").style(\"background\", \"black\");\n\n"
+ << "var tooltip = d3.select(\".chart\").append(\"div\").attr(\"class\", \"remove\")\n"
+ << " .style(\"position\", \"absolute\").style(\"z-index\", \"20\").style(\"visibility\", \"hidden\").style(\"top\", \"10px\");\n\n"
+ << "var circle = svg.append(\"circle\").attr(\"cx\", 100).attr(\"cy\", 350).attr(\"r\", 3).attr(\"fill\", \"black\").style(\"opacity\", \"0\")\n\n"
+ << "d3.select(\"svg\").on(\"mousemove\", function () {\n"
+ << " mousex = d3.mouse(this);\n"
+ << " if (mousex[0] < margin.left + 3 || mousex[0] >= xw - margin.right) {\n"
+ << " vertical.style(\"opacity\", \"0\"); tooltip.style(\"opacity\", \"0\"); circle.style(\"opacity\", \"0\")\n"
+ << " } else {\n"
+ << " var xvalue = x.invert(mousex[0] - margin.left); var pos = findPosition(xvalue)\n"
+ << " vertical.style(\"opacity\", \"0.4\"); tooltip.style(\"opacity\", \"1\"); circle.style(\"opacity\", \"1\")\n"
+ << " circle.attr(\"cx\", pos.x).attr(\"cy\", pos.y); vertical.style(\"left\", mousex[0] + \"px\");tooltip.style(\"left\", mousex[0] + 15 + \"px\")\n"
+ << " tooltip.html(\"<p>\" + xvalue.toFixed(2) + \" Seconds <br>\" + Math.round(pos.mem) + \" MiB <br> \" + pos.name + "
+ << " \"<br> Phase Time: \" + pos.ptime + \" Seconds </p>\").style(\"visibility\", \"visible\");\n"
+ << " }\n})"
+ << ".on(\"mouseover\", function () {\n"
+ << " mousex = d3.mouse(this);\n if (mousex[0] < margin.left + 3 || mousex[0] > xw - margin.right) {\n"
+ << " vertical.style(\"opacity\", \"0\")\n } else {\n vertical.style(\"opacity\", \"0.4\");vertical.style(\"left\", mousex[0] + 7 + \"px\")\n}})\n"
+ << "d3.select(\"#download\").on(\"click\", function () {\n"
+ << "d3.select(this).attr(\"href\", 'data:application/octet-stream;base64,' + btoa(d3.select(\"#visualization\").html())).attr(\"download\", \"viz.svg\")})\n\n"
+ << "function findPosition(e){correctArea=d3.selectAll(\".area\").filter(function(t){if(t.usage[0][0]<=e*1e3&&t.usage[t.usage.length-1][0]>=e*1e3){return true}"
+ << "return false});if(correctArea.empty()){return 0}var t=new Array;correctArea[0].forEach(function(n){t.push(findYValueinArea(n,e))});"
+ << "max_elem=d3.max(t,function(e){return e.mem});var n=t.filter(function(e){return e.mem==max_elem});return n[0]}"
+ << "function findYValueinArea(e,t){len=e.getTotalLength();var n=0;var r=len;for(var i=0;i<=len;i+=50){var s=e.getPointAtLength(i);"
+ << "var o=x.invert(s.x);var u=y.invert(s.y);if(u>0&&o>t){n=Math.max(0,i-50);r=i;break}}var a=e.getPointAtLength(0);"
+ << "var f=1;while(n<r){var l=(r+n)/2;a=e.getPointAtLength(l);target_x=x.invert(a.x);if((l==n||l==r)&&Math.abs(target_x-t)>.01){break}if(target_x>t)r=l;"
+ << "else if(target_x<t)n=l;else{break}if(f>50){break}f++}var c=new function(){this.mem=y.invert(a.y);this.name=e.__data__.name;"
+ << "this.min=d3.min(e.__data__.usage,function(e){return e[0]/1e3});this.max=d3.max(e.__data__.usage,function(e){return e[0]/1e3});"
+ << "this.ptime=Math.round(this.max-this.min);this.x=a.x;this.y=a.y};return c}\n</script></body></html>";
+ return jsonbody.str();
+}
+
+
+template<>
+void write_mem_log<HTML_FORMAT>(std::ostream& out,const memory_monitor& m)
+{
+ std::stringstream json_data;
+ write_mem_log<JSON_FORMAT>(json_data,m);
+
+ out << create_mem_html_header();
+ out << create_mem_js_body(json_data.str());
+}
+
+#define ALIGNMENT sizeof(uint64_t)
+#define ALIGNSPLIT(size) (((size)) & ~0x7)
+#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
+#define MM_BLOCK_OVERHEAD (sizeof(size_t)+sizeof(size_t))
+#define MIN_BLOCKSIZE (ALIGN(sizeof(mm_block_t)+sizeof(mm_block_foot_t)))
+#define UNMASK_SIZE(size) ((size)&~1)
+#define ISFREE(size) ((size)&1)
+#define SETFREE(size) ((size)|1)
+#define SPLIT_THRESHOLD (MIN_BLOCKSIZE)
+
+
+/* from a memory location get the corresponding block header */
+using namespace sdsl;
+
+mm_block_t*
+block_cur(void* ptr)
+{
+ mm_block_t* bptr = (mm_block_t*)((uint8_t*)ptr - sizeof(size_t));
+ return bptr;
+}
+
+/* given a block retrieve the previous block if any. nullptr otherwise */
+mm_block_t*
+block_prev(mm_block_t* cur_bptr,mm_block_t* first)
+{
+ /* start of the heap? */
+ if (cur_bptr == first) return nullptr;
+ mm_block_foot_t* prev_foot = (mm_block_foot_t*)((uint8_t*)cur_bptr - sizeof(mm_block_foot_t));
+ mm_block_t* prev_bptr = (mm_block_t*)((uint8_t*)cur_bptr - UNMASK_SIZE(prev_foot->size));
+ return prev_bptr;
+}
+
+/* given a block retrieve the next block if any. nullptr otherwise */
+mm_block_t*
+block_next(mm_block_t* cur_bptr,uint8_t* top)
+{
+ /* end of the heap? */
+ if ((uint8_t*)((uint8_t*)cur_bptr+UNMASK_SIZE(cur_bptr->size)) >= top) return nullptr;
+
+ mm_block_t* next_bptr = (mm_block_t*)((uint8_t*)cur_bptr + UNMASK_SIZE(cur_bptr->size));
+ return next_bptr;
+}
+
+/* calculate the size of a memory block */
+size_t
+block_size(void* ptr)
+{
+ mm_block_t* bptr = block_cur(ptr);
+ return UNMASK_SIZE(bptr->size);
+}
+
+bool
+block_isfree(mm_block_t* ptr)
+{
+ ;
+ return ((ptr->size)&1ULL);
+}
+
+/* is the next block free */
+bool
+block_nextfree(mm_block_t* ptr,uint8_t* top)
+{
+ mm_block_t* next = block_next(ptr,top);
+ if (next && block_isfree(next)) return true;
+ return false;
+}
+
+/* is the prev block free */
+bool
+block_prevfree(mm_block_t* ptr,mm_block_t* begin)
+{
+ mm_block_t* prev = block_prev(ptr,begin);
+ if (prev && block_isfree(prev)) return 1;
+ return 0;
+}
+
+/* update the footer with a new size */
+void
+foot_update(mm_block_t* ptr,size_t size)
+{
+ mm_block_foot_t* fptr = (mm_block_foot_t*)((uint8_t*)ptr+
+ UNMASK_SIZE(size)-sizeof(mm_block_foot_t));
+ fptr->size = size;
+}
+
+/* update the block with a new size */
+void
+block_update(mm_block_t* ptr,size_t size)
+{
+ ptr->size = size;
+ foot_update(ptr,size);
+}
+
+/* return the pointer to the "data" */
+void*
+block_data(mm_block_t* ptr)
+{
+ return (void*)((uint8_t*)ptr+sizeof(size_t));
+}
+
+/* return size of the data that can be stored in the block */
+size_t
+block_getdatasize(mm_block_t* ptr)
+{
+ size_t blocksize = UNMASK_SIZE(ptr->size);
+ return blocksize - sizeof(size_t) - sizeof(mm_block_foot_t);
+}
+
+/* mark the block as free */
+void
+block_markfree(mm_block_t* ptr)
+{
+ block_update(ptr,SETFREE(ptr->size));
+}
+
+/* mark the block as used */
+void
+block_markused(mm_block_t* ptr)
+{
+ block_update(ptr,UNMASK_SIZE(ptr->size));
+}
+
+
+void
+hugepage_allocator::coalesce_block(mm_block_t* block)
+{
+ //std::cout << "coalesce_block()" << std::endl;
+ mm_block_t* newblock = block;
+ if (block_nextfree(block,m_top)) {
+ mm_block_t* next = block_next(block,m_top);
+ /* remove the "next" block from the free list */
+ remove_from_free_set(next);
+ /* add the size of our block */
+ block_update(block,UNMASK_SIZE(block->size)+UNMASK_SIZE(next->size));
+ }
+ if (block_prevfree(block,m_first_block)) {
+ mm_block_t* prev = block_prev(block,m_first_block);
+ /* we remove the old prev block and readd it to the correct
+ size list if necessary */
+ remove_from_free_set(prev);
+ newblock = prev;
+ block_update(prev,UNMASK_SIZE(prev->size)+UNMASK_SIZE(block->size));
+ }
+ if (newblock) {
+ block_markfree(newblock);
+ insert_into_free_set(newblock);
+ }
+}
+
+
+void
+hugepage_allocator::split_block(mm_block_t* bptr,size_t size)
+{
+ //std::cout << "split_block("<< (void*)bptr << ")" << std::endl;
+ size_t blocksize = UNMASK_SIZE(bptr->size);
+ //std::cout << "cur_block_size = " << blocksize << std::endl;
+ /* only split if we get at least a small block
+ out of it */
+ int64_t newblocksize = ALIGNSPLIT(blocksize - ALIGN(size+MM_BLOCK_OVERHEAD));
+ //std::cout << "new_block_size = " << newblocksize << std::endl;
+ if (newblocksize >= (int64_t)SPLIT_THRESHOLD) {
+ /* update blocksize of old block */
+ //std::cout << "block_update = " << blocksize-newblocksize << std::endl;
+ block_update(bptr,blocksize-newblocksize);
+ mm_block_t* newblock = (mm_block_t*)((char*)bptr+(blocksize-newblocksize));
+ //std::cout << "new block ptr = " << (void*)newblock << std::endl;
+ block_update(newblock,newblocksize);
+ coalesce_block(newblock);
+ }
+}
+
+
+uint8_t*
+hugepage_allocator::hsbrk(size_t size)
+{
+ ptrdiff_t left = (ptrdiff_t) m_total_size - (m_top - m_base);
+ if (left < (ptrdiff_t) size) { // enough space left?
+ throw std::system_error(ENOMEM,std::system_category(),
+ "hugepage_allocator: not enough hugepage memory available");
+ }
+ uint8_t* new_mem = m_top;
+ m_top += size;
+ return new_mem;
+}
+
+mm_block_t*
+hugepage_allocator::new_block(size_t size)
+{
+ //std::cout << "new_block(" << size << ")" << std::endl;
+ size = ALIGN(size+MM_BLOCK_OVERHEAD);
+ if (size < MIN_BLOCKSIZE) size = MIN_BLOCKSIZE;
+ mm_block_t* ptr = (mm_block_t*) hsbrk(size);
+ block_update(ptr,size);
+ return ptr;
+}
+
+mm_block_t*
+hugepage_allocator::last_block()
+{
+ mm_block_t* last = nullptr;
+ //std::cout << "m_top = " << (void*)m_top << std::endl;
+ //std::cout << "m_base = " << (void*)m_base << std::endl;
+ if (m_top != m_base) {
+ mm_block_foot_t* fptr = (mm_block_foot_t*)(m_top - sizeof(size_t));
+ //std::cout << "foot of last = " << (void*)fptr << std::endl;
+ //std::cout << "size of last = " << UNMASK_SIZE(fptr->size) << std::endl;
+ last = (mm_block_t*)(((uint8_t*)fptr) - UNMASK_SIZE(fptr->size) + sizeof(size_t));
+ //std::cout << "last = " << (void*)last << std::endl;
+ }
+ return last;
+}
+
+void
+block_print(int id,mm_block_t* bptr)
+{
+ fprintf(stdout, "%d addr=%p size=%lu (%lu) free=%d\n",id,((void*)bptr),
+ UNMASK_SIZE(bptr->size),bptr->size,block_isfree(bptr));
+ fflush(stdout);
+}
+
+void
+hugepage_allocator::print_heap()
+{
+ mm_block_t* bptr = m_first_block;
+ size_t id = 0;
+ while (bptr) {
+ block_print(id,bptr);
+ id++;
+ bptr = block_next(bptr,m_top);
+ }
+}
+
+void
+hugepage_allocator::remove_from_free_set(mm_block_t* block)
+{
+ //std::cout << "remove_from_free_set()" << std::endl;
+ auto eq_range = m_free_large.equal_range(block->size);
+ // find the block amoung the blocks with equal size
+ auto itr = eq_range.first;
+ auto last = eq_range.second;
+ auto found = m_free_large.end();
+ while (itr != last) {
+ if (itr->second == block) {
+ found = itr;
+ }
+ ++itr;
+ }
+ if (found == m_free_large.end()) {
+ found = last;
+ }
+ m_free_large.erase(found);
+}
+
+void
+hugepage_allocator::insert_into_free_set(mm_block_t* block)
+{
+ //std::cout << "insert_into_free_set("<< (void*)block << "," << UNMASK_SIZE(block->size) << ")" << std::endl;
+ //std::cout << "insert_into_free_set("<< (void*)block << "," << block->size << ")" << std::endl;
+ m_free_large.insert({block->size,block});
+}
+
+mm_block_t*
+hugepage_allocator::find_free_block(size_t size_in_bytes)
+{
+ //std::cout << "find_free_block(" << size_in_bytes << ")" << std::endl;
+
+ mm_block_t* bptr = nullptr;
+ auto free_block = m_free_large.lower_bound(size_in_bytes);
+ if (free_block != m_free_large.end()) {
+ bptr = free_block->second;
+ m_free_large.erase(free_block);
+ }
+ return bptr;
+}
+
+void*
+hugepage_allocator::mm_alloc(size_t size_in_bytes)
+{
+ //std::cout << "ALLOC(" << size_in_bytes << ")" << std::endl;
+ mm_block_t* bptr = nullptr;
+ if ((bptr=find_free_block(size_in_bytes + MM_BLOCK_OVERHEAD)) != nullptr) {
+ //std::cout << "found free block = " << (void*)bptr << std::endl;
+ block_markused(bptr);
+ /* split if we have a block too large for us? */
+ split_block(bptr,size_in_bytes);
+ } else {
+ //std::cout << "no free block found that is big enough!" << std::endl;
+ // check if last block is free
+ //std::cout << "check last block" << std::endl;
+ bptr = last_block();
+ if (bptr && block_isfree(bptr)) {
+ //std::cout << "last block is free. -> extend!" << std::endl;
+ // extent last block as it is free
+ size_t blockdatasize = block_getdatasize(bptr);
+ size_t needed = ALIGN(size_in_bytes - blockdatasize);
+ hsbrk(needed);
+ remove_from_free_set(bptr);
+ block_update(bptr,blockdatasize+needed+sizeof(size_t)+sizeof(mm_block_foot_t));
+ //insert_into_free_set(bptr);
+ block_markused(bptr);
+ } else {
+ bptr = new_block(size_in_bytes);
+ }
+ }
+ //print_heap();
+ //void* ptr = block_data(bptr);
+ //std::cout << "return ptr = " << ptr << std::endl;
+ return block_data(bptr);
+}
+
+void
+hugepage_allocator::mm_free(void* ptr)
+{
+ //print_heap();
+ //std::cout << "FREE(" << ptr << ")" << std::endl;
+ if (ptr) {
+ mm_block_t* bptr = block_cur(ptr);
+ block_markfree(bptr);
+ /* coalesce if needed. otherwise just add */
+ coalesce_block(bptr);
+ }
+ //print_heap();
+}
+
+void*
+hugepage_allocator::mm_realloc(void* ptr, size_t size)
+{
+ //print_heap();
+ //std::cout << "REALLOC(" << ptr << "," << size << ")" << std::endl;
+ /* handle special cases first */
+ if (nullptr==ptr) return mm_alloc(size);
+ if (size==0) {
+ mm_free(ptr);
+ return nullptr;
+ }
+ mm_block_t* bptr = block_cur(ptr);
+
+ bool need_malloc = 0;
+ size_t blockdatasize = block_getdatasize(bptr);
+ /* we do nothing if the size is equal to the block */
+ if (size == blockdatasize) {
+ //std::cout << "return ptr = " << ptr << std::endl;
+ return ptr; /* do nothing if size fits already */
+ }
+ if (size < blockdatasize) {
+ /* we shrink */
+ /* do we shrink enough to perform a split? */
+ //std::cout << "shrink!" << std::endl;
+ split_block(bptr,size);
+ } else {
+ //std::cout << "expand!" << std::endl;
+ /* we expand */
+ /* if the next block is free we could use it! */
+ mm_block_t* next = block_next(bptr,m_top);
+ if (!next) {
+ //std::cout << "no next! -> expand!" << std::endl;
+ // we are the last block so we just expand
+ blockdatasize = block_getdatasize(bptr);
+ size_t needed = ALIGN(size - blockdatasize);
+ hsbrk(needed);
+ block_update(bptr,UNMASK_SIZE(bptr->size)+needed);
+ return block_data(bptr);
+ } else {
+ // we are not the last block
+ //std::cout << "try combine next" << std::endl;
+ if (next && block_isfree(next)) {
+ /* do we have enough space if we use the next block */
+ if (blockdatasize + UNMASK_SIZE(next->size) >= size) {
+ /* the next block is enough! */
+ /* remove the "next" block from the free list */
+ remove_from_free_set(next);
+ /* add the size of our block */
+ block_update(bptr,UNMASK_SIZE(bptr->size)+UNMASK_SIZE(next->size));
+ } else {
+ /* the next block is not enough. we allocate a new one instead */
+ need_malloc = true;
+ }
+ } else {
+ /* try combing the previous block if free */
+ //std::cout << "try combine prev" << std::endl;
+ mm_block_t* prev = block_prev(bptr,m_first_block);
+ if (prev && block_isfree(prev)) {
+ if (blockdatasize + UNMASK_SIZE(prev->size) >= size) {
+ remove_from_free_set(prev);
+ size_t newsize = UNMASK_SIZE(prev->size)+UNMASK_SIZE(bptr->size);
+ block_update(prev,newsize);
+ block_markused(prev);
+ /* move the data into the previous block */
+ ptr = memmove(block_data(prev),ptr,blockdatasize);
+ } else {
+ /* not enough in the prev block */
+ need_malloc = true;
+ }
+ } else {
+ /* prev block not free. get more memory */
+ need_malloc = true;
+ }
+ }
+ }
+ }
+ if (need_malloc) {
+ //std::cout << "need_alloc in REALLOC!" << std::endl;
+ void* newptr = mm_alloc(size);
+ memcpy(newptr,ptr,size);
+ mm_free(ptr);
+ ptr = newptr;
+ }
+ //print_heap();
+ //std::cout << "return ptr = " << ptr << std::endl;
+ return ptr;
+}
+
+uint64_t extract_number(std::string& line)
+{
+ std::string num_str;
+ for (size_t i=line.size()-1; i+1>=1; i--) {
+ if (isdigit(line[i])) {
+ num_str.insert(num_str.begin(),line[i]);
+ } else {
+ if (num_str.size() > 0) {
+ break;
+ }
+ }
+ }
+ return std::strtoull(num_str.c_str(),nullptr,10);
+}
+
+uint64_t extract_multiplier(std::string& line)
+{
+ uint64_t num = 1;
+ if (line[line.size()-2] == 'k' || line[line.size()-2] == 'K') {
+ num = 1024;
+ }
+ if (line[line.size()-2] == 'm' || line[line.size()-2] == 'M') {
+ num = 1024*1024;
+ }
+ if (line[line.size()-2] == 'g' || line[line.size()-2] == 'G') {
+ num = 1024*1024*1024;
+ }
+ return num;
+}
+
+size_t
+hugepage_allocator::determine_available_hugepage_memory()
+{
+ size_t size_in_bytes = 0;
+ size_t page_size_in_bytes = 0;
+ size_t num_free_pages = 0;
+ const std::string meminfo_file = "/proc/meminfo";
+ const std::string ps_str = "Hugepagesize:";
+ const std::string pf_str = "HugePages_Free:";
+ std::ifstream mifs(meminfo_file);
+ if (mifs.is_open()) {
+ // find size of one page
+ std::string line;
+ while (std::getline(mifs, line)) {
+ auto ps = std::mismatch(ps_str.begin(),ps_str.end(), line.begin());
+ if (ps.first == ps_str.end()) {
+ page_size_in_bytes = extract_number(line) * extract_multiplier(line);
+ }
+ auto pf = std::mismatch(pf_str.begin(),pf_str.end(), line.begin());
+ if (pf.first == pf_str.end()) {
+ num_free_pages = extract_number(line);
+ }
+ }
+ size_in_bytes = page_size_in_bytes*num_free_pages;
+ } else {
+ throw std::system_error(ENOMEM,std::system_category(),
+ "hugepage_allocator could not automatically determine available hugepages");
+ }
+ return size_in_bytes;
+}
+
+
+}
diff --git a/lib/nn_dict_dynamic.cpp b/lib/nn_dict_dynamic.cpp
new file mode 100644
index 0000000..90087f1
--- /dev/null
+++ b/lib/nn_dict_dynamic.cpp
@@ -0,0 +1,13 @@
+#include "sdsl/nn_dict_dynamic.hpp"
+#include "sdsl/util.hpp"
+
+namespace sdsl
+{
+namespace util
+{
+void set_zero_bits(nn_dict_dynamic& nn)
+{
+ util::set_to_value(nn.m_tree, 0);
+}
+} // end util
+} // end sdsl
diff --git a/lib/ram_filebuf.cpp b/lib/ram_filebuf.cpp
new file mode 100644
index 0000000..b32a49e
--- /dev/null
+++ b/lib/ram_filebuf.cpp
@@ -0,0 +1,155 @@
+#include "sdsl/ram_filebuf.hpp"
+#include <iostream>
+#include <limits>
+
+namespace sdsl
+{
+
+
+ram_filebuf::~ram_filebuf() {}
+
+ram_filebuf::ram_filebuf() {}
+
+ram_filebuf::ram_filebuf(std::vector<char>& ram_file) : m_ram_file(&ram_file)
+{
+ char* begin = m_ram_file->data();
+ char* end = begin + m_ram_file->size();
+ setg(begin, begin, end); // set get pointers eback(), eptr(), egptr()
+}
+
+std::streambuf*
+ram_filebuf::open(const std::string name, std::ios_base::openmode mode)
+{
+ // open ram_file
+ if ((mode & std::ios_base::in) and !(mode & std::ios_base::trunc)) {
+ // file must exist, initial position at the start
+ if (!ram_fs::exists(name)) {
+ m_ram_file = nullptr;
+ } else {
+ m_ram_file = &ram_fs::content(name);
+ }
+ } else { // existence of file not required
+ if (!ram_fs::exists(name)) {
+ // create empty file, if it does not yet exist
+ ram_fs::store(name, ram_fs::content_type());// TODO: create method in ram_fs?? or store w 1 arg?
+ }
+ m_ram_file = &ram_fs::content(name);
+ if ((mode & std::ios_base::out) and !(mode & std::ios_base::app)) {
+ m_ram_file->clear();
+ }
+ }
+
+ if (m_ram_file and(mode & std::ios_base::trunc)) {
+ m_ram_file->clear();
+ }
+ if (m_ram_file) {
+ if (mode & std::ios_base::ate) {
+ // TODO: move put pointer to the end of the file
+ } else {
+
+ }
+ setg(m_ram_file->data(), m_ram_file->data(), m_ram_file->data()+m_ram_file->size());
+ setp(m_ram_file->data(), m_ram_file->data()+m_ram_file->size());
+ }
+// ATTENTION: if m_ram_file->size() == 0, then data might be nullptr !!!
+ return m_ram_file ? this : nullptr;
+}
+
+bool
+ram_filebuf::is_open()
+{
+ return m_ram_file!=nullptr;
+}
+
+ram_filebuf*
+ram_filebuf::close()
+{
+ if (!this->is_open())
+ return nullptr;
+ m_ram_file = nullptr;
+ setg(nullptr, nullptr, nullptr);
+ setp(nullptr, nullptr);
+ return this;
+}
+
+ram_filebuf::pos_type
+ram_filebuf::seekpos(pos_type sp, std::ios_base::openmode mode)
+{
+ if (sp >= (pos_type)0 and sp <= (pos_type)m_ram_file->size()) {
+ setg(m_ram_file->data(), m_ram_file->data()+sp, m_ram_file->data()+m_ram_file->size());
+ setp(m_ram_file->data(), m_ram_file->data()+m_ram_file->size());
+ pbump64(sp);
+ } else {
+ if (mode & std::ios_base::out) {
+ // extend buffer
+ m_ram_file->resize(sp, 0);
+ setg(m_ram_file->data(), m_ram_file->data()+sp, m_ram_file->data()+m_ram_file->size());
+ setp(m_ram_file->data(), m_ram_file->data()+m_ram_file->size());
+ pbump64(sp);
+ } else {
+ return pos_type(off_type(-1));
+ }
+ }
+ return sp;
+}
+
+ram_filebuf::pos_type
+ram_filebuf::pubseekoff(off_type off, std::ios_base::seekdir way,
+ std::ios_base::openmode which)
+{
+ if (std::ios_base::beg == way) {
+ if (seekpos(off, which) == pos_type(-1)) {
+ return pos_type(-1);
+ }
+ } else if (std::ios_base::cur == way) {
+ if (seekpos(gptr()-eback()+off, which) == pos_type(-1)) {
+ return pos_type(-1);
+ }
+ } else if (std::ios_base::end == way) {
+ if (seekpos(egptr()-eback()+off, which) == pos_type(-1)) {
+ return pos_type(-1);
+ }
+ }
+ return gptr()-eback();
+}
+
+
+ram_filebuf::pos_type
+ram_filebuf::pubseekpos(pos_type sp, std::ios_base::openmode which)
+{
+ if (seekpos(sp, which) == pos_type(-1)) {
+ return pos_type(-1);
+ } else {
+ return gptr()-eback();
+ }
+}
+
+int
+ram_filebuf::sync()
+{
+ return 0; // we are always in sync, since buffer is sink
+}
+
+ram_filebuf::int_type
+ram_filebuf::overflow(int_type c)
+{
+ if (m_ram_file) {
+ m_ram_file->push_back(c);
+ setp(m_ram_file->data(), m_ram_file->data()+m_ram_file->size());
+ std::ptrdiff_t add = epptr()-pbase();
+ pbump64(add);
+ setg(m_ram_file->data(), gptr(), m_ram_file->data()+m_ram_file->size());
+ }
+ return traits_type::to_int_type(c);
+}
+
+void ram_filebuf::pbump64(std::ptrdiff_t x)
+{
+ while (x > std::numeric_limits<int>::max()) {
+ pbump(std::numeric_limits<int>::max());
+ x -= std::numeric_limits<int>::max();
+ }
+ pbump(x);
+}
+
+}
diff --git a/lib/ram_fs.cpp b/lib/ram_fs.cpp
new file mode 100644
index 0000000..b9327ff
--- /dev/null
+++ b/lib/ram_fs.cpp
@@ -0,0 +1,135 @@
+#include "sdsl/ram_fs.hpp"
+#include "sdsl/util.hpp"
+#include <cstdio>
+#include <iostream>
+#include <algorithm>
+
+static int nifty_counter = 0;
+
+sdsl::ram_fs::mss_type sdsl::ram_fs::m_map;
+std::recursive_mutex sdsl::ram_fs::m_rlock;
+
+
+sdsl::ram_fs_initializer::ram_fs_initializer()
+{
+ if (0 == nifty_counter++) {
+ ram_fs::m_map = ram_fs::mss_type();
+ }
+}
+
+sdsl::ram_fs_initializer::~ram_fs_initializer()
+{
+ if (0 == --nifty_counter) {
+ // clean up
+ }
+}
+
+namespace sdsl
+{
+
+ram_fs::ram_fs() {};
+
+void
+ram_fs::store(const std::string& name, content_type data)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_rlock);
+ if (!exists(name)) {
+ std::string cname = name;
+ m_map.insert(std::make_pair(std::move(cname), std::move(data)));
+ } else {
+ m_map[name] = std::move(data);
+ }
+}
+
+bool
+ram_fs::exists(const std::string& name)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_rlock);
+ return m_map.find(name) != m_map.end();
+}
+
+ram_fs::content_type&
+ram_fs::content(const std::string& name)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_rlock);
+ return m_map[name];
+}
+
+size_t
+ram_fs::file_size(const std::string& name)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_rlock);
+ if (exists(name)) {
+ return m_map[name].size();
+ } else {
+ return 0;
+ }
+}
+
+int
+ram_fs::remove(const std::string& name)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_rlock);
+ m_map.erase(name);
+ return 0;
+}
+
+int
+ram_fs::rename(const std::string old_filename, const std::string new_filename)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_rlock);
+ m_map[new_filename] = std::move(m_map[old_filename]);
+ remove(old_filename);
+ return 0;
+}
+
+bool is_ram_file(const std::string& file)
+{
+ if (file.size() > 0) {
+ if (file[0]=='@') {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::string ram_file_name(const std::string& file)
+{
+ if (is_ram_file(file)) {
+ return file;
+ } else {
+ return "@" + file;
+ }
+}
+
+std::string disk_file_name(const std::string& file)
+{
+ if (!is_ram_file(file)) {
+ return file;
+ } else {
+ return file.substr(1);
+ }
+}
+
+int remove(const std::string& file)
+{
+ if (is_ram_file(file)) {
+ return ram_fs::remove(file);
+ } else {
+ return std::remove(file.c_str());
+ }
+}
+
+int rename(const std::string& old_filename, const std::string& new_filename)
+{
+ if (is_ram_file(old_filename)) {
+ if (!is_ram_file(new_filename)) { // error, if new file is not also RAM-file
+ return -1;
+ }
+ return ram_fs::rename(old_filename, new_filename);
+ } else {
+ return std::rename(old_filename.c_str(), new_filename.c_str());
+ }
+}
+
+} // end namespace sdsl
diff --git a/lib/rrr_vector_15.cpp b/lib/rrr_vector_15.cpp
new file mode 100644
index 0000000..8d0cd4c
--- /dev/null
+++ b/lib/rrr_vector_15.cpp
@@ -0,0 +1,9 @@
+#include "sdsl/rrr_vector_15.hpp"
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+// initialize the inner class
+binomial15::impl binomial15::iii;
+
+} // end namespace
diff --git a/lib/sfstream.cpp b/lib/sfstream.cpp
new file mode 100644
index 0000000..848e5d8
--- /dev/null
+++ b/lib/sfstream.cpp
@@ -0,0 +1,290 @@
+#include "sdsl/sfstream.hpp"
+#include "sdsl/util.hpp"
+#include <iostream>
+
+namespace sdsl
+{
+
+// IMPLEMENTATION OF OSFSTREAM
+
+osfstream::osfstream() : std::ostream(nullptr)
+{
+ this->init(m_streambuf);
+}
+
+osfstream::osfstream(const std::string& file, std::ios_base::openmode mode) : std::ostream(nullptr)
+{
+ this->init(m_streambuf);
+ open(file, mode);
+}
+
+osfstream::buf_ptr_type
+osfstream::open(const std::string& file, std::ios_base::openmode mode)
+{
+ delete m_streambuf;
+ m_streambuf = nullptr;
+ m_file = file;
+ std::streambuf* success = nullptr;
+ if (is_ram_file(file)) {
+ m_streambuf = new ram_filebuf();
+ success = ((ram_filebuf*)m_streambuf)->open(m_file, mode);
+ } else {
+ m_streambuf = new std::filebuf();
+ success = ((std::filebuf*)m_streambuf)->open(m_file, mode);
+ }
+ if (success) {
+ this->clear();
+ } else {
+ this->setstate(std::ios_base::failbit);
+ delete m_streambuf;
+ m_streambuf = nullptr;
+ }
+ this->rdbuf(m_streambuf);
+ return m_streambuf;
+}
+
+bool
+osfstream::is_open()
+{
+ if (nullptr == m_streambuf)
+ return false;
+ if (is_ram_file(m_file)) {
+ return ((ram_filebuf*)m_streambuf)->is_open();
+ } else {
+ return ((std::filebuf*)m_streambuf)->is_open();
+ }
+}
+
+void
+osfstream::close()
+{
+ bool fail = false;
+ if (nullptr == m_streambuf) {
+ fail = true;
+ } else {
+ if (is_ram_file(m_file)) {
+ fail = !((ram_filebuf*)m_streambuf)->close();
+ } else {
+ fail = !((std::filebuf*)m_streambuf)->close();
+ }
+ }
+ if (fail) this->setstate(std::ios::failbit);
+}
+
+osfstream::~osfstream()
+{
+ delete m_streambuf; // streambuf closes the file on destruction
+}
+
+osfstream::operator voidptr()const
+{
+ return m_streambuf;
+}
+
+osfstream&
+osfstream::seekp(pos_type pos)
+{
+ ios_base::iostate err = std::ios_base::iostate(std::ios_base::goodbit);
+ try {
+ if (!this->fail()) {
+ pos_type p = 0;
+ if (is_ram_file(m_file)) {
+ p = ((ram_filebuf*)m_streambuf)->pubseekpos(pos, std::ios_base::out);
+ } else {
+ p = ((std::filebuf*)m_streambuf)->pubseekpos(pos, std::ios_base::out);
+ }
+ if (p == pos_type(off_type(-1))) {
+ err |= ios_base::failbit;
+ this->setstate(err);
+ }
+ }
+ } catch (...) {
+ if (err) {
+ this->setstate(err);
+ }
+ }
+ return *this;
+}
+
+
+osfstream&
+osfstream::seekp(off_type off, std::ios_base::seekdir way)
+{
+ ios_base::iostate err = std::ios_base::iostate(ios_base::goodbit);
+ try {
+ if (!this->fail()) {
+ pos_type p = 0;
+ if (is_ram_file(m_file)) {
+ p = ((ram_filebuf*)m_streambuf)->pubseekoff(off, way, std::ios_base::out);
+
+ } else {
+ p = ((std::filebuf*)m_streambuf)->pubseekoff(off, way, std::ios_base::out);
+ }
+ if (p == pos_type(off_type(-1))) {
+ err |= ios_base::failbit;
+ this->setstate(err);
+ }
+ }
+ } catch (...) {
+ if (err) {
+ this->setstate(err);
+ }
+ }
+ return *this;
+}
+
+
+
+// IMPLEMENTATION OF ISFSTREAM
+
+isfstream::isfstream() : std::istream(nullptr)
+{
+ this->init(m_streambuf);
+}
+
+isfstream::isfstream(const std::string& file, std::ios_base::openmode mode) : std::istream(nullptr)
+{
+ this->init(m_streambuf);
+ open(file, mode);
+}
+
+isfstream::buf_ptr_type
+isfstream::open(const std::string& file, std::ios_base::openmode mode)
+{
+ delete m_streambuf;
+ m_streambuf = nullptr;
+ m_file = file;
+ std::streambuf* success = nullptr;
+ if (is_ram_file(file)) {
+ m_streambuf = new ram_filebuf();
+ success = ((ram_filebuf*)m_streambuf)->open(m_file, mode);
+ } else {
+ m_streambuf = new std::filebuf();
+ success = ((std::filebuf*)m_streambuf)->open(m_file, mode);
+ }
+ if (success) {
+ this->clear();
+ } else {
+ this->setstate(std::ios_base::failbit);
+ delete m_streambuf;
+ m_streambuf = nullptr;
+ }
+ this->rdbuf(m_streambuf);
+ return m_streambuf;
+}
+
+bool
+isfstream::is_open()
+{
+ if (nullptr == m_streambuf)
+ return false;
+ if (is_ram_file(m_file)) {
+ return ((ram_filebuf*)m_streambuf)->is_open();
+ } else {
+ return ((std::filebuf*)m_streambuf)->is_open();
+ }
+}
+
+void
+isfstream::close()
+{
+ bool fail = false;
+ if (nullptr == m_streambuf) {
+ fail = true;
+ } else {
+ if (is_ram_file(m_file)) {
+ fail = !((ram_filebuf*)m_streambuf)->close();
+ } else {
+ fail = !((std::filebuf*)m_streambuf)->close();
+ }
+ }
+ if (fail) this->setstate(std::ios::failbit);
+}
+
+isfstream&
+isfstream::seekg(pos_type pos)
+{
+ ios_base::iostate err = std::ios_base::iostate(std::ios_base::goodbit);
+ try {
+ if (!this->fail()) {
+ pos_type p = 0;
+ if (is_ram_file(m_file)) {
+ p = ((ram_filebuf*)m_streambuf)->pubseekpos(pos, std::ios_base::in);
+
+ } else {
+ p = ((std::filebuf*)m_streambuf)->pubseekpos(pos, std::ios_base::in);
+ }
+ if (p == pos_type(off_type(-1))) {
+ err |= ios_base::failbit;
+ }
+ }
+ } catch (...) {
+ if (err) {
+ this->setstate(err);
+ }
+ }
+ return *this;
+}
+
+
+isfstream&
+isfstream::seekg(off_type off, std::ios_base::seekdir way)
+{
+ ios_base::iostate err = std::ios_base::iostate(ios_base::goodbit);
+ try {
+ if (!this->fail()) {
+ pos_type p = 0;
+ if (is_ram_file(m_file)) {
+ p = ((ram_filebuf*)m_streambuf)->pubseekoff(off, way, std::ios_base::in);
+
+ } else {
+ p = ((std::filebuf*)m_streambuf)->pubseekoff(off, way, std::ios_base::in);
+ }
+ if (p == pos_type(off_type(-1))) {
+ err |= ios_base::failbit;
+ }
+ }
+ } catch (...) {
+ if (err) {
+ this->setstate(err);
+ }
+ }
+ return *this;
+}
+
+std::streampos
+isfstream::tellg()
+{
+ ios_base::iostate err = std::ios_base::iostate(ios_base::goodbit);
+ pos_type p = pos_type(off_type(-1));
+ try {
+ if (!this->fail()) {
+ if (is_ram_file(m_file)) {
+ p = ((ram_filebuf*)m_streambuf)->pubseekoff(0, std::ios_base::cur);
+
+ } else {
+ p = ((std::filebuf*)m_streambuf)->pubseekoff(0, std::ios_base::cur);
+ }
+ if (p == pos_type(off_type(-1))) {
+ err |= ios_base::failbit;
+ }
+ }
+ } catch (...) {
+ if (err) {
+ this->setstate(err);
+ }
+ }
+ return p;
+}
+
+isfstream::~isfstream()
+{
+ delete m_streambuf;
+}
+
+isfstream::operator voidptr()const
+{
+ return m_streambuf; // streambuf closes the file on destruction
+}
+
+}// end namespace sdsl
diff --git a/lib/structure_tree.cpp b/lib/structure_tree.cpp
new file mode 100644
index 0000000..7774525
--- /dev/null
+++ b/lib/structure_tree.cpp
@@ -0,0 +1,266 @@
+#include "sdsl/structure_tree.hpp"
+#include "sdsl/util.hpp"
+
+namespace sdsl
+{
+
+void output_tab(std::ostream& out,size_t level)
+{
+ for (size_t i=0; i<level; i++) out << "\t";
+}
+
+template<>
+void write_structure_tree<JSON_FORMAT>(const structure_tree_node* v, std::ostream& out, size_t level)
+{
+ if (v) {
+ output_tab(out,level); out << "{" << std::endl;
+ output_tab(out,level+1); out << "\"class_name\":" << "\"" << v->type << "\"," << std::endl;
+ output_tab(out,level+1); out << "\"name\":" << "\"" << v->name << "\"," << std::endl;
+ output_tab(out,level+1); out << "\"size\":" << "\"" << v->size << "\"";
+
+ if (v->children.size()) {
+ out << "," << std::endl; // terminate the size tag from before if there are children
+ output_tab(out,level+1); out << "\"children\":[" << std::endl;
+ size_t written_child_elements = 0;
+ for (const auto& child : v->children) {
+ if (written_child_elements++ > 0) {
+ out << "," << std::endl;
+ }
+ write_structure_tree<JSON_FORMAT>(child.second.get(), out,level+2);
+ }
+ out << std::endl;
+ output_tab(out,level+1); out << "]" << std::endl;
+ } else {
+ out << std::endl;
+ }
+ output_tab(out,level); out << "}";
+ }
+}
+
+std::string create_html_header(const char* file_name)
+{
+ std::stringstream jsonheader;
+ jsonheader
+ << "<html>\n"
+ << " <head>\n"
+ << " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n"
+ << " <title>" << file_name << "</title>\n"
+ << " <script src=\"http://d3js.org/d3.v2.js\"></script>\n"
+ << " <style type=\"text/css\">\n"
+ << " path { stroke: #000; stroke-width: 0.8; cursor: pointer; }\n"
+ << " text { font: 11px sans-serif; cursor: pointer; }\n"
+ << " body { width: 900; margin: 0 auto; }\n"
+ << " h1 { text-align: center; margin: .5em 0; }\n"
+ << " #breadcrumbs { display: none; }\n"
+ << " svg { font: 10px sans-serif; }\n"
+ << " </style>\n"
+ << " </head>\n"
+ << "<body marginwidth=\"0\" marginheight=\"0\">\n"
+ << "<button><a id=\"download\">Save as SVG</a></button>\n"
+ << " <div id=\"chart\"></div>" << std::endl;
+ return jsonheader.str();
+}
+
+std::string create_js_body(const std::string& jsonsize)
+{
+ std::stringstream jsonbody;
+ jsonbody
+ << "<script type=\"text/javascript\">" << std::endl
+ << ""
+ "var w = 800,\n"
+ " h = w,\n"
+ " r = w / 2,\n"
+ " x = d3.scale.linear().range([0, 2 * Math.PI]),\n"
+ " y = d3.scale.pow().exponent(1.3).domain([0, 1]).range([0, r]),\n"
+ " p = 5,\n"
+ " color = d3.scale.category20c(),\n"
+ " duration = 1000;\n"
+ "\n"
+ "var vis = d3.select(\"#chart\").append(\"svg:svg\")\n"
+ " .attr(\"width\", w + p * 2)\n"
+ " .attr(\"height\", h + p * 2)\n"
+ " .append(\"g\")\n"
+ " .attr(\"transform\", \"translate(\" + (r + p) + \",\" + (r + p) + \")\");\n"
+ "\n"
+ "vis.append(\"p\")\n"
+ " .attr(\"id\", \"intro\")\n"
+ " .text(\"Click to zoom!\");\n"
+ "\n"
+ "var partition = d3.layout.partition()\n"
+ " .sort(null)\n"
+ " .size([2 * Math.PI, r * r])\n"
+ " .value(function(d) { return d.size; });\n"
+ "\n"
+ "var arc = d3.svg.arc()\n"
+ " .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })\n"
+ " .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })\n"
+ " .innerRadius(function(d) { return Math.max(0, d.y ? y(d.y) : d.y); })\n"
+ " .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });\n"
+ "\n"
+ " " << std::endl
+ << "var spaceJSON = " << jsonsize << ";" << std::endl << std::endl
+ << "\n"
+ "\n"
+ " var nodes = partition.nodes(spaceJSON);\n"
+ "\n"
+ " var path = vis.selectAll(\"path\").data(nodes);\n"
+ " path.enter().append(\"path\")\n"
+ " .attr(\"id\", function(d, i) { return \"path-\" + i; })\n"
+ " .attr(\"d\", arc)\n"
+ " .attr(\"fill-rule\", \"evenodd\")\n"
+ " .style(\"fill\", colour)\n"
+ " .on(\"click\", click);\n"
+ "\n"
+ " path.append(\"title\").text(function(d) { return 'class name: ' + d.class_name + '\\nmember_name: ' + d.name + '\\n size: ' + sizeMB(d) });\n"
+ "\n"
+ " var text = vis.selectAll(\"text\").data(nodes);\n"
+ " var textEnter = text.enter().append(\"text\")\n"
+ " .style(\"opacity\", 1)\n"
+ " .style(\"fill\", function(d) {\n"
+ " return brightness(d3.rgb(colour(d))) < 125 ? \"#eee\" : \"#000\";\n"
+ " })\n"
+ " .attr(\"text-anchor\", function(d) {\n"
+ " return x(d.x + d.dx / 2) > Math.PI ? \"end\" : \"start\";\n"
+ " })\n"
+ " .attr(\"dy\", \".2em\")\n"
+ " .attr(\"transform\", function(d) {\n"
+ " var multiline = (d.name || \"\").split(\" \").length > 1,\n"
+ " angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,\n"
+ " rotate = angle + (multiline ? -.5 : 0);\n"
+ " return \"rotate(\" + rotate + \")translate(\" + (y(d.y) + p) + \")rotate(\" + (angle > 90 ? -180 : 0) + \")\";\n"
+ " })\n"
+ " .on(\"click\", click);\n"
+ "\n"
+ " textEnter.append(\"title\").text(function(d) { return 'class name: ' + d.class_name + '\\nmember_name: ' + d.name + '\\n size: ' + sizeMB(d) });\n"
+ "\n"
+ " textEnter.append(\"tspan\")\n"
+ " .attr(\"x\", 0)\n"
+ " .text(function(d) { return d.dx < 0.05 ? \"\" : d.depth ? d.name.split(\" \")[0] : \"\"; });\n"
+ " textEnter.append(\"tspan\")\n"
+ " .attr(\"x\", 0)\n"
+ " .attr(\"dy\", \"1em\")\n"
+ " .text(function(d) { return d.dx < 0.05 ? \"\" : d.depth ? d.name.split(\" \")[1] || \"\" : \"\"; });\n"
+ "\n"
+ " function click(d) {\n"
+ " path.transition()\n"
+ " .duration(duration)\n"
+ " .attrTween(\"d\", arcTween(d));\n"
+ "\n"
+ " // Somewhat of a hack as we rely on arcTween updating the scales.\n"
+ " text\n"
+ " .style(\"visibility\", function(e) {\n"
+ " return isParentOf(d, e) ? null : d3.select(this).style(\"visibility\");\n"
+ " })\n"
+ " .transition().duration(duration)\n"
+ " .attrTween(\"text-anchor\", function(d) {\n"
+ " return function() {\n"
+ " return x(d.x + d.dx / 2) > Math.PI ? \"end\" : \"start\";\n"
+ " };\n"
+ " })\n"
+ " .attrTween(\"transform\", function(d) {\n"
+ " var multiline = (d.name || \"\").split(\" \").length > 1;\n"
+ " return function() {\n"
+ " var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,\n"
+ " rotate = angle + (multiline ? -.5 : 0);\n"
+ " return \"rotate(\" + rotate + \")translate(\" + (y(d.y) + p) + \")rotate(\" + (angle > 90 ? -180 : 0) + \")\";\n"
+ " };\n"
+ " })\n"
+ " .style(\"opacity\", function(e) { return isParentOf(d, e) ? 1 : 1e-6; })\n"
+ " .each(\"end\", function(e) {\n"
+ " d3.select(this).style(\"visibility\", isParentOf(d, e) ? null : \"hidden\");\n"
+ " });\n"
+ " }\n"
+ "\n"
+ "\n"
+ "function sizeMB(d) {\n"
+ "// if (d.children) {\n"
+ "// var sum = calcSum(d);\n"
+ "// return (sum / (1024*1024)).toFixed(2) + 'MB';\n"
+ "// } else {\n"
+ " return (d.size / (1024*1024)).toFixed(2) + 'MB';\n"
+ "// }\n"
+ "}\n"
+ "\n"
+ "function calcSum(d) {\n"
+ " if(d.children) {\n"
+ " var sum = 0;\n"
+ " function recurse(d) {\n"
+ " if(d.children) d.children.forEach( function(child) { recurse(child); } );\n"
+ " else sum += d.size;\n"
+ " }\n"
+ " recurse(d,sum);\n"
+ " console.log(sum);\n"
+ " console.log(d.children);\n"
+ " return sum;\n"
+ " } else {\n"
+ " console.log(d.size);\n"
+ " return d.size;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "function isParentOf(p, c) {\n"
+ " if (p === c) return true;\n"
+ " if (p.children) {\n"
+ " return p.children.some(function(d) {\n"
+ " return isParentOf(d, c);\n"
+ " });\n"
+ " }\n"
+ " return false;\n"
+ "}\n"
+ "\n"
+ "function colour(d) {\n"
+ " return color(d.name);\n"
+ "}\n"
+ "\n"
+ "// Interpolate the scales!\n"
+ "function arcTween(d) {\n"
+ " var my = maxY(d),\n"
+ " xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),\n"
+ " yd = d3.interpolate(y.domain(), [d.y, my]),\n"
+ " yr = d3.interpolate(y.range(), [d.y ? 20 : 0, r]);\n"
+ " return function(d) {\n"
+ " return function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };\n"
+ " };\n"
+ "}\n"
+ "\n"
+ "// Interpolate the scales!\n"
+ "function arcTween2(d) {\n"
+ " var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),\n"
+ " yd = d3.interpolate(y.domain(), [d.y, 1]),\n"
+ " yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);\n"
+ " return function(d, i) {\n"
+ " return i\n"
+ " ? function(t) { return arc(d); }\n"
+ " : function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };\n"
+ " };\n"
+ "}\n"
+ "\n"
+ "function maxY(d) {\n"
+ " return d.children ? Math.max.apply(Math, d.children.map(maxY)) : d.y + d.dy;\n"
+ "}\n"
+ "\n"
+ "// http://www.w3.org/WAI/ER/WD-AERT/#color-contrast\n"
+ "function brightness(rgb) {\n"
+ " return rgb.r * .299 + rgb.g * .587 + rgb.b * .114;\n"
+ "}\n"
+ "d3.select(\"#download\").on(\"click\", function () {\n"
+ "d3.select(this).attr(\"href\", 'data:application/octet-stream;base64,' + btoa(d3.select(\"#chart\").html())).attr(\"download\", \"memorysun.svg\")})\n\n"
+ "click(nodes[0]);\n"
+ " " << std::endl
+ << "</script>" << std::endl
+ << "</body>" << std::endl
+ << "</html>" << std::endl;
+ return jsonbody.str();
+}
+
+template<>
+void write_structure_tree<HTML_FORMAT>(const structure_tree_node* v, std::ostream& out, SDSL_UNUSED size_t level)
+{
+ std::stringstream json_data;
+ write_structure_tree<JSON_FORMAT>(v, json_data);
+
+ out << create_html_header("sdsl data structure visualization");
+ out << create_js_body(json_data.str());
+}
+
+} // namespace end
diff --git a/lib/uint128_t.cpp b/lib/uint128_t.cpp
new file mode 100644
index 0000000..379f66e
--- /dev/null
+++ b/lib/uint128_t.cpp
@@ -0,0 +1,19 @@
+#include "sdsl/uint128_t.hpp"
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+
+std::ostream& operator<<(std::ostream& os, const uint128_t& x)
+{
+ uint64_t X[2] = {(uint64_t)(x >> 64), (uint64_t)x};
+ for (int j=0; j < 2; ++j) {
+ for (int i=0; i < 16; ++i) {
+ os << std::hex << ((X[j]>>60)&0xFULL);
+ X[j] <<= 4;
+ }
+ }
+ return os;
+}
+
+} // end namespace
diff --git a/lib/uint256_t.cpp b/lib/uint256_t.cpp
new file mode 100644
index 0000000..14e609c
--- /dev/null
+++ b/lib/uint256_t.cpp
@@ -0,0 +1,17 @@
+#include "sdsl/uint256_t.hpp"
+
+//! Namespace for the succinct data structure library
+namespace sdsl
+{
+std::ostream& operator<<(std::ostream& os, const uint256_t& x)
+{
+ uint64_t X[4] = {(uint64_t)(x.m_high >> 64), (uint64_t)x.m_high, x.m_mid, x.m_lo};
+ for (int j=0; j < 4; ++j) {
+ for (int i=0; i < 16; ++i) {
+ os << std::hex << ((X[j]>>60)&0xFULL) << std::dec;
+ X[j] <<= 4;
+ }
+ }
+ return os;
+}
+} // end namespace
diff --git a/lib/util.cpp b/lib/util.cpp
new file mode 100644
index 0000000..a291b78
--- /dev/null
+++ b/lib/util.cpp
@@ -0,0 +1,145 @@
+/* sdsl - succinct data structures library
+ Copyright (C) 2009-2013 Simon Gog
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "sdsl/util.hpp"
+#include "cxxabi.h"
+#include <sys/types.h> // for file_size
+#include <sys/stat.h> // for file_size
+#include <iomanip>
+#include <vector>
+#include <string>
+
+namespace sdsl
+{
+
+namespace util
+{
+
+uint64_t _id_helper::id = 0;
+
+std::string basename(std::string file)
+{
+ file = disk_file_name(file); // remove RAM-prefix
+ char* c = strdup((const char*)file.c_str());
+ std::string res = std::string(::basename(c));
+ free(c);
+ return res;
+}
+
+std::string dirname(std::string file)
+{
+ bool ram_file = is_ram_file(file);
+ file = disk_file_name(file); // remove RAM-prefix
+ char* c = strdup((const char*)file.c_str());
+ std::string res = std::string(::dirname(c));
+ free(c);
+ if (ram_file) {
+ if ("." == res) {
+ res = ram_file_name("");
+ } else if ("/" ==res) {
+ res = ram_file_name(res);
+ }
+ }
+ return res;
+}
+
+uint64_t pid()
+{
+ return getpid();
+}
+
+uint64_t id()
+{
+ return _id_helper::getId();
+}
+
+std::string demangle(const std::string& name)
+{
+#ifndef HAVE_CXA_DEMANGLE
+ char buf[4096];
+ size_t size = 4096;
+ int status = 0;
+ abi::__cxa_demangle(name.c_str(), buf, &size, &status);
+ if (status==0)
+ return std::string(buf);
+ return name;
+#else
+ return name;
+#endif
+}
+
+std::string demangle2(const std::string& name)
+{
+ std::string result = demangle(name);
+ std::vector<std::string> words_to_delete;
+ words_to_delete.push_back("sdsl::");
+ words_to_delete.push_back("(unsigned char)");
+ words_to_delete.push_back(", unsigned long");
+
+ for (size_t k=0; k<words_to_delete.size(); ++k) {
+ std::string w = words_to_delete[k];
+ for (size_t i = result.find(w); i != std::string::npos; i = result.find(w, i)) {
+ result.erase(i, w.length());
+ ++i;
+ }
+ }
+ size_t index = 0;
+ std::string to_replace = "int_vector<1>";
+ while ((index = result.find(to_replace, index)) != std::string::npos) {
+ result.replace(index, to_replace.size(), "bit_vector");
+ }
+ return result;
+}
+
+void delete_all_files(tMSS& file_map)
+{
+ for (auto file_pair : file_map) {
+ sdsl::remove(file_pair.second);
+ }
+ file_map.clear();
+}
+
+std::string to_latex_string(unsigned char c)
+{
+ if (c == '_')
+ return "\\_";
+ else if (c == '\0')
+ return "\\$";
+ else
+ return to_string(c);
+}
+
+void set_verbose()
+{
+ verbose = true;
+}
+
+off_t file_size(const std::string& file)
+{
+ if (is_ram_file(file)) {
+ return ram_fs::file_size(file);
+ } else {
+ struct stat filestatus;
+ stat(file.c_str(), &filestatus);
+ return filestatus.st_size;
+ }
+}
+
+}// end namespace util
+
+}// end namespace sdsl
+
diff --git a/lib/wt_helper.cpp b/lib/wt_helper.cpp
new file mode 100644
index 0000000..b117460
--- /dev/null
+++ b/lib/wt_helper.cpp
@@ -0,0 +1,35 @@
+#include "sdsl/wt_helper.hpp"
+
+namespace sdsl
+{
+
+bool empty(const range_type& r)
+{
+ return r.first == r.second + 1;
+}
+
+int_vector<>::size_type size(const range_type& r)
+{
+ return r.second - r.first + 1;
+}
+
+
+pc_node::pc_node(uint64_t freq, uint64_t sym, uint64_t parent,
+ uint64_t child_left, uint64_t child_right):
+ freq(freq), sym(sym), parent(parent)
+{
+ child[0] = child_left;
+ child[1] = child_right;
+}
+
+pc_node& pc_node::operator=(const pc_node& v)
+{
+ freq = v.freq;
+ sym = v.sym;
+ parent = v.parent;
+ child[0] = v.child[0];
+ child[1] = v.child[1];
+ return *this;
+}
+
+}
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..eb731a7
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,7 @@
+*.x
+*.x.dSYM
+*.gcno
+*.gcda
+*.swp
+*.swo
+CompileTest.hpp
diff --git a/test/BitVectorGenerator.cpp b/test/BitVectorGenerator.cpp
new file mode 100644
index 0000000..6e0c6d0
--- /dev/null
+++ b/test/BitVectorGenerator.cpp
@@ -0,0 +1,67 @@
+#include "sdsl/int_vector.hpp"
+#include <string>
+#include <cstdlib>
+#include <random>
+
+using namespace std;
+using namespace sdsl;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3) {
+ cout << "Usage: " << argv[0] << " FILE BIT_VECTOR_ID" << endl;
+ cout << " Generator program for bit_vectors." << endl;
+ cout << " (1) The corresponding bit_vector for BIT_VECTOR_ID is generated." << endl;
+ cout << " (2) The bit_vector is stored to FILE." << endl;
+ return 1;
+ }
+ string ID = argv[2];
+ bit_vector bv;
+ if ("CRAFTED-32" == ID) {
+ bv = bit_vector(32, 0);
+ bv[1] = bv[4] = bv[7] = bv[18] = bv[24] = bv[26] = bv[30] = bv[31] = 1;
+ } else if ("CRAFTED-SPARSE-0" == ID or "CRAFTED-SPARSE-1" == ID) {
+ bool default_value = ID[ID.length()-1]-'0';
+ bv = bit_vector(1000000, default_value);
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, bv.size()-1);
+ auto dice = bind(distribution, rng);
+ // populate vectors with some other bits
+ for (uint64_t i=0; i < bv.size()/1000; ++i) {
+ uint64_t x = dice();
+ bv[x] = !default_value;
+ }
+ } else if ("CRAFTED-BLOCK-0" == ID or "CRAFTED-BLOCK-1" == ID) {
+ bool default_value = ID[ID.length()-1]-'0';
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution1(0, bv.size()-1);
+ std::uniform_int_distribution<uint64_t> distribution2(0, 999);
+ auto dice1 = bind(distribution1, rng);
+ auto dice2 = bind(distribution2, rng);
+ bv = bit_vector(1000000, default_value);
+ // populate vectors with some blocks of other bits
+ for (uint64_t i=0; i< bv.size()/1000; ++i) {
+ uint64_t x = dice1();
+ uint64_t len = dice2();
+ for (uint64_t j=x; j<x+len and j<bv.size(); ++j) {
+ bv[j] = 1-default_value;
+ }
+ }
+ } else if ("CRAFTED-MAT-SELECT") {
+ // Matthias Petri's test
+ srand(4711);
+ uint64_t ones = 4030+(rand()%80);
+ bv = bit_vector(1000000);
+ for (uint64_t i=0; i<ones; i++) {
+ uint64_t rnd = rand();
+ while (bv[rnd%bv.size()]==1) {
+ rnd = rand();
+ }
+ bv[rnd%bv.size()] = 1;
+ }
+ } else {
+ cerr << "ID not found. No bitvector generated." << endl;
+ return 1;
+ }
+ store_to_file(bv, argv[1]);
+}
diff --git a/test/BitVectorTest.config b/test/BitVectorTest.config
new file mode 100644
index 0000000..39ca5d9
--- /dev/null
+++ b/test/BitVectorTest.config
@@ -0,0 +1,35 @@
+# Inputs which should be used in BitVectorTest,
+# RankSupportTest, SelectSupportTest, and
+# SelectSupport0Test
+# Each line contains an ID and a path to a bit_vector.
+BIT-EMPTY;test_cases/int-vec.0.1.0;
+BIT-1-1-0;test_cases/int-vec.1.1.0;
+BIT-1000000-1-0;test_cases/int-vec.1000000.1.0;
+BIT-1000000-1-1;test_cases/int-vec.1000000.1.1;
+BIT-07-1-1;test_cases/int-vec.7.1.1;
+BIT-08-1-0;test_cases/int-vec.8.1.0;
+BIT-09-1-1;test_cases/int-vec.9.1.1;
+BIT-10-1-0;test_cases/int-vec.10.1.0;
+BIT-11-1-1;test_cases/int-vec.11.1.1;
+BIT-12-1-0;test_cases/int-vec.12.1.0;
+BIT-13-1-1;test_cases/int-vec.13.1.1;
+BIT-14-1-0;test_cases/int-vec.14.1.0;
+BIT-15-1-1;test_cases/int-vec.15.1.1;
+BIT-8-1-r-17;test_cases/int-vec.8.1.r.17;
+BIT-16-1-r-42;test_cases/int-vec.16.1.r.42;
+BIT-32-1-r-111;test_cases/int-vec.32.1.r.111;
+BIT-64-1-r-222;test_cases/int-vec.64.1.r.222;
+BIT-128-1-r-73;test_cases/int-vec.128.1.r.73;
+BIT-256-1-r-4887;test_cases/int-vec.256.1.r.4887;
+BIT-512-1-r-432;test_cases/int-vec.512.1.r.432;
+BIT-1024-1-r-898;test_cases/int-vec.1024.1.r.898;
+BIT-2048-1-r-5432;test_cases/int-vec.2048.1.r.5432;
+BIT-4096-1-r-793;test_cases/int-vec.4096.1.r.793;
+BIT-8192-1-r-1043;test_cases/int-vec.8192.1.r.1043;
+BIT-1000000-1-r-815;test_cases/int-vec.1000000.1.r.815;
+CRAFTED-32;test_cases/bit-vec.CRAFTED-32;
+CRAFTED-SPARSE-0;test_cases/bit-vec.CRAFTED-SPARSE-0;
+CRAFTED-SPARSE-1;test_cases/bit-vec.CRAFTED-SPARSE-1;
+CRAFTED-BLOCK-0;test_cases/bit-vec.CRAFTED-BLOCK-0;
+CRAFTED-BLOCK-1;test_cases/bit-vec.CRAFTED-BLOCK-1;
+CRAFTED-MAT-SELECT;test_cases/bit-vec.CRAFTED-MAT-SELECT;
diff --git a/test/BitVectorTest.cpp b/test/BitVectorTest.cpp
new file mode 100644
index 0000000..cea6709
--- /dev/null
+++ b/test/BitVectorTest.cpp
@@ -0,0 +1,126 @@
+#include "sdsl/bit_vectors.hpp" // for rrr_vector
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+string test_file;
+
+namespace
+{
+
+template<class T>
+class BitVectorTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<
+bit_vector,
+bit_vector_il<64>,
+bit_vector_il<128>,
+bit_vector_il<256>,
+bit_vector_il<512>,
+bit_vector_il<1024>,
+rrr_vector<64>,
+rrr_vector<256>,
+rrr_vector<129>,
+rrr_vector<192>,
+rrr_vector<255>,
+rrr_vector<15>,
+rrr_vector<31>,
+rrr_vector<63>,
+rrr_vector<83>,
+rrr_vector<127>,
+rrr_vector<128>,
+sd_vector<>,
+sd_vector<rrr_vector<63> >
+> Implementations;
+
+
+
+TYPED_TEST_CASE(BitVectorTest, Implementations);
+
+
+//! Test operator[]
+TYPED_TEST(BitVectorTest, Access)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ bit_vector bv;
+ ASSERT_TRUE(load_from_file(bv, test_file));
+ TypeParam c_bv(bv);
+ ASSERT_EQ(bv.size(), c_bv.size());
+ for (uint64_t j=0; j < bv.size(); ++j) {
+ ASSERT_EQ((bool)(bv[j]), (bool)(c_bv[j]));
+ }
+ TypeParam mo_bv = TypeParam(bv);
+ ASSERT_EQ(bv.size(), mo_bv.size());
+ for (uint64_t j=0; j < bv.size(); ++j) {
+ ASSERT_EQ((bool)(bv[j]), (bool)(c_bv[j]));
+ }
+}
+
+TYPED_TEST(BitVectorTest, GetInt)
+{
+ bit_vector bv;
+ ASSERT_TRUE(load_from_file(bv, test_file));
+ TypeParam c_bv(bv);
+ ASSERT_EQ(bv.size(), c_bv.size());
+ uint8_t len = 63;
+ for (uint64_t j=0; j+len < bv.size(); j+=len) {
+ ASSERT_EQ(bv.get_int(j, len), c_bv.get_int(j, len));
+ }
+}
+
+TYPED_TEST(BitVectorTest, GetIntAllBlockSizes)
+{
+ bit_vector bv(10000, 0);
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, 9);
+ auto dice = bind(distribution, rng);
+ for (size_t i=1001; i < bv.size(); ++i) {
+ if (0 == dice())
+ bv[i] = 1;
+ }
+
+ TypeParam c_bv(bv);
+ for (uint8_t len=1; len<=64; ++len) {
+ for (size_t i=0; i+len <= bv.size(); ++i) {
+ ASSERT_EQ(bv.get_int(i,len), c_bv.get_int(i,len))
+ << "i="<<i<<" len="<<(int)len<<endl;
+ }
+ }
+}
+
+TYPED_TEST(BitVectorTest, Swap)
+{
+ bit_vector bv;
+ ASSERT_TRUE(load_from_file(bv, test_file));
+ TypeParam c_bv(bv);
+ ASSERT_EQ(bv.size(), c_bv.size());
+ TypeParam bv_empty;
+ ASSERT_EQ((uint64_t)0, bv_empty.size());
+ bv_empty.swap(c_bv);
+ ASSERT_EQ((uint64_t)0, c_bv.size());
+ ASSERT_EQ(bv.size(), bv_empty.size());
+ for (uint64_t j=0; j < bv.size(); ++j) {
+ ASSERT_EQ((bool)(bv[j]), (bool)(bv_empty[j]));
+ }
+}
+
+}// end namespace
+
+int main(int argc, char* argv[])
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 2) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " FILE " << endl;
+ cout << " Reads a bitvector from FILE and executes tests." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ return RUN_ALL_TESTS();
+}
+
diff --git a/test/BitsTest.cpp b/test/BitsTest.cpp
new file mode 100644
index 0000000..304a666
--- /dev/null
+++ b/test/BitsTest.cpp
@@ -0,0 +1,190 @@
+#include "sdsl/int_vector.hpp"
+#include "sdsl/bits.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+
+namespace
+{
+
+SDSL_UNUSED uint32_t cnt_naive(uint64_t x)
+{
+ uint32_t res = 0;
+ for (int i=0; i<64; ++i) {
+ res += x&1;
+ x>>=1;
+ }
+ return res;
+}
+
+SDSL_UNUSED inline uint32_t cnt10_naive(uint64_t x, uint64_t& c)
+{
+ uint32_t sum = 0, lastbit = c;
+ for (uint32_t i=0; i<64; ++i) {
+ if ((x&1) == 0 and lastbit == 1) {
+ ++sum;
+ }
+ lastbit = (x&1);
+ x >>= 1;
+ }
+ c = lastbit;
+ return sum;
+}
+
+SDSL_UNUSED uint32_t cnt11_naive(uint64_t x)
+{
+ uint32_t res = 0;
+ for (int i=0; i<64; ++i) {
+ if ((x&3) == 3) {
+ ++res;
+ ++i;
+ x>>=1;
+ }
+ x>>=1;
+ }
+ return res;
+}
+
+SDSL_UNUSED inline uint32_t hi_naive(uint64_t x)
+{
+ uint32_t res=63;
+ while (x) {
+ if (x&0x8000000000000000ULL) {
+ return res;
+ }
+ --res;
+ x<<=1;
+ }
+ return 0;
+}
+
+inline uint32_t lo_naive(uint64_t x)
+{
+ if (x&1)
+ return 0;
+ x>>=1;
+ for (int i=1; i<64; ++i)
+ if (x&1)
+ return i;
+ else
+ x>>=1;
+ return 63;
+}
+
+SDSL_UNUSED inline uint32_t sel_naive(uint64_t x, uint32_t i)
+{
+ uint32_t pos = 0;
+ while (x) {
+ i -= x&1;
+ x>>=1;
+ if (!i) break;
+ ++pos;
+ }
+ return pos;
+}
+
+SDSL_UNUSED uint32_t sel11_naive(uint64_t x, uint32_t i)
+{
+ for (uint32_t j=0; j<63; ++j) {
+ if ((x&3)==3) {
+ i--;
+ if (!i) return j+1;
+ x>>=1;
+ ++j;
+ }
+ x>>=1;
+ }
+ return 63;
+}
+
+SDSL_UNUSED inline uint64_t rev_naive(uint64_t x)
+{
+ uint64_t y = 0;
+ for (size_t i=0; i<64; i++) {
+ if (x&(1ULL << i)) {
+ y |= (1ULL << (63-i));
+ }
+ }
+ return y;
+}
+
+
+// The fixture for testing class int_vector.
+class BitsTest : public ::testing::Test
+{
+ protected:
+
+ BitsTest() {
+ m_data = sdsl::int_vector<64>(1000000);
+ sdsl::util::set_random_bits(m_data);
+ }
+
+ virtual ~BitsTest() { }
+
+ virtual void SetUp() { }
+
+ virtual void TearDown() { }
+ sdsl::int_vector<64> m_data;
+};
+
+//! Test the default constructor
+TEST_F(BitsTest, cnt)
+{
+ for (uint64_t i=0; i<64; ++i) {
+ ASSERT_EQ((uint64_t)1, sdsl::bits::cnt(1ULL<<i));
+ }
+}
+
+//! Test the parametrized constructor
+TEST_F(BitsTest, sel)
+{
+ for (uint64_t i=0; i<64; ++i) {
+ ASSERT_EQ(i, sdsl::bits::sel(1ULL<<i, 1));
+ }
+ for (uint64_t i=0; i < this->m_data.size(); ++i) {
+ uint64_t x = this->m_data[i];
+ for (uint64_t j=0, ones=0; j<64; ++j) {
+ if ((x >> j)&1) {
+ ++ones;
+ ASSERT_EQ(j, sdsl::bits::sel(x, ones));
+ }
+ }
+ }
+}
+
+TEST_F(BitsTest, hi)
+{
+ for (uint64_t i=0; i<64; ++i) {
+ uint64_t x = 1ULL<<i;
+ ASSERT_EQ(hi_naive(x), sdsl::bits::hi(x));
+ }
+}
+
+
+TEST_F(BitsTest, lo)
+{
+ for (uint64_t i=0; i<64; ++i) {
+ uint64_t x = 1ULL<<i;
+ ASSERT_EQ(lo_naive(x), sdsl::bits::lo(x));
+ }
+}
+
+TEST_F(BitsTest, rev)
+{
+ for (uint64_t i=0; i < this->m_data.size(); ++i) {
+ uint64_t x = this->m_data[i];
+ uint64_t rx = sdsl::bits::rev(x);
+ ASSERT_EQ(rev_naive(x),rx);
+ ASSERT_EQ(x,sdsl::bits::rev(rx));
+ }
+}
+
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/CoderTest.cpp b/test/CoderTest.cpp
new file mode 100644
index 0000000..979b3d9
--- /dev/null
+++ b/test/CoderTest.cpp
@@ -0,0 +1,106 @@
+#include "sdsl/int_vector.hpp"
+#include "sdsl/coder.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <random>
+
+namespace
+{
+
+using namespace sdsl;
+
+// The fixture for testing class int_vector.
+template<class T>
+class CoderTest : public ::testing::Test
+{
+ protected:
+
+ CoderTest() {
+ m_data = sdsl::int_vector<>(10000000);
+ util::set_random_bits(m_data);
+ for (size_t i=0; i<m_data.size()/3; ++i)
+ m_data[i] = i;
+
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, 6);
+ auto dice = bind(distribution, rng);
+ for (size_t i=m_data.size()/3; i<2*m_data.size()/3; ++i)
+ m_data[i] = dice();
+ }
+
+ virtual ~CoderTest() { }
+
+ virtual void SetUp() { }
+
+ virtual void TearDown() { }
+ sdsl::int_vector<> m_data;
+};
+
+using testing::Types;
+typedef Types<
+ coder::elias_delta,
+ coder::elias_gamma,
+ coder::fibonacci,
+ coder::comma<>,
+ coder::comma<4>,
+ coder::comma<8>,
+ coder::comma<16>
+ >
+ Implementations;
+
+TYPED_TEST_CASE(CoderTest, Implementations);
+
+TYPED_TEST(CoderTest, SinlgeEncodeDecode)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ uint8_t offset = 0;
+ uint64_t buf[8] = {0};
+ uint64_t* pb = buf;
+ for (size_t i=0; i<this->m_data.size(); ++i) {
+ TypeParam::encode(this->m_data[i], pb, offset);
+ pb = buf;
+ offset = 0;
+ uint64_t x = TypeParam::template decode<false,false,uint64_t*>(buf, 0, 1);
+ ASSERT_EQ(this->m_data[i], x);
+ }
+}
+
+TYPED_TEST(CoderTest, AllEncodeDecode)
+{
+ int_vector<> tmp,data;
+ TypeParam::encode(this->m_data, tmp);
+ TypeParam::decode(tmp, data);
+ ASSERT_EQ(this->m_data.size(), data.size());
+ for (size_t i=0; i<this->m_data.size(); ++i) {
+ ASSERT_EQ(this->m_data[i], data[i]);
+ }
+}
+
+TYPED_TEST(CoderTest, DecodePrefixSum)
+{
+ int_vector<> tmp;
+ TypeParam::encode(this->m_data, tmp);
+ uint64_t start = 0;
+ const uint64_t sample = 32;
+ for (size_t i=0; i<this->m_data.size(); ++i) {
+ uint64_t sum = 0;
+ uint64_t lstart = start;
+ if (i%sample==0) {
+ for (size_t j=1; j<=sample and i+j-1<this->m_data.size(); ++j) {
+ sum += this->m_data[i+j-1];
+ ASSERT_EQ(sum, TypeParam::decode_prefix_sum(tmp.data(), lstart, j));
+ uint64_t x = TypeParam::template decode<true,false,uint64_t*>(tmp.data(), lstart, j);
+ ASSERT_EQ(sum, x);
+ }
+ }
+ start += TypeParam::encoding_length(this->m_data[i]);
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/CompileTest.cpp b/test/CompileTest.cpp
new file mode 100644
index 0000000..fa70e51
--- /dev/null
+++ b/test/CompileTest.cpp
@@ -0,0 +1,18 @@
+#include "gtest/gtest.h"
+#include "CompileTest.hpp"
+
+namespace
+{
+// The fixture for testing the compilation of all header files.
+class CompileTest : public ::testing::Test { };
+
+//! Test constructors
+TEST_F(CompileTest, Compile) { }
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/CsaByteTest.config b/test/CsaByteTest.config
new file mode 100644
index 0000000..8a96b77
--- /dev/null
+++ b/test/CsaByteTest.config
@@ -0,0 +1,7 @@
+# Texts which should be used in the CsaByteTest.
+# Format: [TC_ID];[TC_PATH];[TC_NAME]
+TXT-EMPTY;test_cases/empty.txt;empty
+TXT-EXAMPE01;test_cases/example01.txt;example01
+TXT-100A;test_cases/100a.txt;100a
+TXT-FAUST;test_cases/faust.txt;faust-de
+TXT-ZARATHUSTRA;test_cases/zarathustra.txt;zarathustra-de
diff --git a/test/CsaByteTest.cpp b/test/CsaByteTest.cpp
new file mode 100644
index 0000000..db1d7f3
--- /dev/null
+++ b/test/CsaByteTest.cpp
@@ -0,0 +1,246 @@
+#include "sdsl/suffix_arrays.hpp"
+#include "sdsl/coder.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+
+namespace
+{
+
+using namespace sdsl;
+using namespace std;
+
+typedef int_vector<>::size_type size_type;
+
+tMSS test_case_file_map;
+string test_file;
+string temp_file;
+string temp_dir;
+bool in_memory;
+
+template<class T>
+class CsaByteTest : public ::testing::Test { };
+
+
+using testing::Types;
+
+typedef Types<
+csa_wt<>,
+ csa_sada<>,
+ csa_sada<enc_vector<coder::fibonacci>>,
+ csa_sada<enc_vector<coder::elias_gamma>>,
+ csa_wt<wt_huff<>, 8, 16, text_order_sa_sampling<>>,
+ csa_wt<wt_huff<>, 8, 16, sa_order_sa_sampling<>>,
+ csa_wt<wt_huff<>, 8, 16, sa_order_sa_sampling<>, int_vector<>,
+ succinct_byte_alphabet<bit_vector, rank_support_v<>, select_support_mcl<>>>,
+ csa_wt<wt_huff<>, 8, 16, sa_order_sa_sampling<>, int_vector<>,
+ succinct_byte_alphabet<>>,
+ csa_bitcompressed<>
+ > Implementations;
+
+TYPED_TEST_CASE(CsaByteTest, Implementations);
+
+TYPED_TEST(CsaByteTest, CreateAndStoreTest)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ TypeParam csa;
+ cache_config config(false, temp_dir, util::basename(test_file));
+ construct(csa, test_file, config, 1);
+ test_case_file_map = config.file_map;
+ ASSERT_TRUE(store_to_file(csa, temp_file));
+}
+
+//! Test sigma member
+TYPED_TEST(CsaByteTest, Sigma)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ text.resize(text.size()+1);
+ text[text.size()-1] = 0; // add 0-character to the end
+ ASSERT_EQ(text.size(), csa.size());
+ bit_vector occur(256, 0);
+ uint16_t sigma = 0;
+ for (size_type j=0; j<text.size(); ++j) {
+ if (!occur[text[j]]) {
+ occur[text[j]] = 1;
+ ++sigma;
+ }
+ }
+ ASSERT_EQ(sigma, csa.sigma);
+}
+
+//! Test suffix array access methods
+TYPED_TEST(CsaByteTest, SaAccess)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> sa;
+ load_from_file(sa, test_case_file_map[conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(sa[j], csa[j])<<" j="<<j;
+ }
+}
+
+//! Test inverse suffix access methods
+TYPED_TEST(CsaByteTest, IsaAccess)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> isa;
+ size_type n = 0;
+ {
+ int_vector<> sa;
+ load_from_file(sa, test_case_file_map[conf::KEY_SA]);
+ n = sa.size();
+ ASSERT_EQ(n, csa.size());
+ isa = sa;
+ for (size_type j=0; j<n; ++j) {
+ isa[sa[j]] = j;
+ }
+ }
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(isa[j], csa.isa[j])<<" j="<<j;
+ }
+}
+
+//! Test text access methods
+TYPED_TEST(CsaByteTest, TextAccess)
+{
+ if (test_case_file_map.find(conf::KEY_TEXT) != test_case_file_map.end()) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<8> text;
+ load_from_file(text, test_case_file_map[conf::KEY_TEXT]);
+ size_type n = text.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(text[j], csa.text[j])<<" j="<<j;
+ }
+ auto len = std::min(csa.size(),
+ std::max(csa.size()/10, (decltype(csa.size()))20));
+ auto ex_text = extract(csa, 0, len-1);
+ for (size_type j=0; j<len; ++j) {
+ ASSERT_EQ(text[j], (decltype(text[j]))ex_text[j])<<" j="<<j;
+ }
+ }
+}
+
+//! Test Burrows-Wheeler access methods
+TYPED_TEST(CsaByteTest, BwtAccess)
+{
+ if (test_case_file_map.find(conf::KEY_BWT) != test_case_file_map.end()) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<8> bwt;
+ load_from_file(bwt, test_case_file_map[conf::KEY_BWT]);
+ size_type n = bwt.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(bwt[j], csa.bwt[j])<<" j="<<j;
+ }
+ }
+}
+
+TYPED_TEST(CsaByteTest, FAccess)
+{
+ if (test_case_file_map.find(conf::KEY_TEXT) != test_case_file_map.end()) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<8> text;
+ load_from_file(text, test_case_file_map[conf::KEY_TEXT]);
+ std::sort(begin(text),end(text));
+ size_type n = text.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; j+=200) {
+ ASSERT_EQ(text[j], csa.F[j])<<" j="<<j;
+ }
+ }
+}
+
+
+//! Test Psi access methods
+TYPED_TEST(CsaByteTest, PsiAccess)
+{
+ if (test_case_file_map.find(conf::KEY_PSI) != test_case_file_map.end()) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> psi;
+ load_from_file(psi, test_case_file_map[conf::KEY_PSI]);
+ size_type n = psi.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(psi[j], csa.psi[j])<<" j="<<j;
+ }
+ }
+}
+
+//! Test if Psi[LF[i]]=i
+TYPED_TEST(CsaByteTest, PsiLFAccess)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ for (size_type j=0; j<csa.size(); ++j) {
+ size_type lf = csa.lf[j];
+ ASSERT_TRUE(lf < csa.size());
+ ASSERT_EQ(j, csa.psi[lf])<<" j="<<j;
+ }
+}
+
+
+//! Test access after swap
+TYPED_TEST(CsaByteTest, SwapTest)
+{
+ TypeParam csa1;
+ ASSERT_TRUE(load_from_file(csa1, temp_file));
+ TypeParam csa2;
+ csa1.swap(csa2);
+ int_vector<> sa;
+ load_from_file(sa, test_case_file_map[conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, csa2.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ((typename TypeParam::value_type)sa[j], csa2[j]);
+ }
+}
+
+
+TYPED_TEST(CsaByteTest, DeleteTest)
+{
+ sdsl::remove(temp_file);
+ util::delete_all_files(test_case_file_map);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 4) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file temp_file tmp_dir [in-memory]" << endl;
+ cout << " (1) Generates a CSA out of test_file; stores it in temp_file." << endl;
+ cout << " Temporary files (SA/BWT/TEXT) are stored in tmp_dir." << endl;
+ cout << " If `in-memory` is specified, the in-memory construction is tested." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_file = argv[2];
+ temp_dir = argv[3];
+ in_memory = argc > 4;
+ if (in_memory) {
+ temp_dir = "@";
+ int_vector<8> data;
+ load_vector_from_file(data, test_file, 1);
+ test_file = ram_file_name(test_file);
+ store_to_plain_array<uint8_t>(data, test_file);
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/test/CsaIntTest.config b/test/CsaIntTest.config
new file mode 100644
index 0000000..93f6ec9
--- /dev/null
+++ b/test/CsaIntTest.config
@@ -0,0 +1,9 @@
+# Texts which should be used in the CsaIntTest.
+# Each line contains [TC_ID];[TC_PATH];[TC_NAME];[NUM_BYTE]
+TXT-EMPTY;test_cases/empty.txt;empty;1
+TXT-EXAMPE01;test_cases/example01.txt;example01;1
+TXT-100A;test_cases/100a.txt;100a;1
+TXT-FAUST;test_cases/faust.txt;faust-de;1
+TXT-ZARATHUSTRA;test_cases/zarathustra.txt;zarathustra-de;1
+INT-KEEPER;test_cases/keeper.int;keeper.int;8
+INT-MOBY;test_cases/moby.int;moby.int;8
diff --git a/test/CsaIntTest.cpp b/test/CsaIntTest.cpp
new file mode 100644
index 0000000..4d2690a
--- /dev/null
+++ b/test/CsaIntTest.cpp
@@ -0,0 +1,250 @@
+#include "sdsl/suffix_arrays.hpp"
+#include "gtest/gtest.h"
+#include <cstdlib>
+#include <vector>
+#include <string>
+
+namespace
+{
+
+using namespace sdsl;
+using namespace std;
+
+typedef int_vector<>::size_type size_type;
+tMSS test_case_file_map;
+string test_file;
+uint8_t num_bytes;
+string temp_file;
+string temp_dir;
+bool in_memory;
+
+
+template<class T>
+class CsaIntTest : public ::testing::Test { };
+
+
+using testing::Types;
+
+typedef Types< csa_wt<wt_int<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, int_alphabet<> >,
+ csa_sada<enc_vector<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, int_alphabet<> >,
+ csa_bitcompressed<int_alphabet<> >,
+ csa_wt<wt_int<rrr_vector<63> >, 8, 8, sa_order_sa_sampling<>, int_vector<>, int_alphabet<> >,
+ csa_wt<wt_int<>, 32, 32, text_order_sa_sampling<>, int_vector<>, int_alphabet<> >,
+ csa_sada<enc_vector<>, 32, 32, text_order_sa_sampling<>, int_vector<>, int_alphabet<> >
+ > Implementations;
+
+TYPED_TEST_CASE(CsaIntTest, Implementations);
+
+TYPED_TEST(CsaIntTest, CreateAndStoreTest)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ TypeParam csa;
+ cache_config config(false, temp_dir, util::basename(test_file));
+ construct(csa, test_file, config, num_bytes);
+ test_case_file_map = config.file_map;
+ ASSERT_TRUE(store_to_file(csa, temp_file));
+}
+
+//! Test access methods
+TYPED_TEST(CsaIntTest, Sigma)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> text;
+ load_vector_from_file(text, test_file, num_bytes);
+ text.resize(text.size()+1);
+ text[text.size()-1] = 0; // add 0-character at the end
+ size_type n = text.size();
+ ASSERT_EQ(n, csa.size());
+ std::set<uint64_t> occur;
+ size_type sigma = 0;
+ for (size_type j=0; j<n; ++j) {
+ if (occur.end() == occur.find(text[j])) {
+ occur.insert(text[j]);
+ ++sigma;
+ }
+ }
+ ASSERT_EQ(sigma, csa.sigma);
+}
+
+//! Test suffix array access methods
+TYPED_TEST(CsaIntTest, SaAccess)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> sa;
+ load_from_file(sa, test_case_file_map[conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(sa[j], csa[j])<<" j="<<j;
+ }
+}
+
+
+//! Test inverse suffix access methods
+TYPED_TEST(CsaIntTest, IsaAccess)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> isa;
+ size_type n = 0;
+ {
+ int_vector<> sa;
+ load_from_file(sa, test_case_file_map[conf::KEY_SA]);
+ n = sa.size();
+ ASSERT_EQ(n, csa.size());
+ isa = sa;
+ for (size_type j=0; j<n; ++j) {
+ isa[sa[j]] = j; // calculate inverse suffix array
+ }
+ }
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(isa[j], csa.isa[j])<<" j="<<j;
+ }
+}
+
+//! Test Burrows-Wheeler access methods
+TYPED_TEST(CsaIntTest, BwtAccess)
+{
+ if (test_case_file_map.end() != test_case_file_map.find(conf::KEY_BWT_INT)) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> bwt;
+ load_from_file(bwt, test_case_file_map[conf::KEY_BWT_INT]);
+ size_type n = bwt.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(bwt[j], csa.bwt[j])<<" j="<<j;
+ }
+ }
+}
+
+TYPED_TEST(CsaIntTest, FAccess)
+{
+ if (test_case_file_map.end() != test_case_file_map.find(conf::KEY_TEXT_INT)) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> text;
+ load_from_file(text, test_case_file_map[conf::KEY_TEXT_INT]);
+ std::sort(begin(text),end(text));
+ size_type n = text.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; j+=200) {
+ ASSERT_EQ(text[j], csa.F[j])<<" j="<<j;
+ }
+ }
+}
+
+//! Test text access methods
+TYPED_TEST(CsaIntTest, TextAccess)
+{
+ if (test_case_file_map.end() != test_case_file_map.find(conf::KEY_TEXT_INT)) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> text;
+ load_from_file(text, test_case_file_map[conf::KEY_TEXT_INT]);
+ size_type n = text.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(text[j], csa.text[j])<<" j="<<j;
+ }
+ auto len = std::min(csa.size(),
+ std::max(csa.size()/10, (decltype(csa.size()))20));
+ auto ex_text = extract(csa, 0, len-1);
+ for (size_type j=0; j<len; ++j) {
+ ASSERT_EQ(text[j], ex_text[j])<<" j="<<j;
+ }
+ }
+}
+
+//! Test Psi access methods
+TYPED_TEST(CsaIntTest, PsiAccess)
+{
+ if (test_case_file_map.end() != test_case_file_map.find(conf::KEY_PSI)) {
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ int_vector<> psi;
+ load_from_file(psi, test_case_file_map[conf::KEY_PSI]);
+ size_type n = psi.size();
+ ASSERT_EQ(n, csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(psi[j], csa.psi[j])<<" j="<<j;
+ }
+ }
+}
+
+//! Test if Psi[LF[i]]=i
+TYPED_TEST(CsaIntTest, PsiLFAccess)
+{
+ TypeParam csa;
+ ASSERT_TRUE(load_from_file(csa, temp_file));
+ for (size_type j=0; j<csa.size(); ++j) {
+ size_type lf = csa.lf[j];
+ ASSERT_TRUE(lf < csa.size());
+ ASSERT_EQ(j, csa.psi[lf])<<" j="<<j;
+ }
+}
+
+
+//! Test access after swap
+TYPED_TEST(CsaIntTest, SwapTest)
+{
+ TypeParam csa1;
+ ASSERT_TRUE(load_from_file(csa1, temp_file));
+ TypeParam csa2;
+ csa1.swap(csa2);
+ int_vector<> sa;
+ load_from_file(sa, test_case_file_map[conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, csa2.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ((typename TypeParam::value_type)sa[j], csa2[j]);
+ }
+}
+
+TYPED_TEST(CsaIntTest, DeleteTest)
+{
+ sdsl::remove(temp_file);
+ util::delete_all_files(test_case_file_map);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 4) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file num_bytes temp_file tmp_dir" << endl;
+ cout << " (1) Generates a CSA out of test_file; stores it in temp_file." << endl;
+ cout << " Temporary files (SA/BWT/TEXT) are stored in tmp_dir." << endl;
+ cout << " num_bytes specifies who many bytes make a symbol in the"<< endl;
+ cout << " input sequence" << endl;
+ cout << " If `in-memory` is specified, the in-memory construction is tested." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ num_bytes = atoi(argv[2]);
+ temp_file = argv[3];
+ temp_dir = argv[4];
+ in_memory = argc > 5;
+ if (in_memory) {
+ temp_dir = "@";
+ int_vector<> data;
+ load_vector_from_file(data, test_file, num_bytes);
+ test_file = ram_file_name(test_file);
+ switch (num_bytes) {
+ case 0: store_to_file(data, test_file); break;
+ case 1: store_to_plain_array<uint8_t>(data, test_file); break;
+ case 2: store_to_plain_array<uint16_t>(data, test_file); break;
+ case 3: store_to_plain_array<uint32_t>(data, test_file); break;
+ case 4: store_to_plain_array<uint64_t>(data, test_file); break;
+ }
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/test/CstByteTest.config b/test/CstByteTest.config
new file mode 100644
index 0000000..d515efd
--- /dev/null
+++ b/test/CstByteTest.config
@@ -0,0 +1,7 @@
+# Texts which should be used in the CstByteTest.
+# Format: [TC_ID];[TC_PATH];[TC_NAME]
+TXT-EMPTY;test_cases/empty.txt;empty
+TXT-EXAMPE01;test_cases/example01.txt;example01
+TXT-100A;test_cases/100a.txt;100a
+TXT-FAUST;test_cases/faust.txt;faust-de
+#TXT-ZARATHUSTRA;test_cases/zarathustra.txt;zarathustra-de
diff --git a/test/CstByteTest.cpp b/test/CstByteTest.cpp
new file mode 100644
index 0000000..950c79f
--- /dev/null
+++ b/test/CstByteTest.cpp
@@ -0,0 +1,474 @@
+#include "CstHelper.hpp"
+#include "sdsl/suffix_trees.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <set>
+#include <sstream>
+#include <random>
+
+using namespace sdsl;
+using namespace std;
+
+namespace
+{
+
+typedef int_vector<>::size_type size_type;
+typedef bit_vector bit_vector;
+
+tMSS test_case_file_map;
+string test_file;
+string temp_file;
+string temp_dir;
+bool in_memory;
+
+template<class T>
+class CstByteTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<
+cst_sct3<>,
+ cst_sada<>,
+ cst_sct3<cst_sct3<>::csa_type, lcp_bitcompressed<>>,
+ cst_sct3<cst_sct3<>::csa_type, lcp_support_tree2<>>,
+ cst_sada<cst_sada<>::csa_type, lcp_dac<>>,
+ cst_sada<cst_sada<>::csa_type, lcp_vlc<>>,
+ cst_sada<cst_sada<>::csa_type, lcp_byte<>>,
+ cst_sada<cst_sada<>::csa_type, lcp_support_tree2<>, bp_support_gg<>>,
+ cst_sct3<cst_sct3<>::csa_type, lcp_support_tree<>, bp_support_gg<>>,
+ cst_sada<cst_sada<>::csa_type, lcp_support_tree<> >,
+ cst_sct3<cst_sct3<>::csa_type, lcp_support_sada<> >,
+ cst_sct3<cst_sct3<>::csa_type, lcp_wt<> >,
+ cst_sct3<cst_sct3<>::csa_type, lcp_support_tree<>, bp_support_g<> >,
+ cst_sct3<csa_bitcompressed<>, lcp_bitcompressed<> >
+ > Implementations;
+
+TYPED_TEST_CASE(CstByteTest, Implementations);
+
+
+TYPED_TEST(CstByteTest, CreateAndStoreTest)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ TypeParam cst;
+ ASSERT_TRUE(cst.empty());
+ cache_config config(false, temp_dir, util::basename(test_file));
+ construct(cst, test_file, config, 1);
+ test_case_file_map = config.file_map;
+ ASSERT_TRUE(store_to_file(cst, temp_file));
+ TypeParam cst2;
+ cst2 = cst;
+ ASSERT_EQ(cst.size(), cst2.size());
+ ASSERT_TRUE(cst.size() <= TypeParam::max_size());
+}
+
+//! Test the swap method
+TYPED_TEST(CstByteTest, SwapMethod)
+{
+ TypeParam cst1;
+ ASSERT_TRUE(load_from_file(cst1, temp_file));
+ size_type n = cst1.size();
+ TypeParam cst2;
+ ASSERT_EQ((size_type)0, cst2.size());
+ cst1.swap(cst2);
+ ASSERT_EQ((size_type)0, cst1.size());
+ ASSERT_EQ(n, cst2.size());
+ ASSERT_EQ(n, cst2.csa.size());
+ bit_vector mark((size_type)0, cst2.size());
+ check_node_method(cst2);
+}
+
+//! Test the move method
+TYPED_TEST(CstByteTest, MoveMethod)
+{
+ TypeParam cst1;
+ ASSERT_TRUE(load_from_file(cst1, temp_file));
+ size_type n = cst1.size();
+ TypeParam cst2 = std::move(cst1);
+ ASSERT_EQ(n, cst2.size());
+ ASSERT_EQ(n, cst2.csa.size());
+ bit_vector mark((size_type)0, cst2.size());
+ check_node_method(cst2);
+}
+
+
+//! Test the node method
+TYPED_TEST(CstByteTest, NodeMethod)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ // doing a depth first traversal through the tree to count the nodes
+ check_node_method(cst);
+}
+
+//! Test basic methods
+TYPED_TEST(CstByteTest, BasicMethods)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ typedef typename TypeParam::node_type node_type;
+ node_type r = cst.root(); // get root node
+ // Size of the subtree rooted at r should the size of the suffix array
+ ASSERT_EQ(cst.csa.size(), cst.size(r));
+ // Check leaf methods
+ for (size_type i=0; i < cst.csa.size(); ++i) {
+ ASSERT_TRUE(cst.is_leaf(cst.select_leaf(i+1)));
+ }
+}
+
+//! Test suffix array access
+TYPED_TEST(CstByteTest, SaAccess)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ sdsl::int_vector<> sa;
+ sdsl::load_from_file(sa, test_case_file_map[sdsl::conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, cst.csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(sa[j], cst.csa[j])<<" j="<<j;
+ }
+}
+
+//! Test suffix array access after move
+TYPED_TEST(CstByteTest, MoveSaAccess)
+{
+ TypeParam cst_load;
+ ASSERT_TRUE(load_from_file(cst_load, temp_file));
+ TypeParam cst = std::move(cst_load);
+ sdsl::int_vector<> sa;
+ sdsl::load_from_file(sa, test_case_file_map[sdsl::conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, cst.csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(sa[j], cst.csa[j])<<" j="<<j;
+ }
+}
+
+//! Test BWT access
+TYPED_TEST(CstByteTest, BwtAccess)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ sdsl::int_vector<8> bwt;
+ sdsl::load_from_file(bwt, test_case_file_map[sdsl::conf::KEY_BWT]);
+ size_type n = bwt.size();
+ ASSERT_EQ(n, cst.csa.bwt.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(bwt[j], cst.csa.bwt[j])<<" j="<<j;
+ }
+}
+
+//! Test LCP access
+TYPED_TEST(CstByteTest, LcpAccess)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ sdsl::int_vector<> lcp;
+ sdsl::load_from_file(lcp, test_case_file_map[sdsl::conf::KEY_LCP]);
+ size_type n = lcp.size();
+ ASSERT_EQ(n, cst.lcp.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(lcp[j], cst.lcp[j])<<" j="<<j;
+ }
+}
+
+//! Test LCP access after move
+TYPED_TEST(CstByteTest, MoveLcpAccess)
+{
+ TypeParam cst_load;
+ ASSERT_TRUE(load_from_file(cst_load, temp_file));
+ TypeParam cst = std::move(cst_load);
+ sdsl::int_vector<> lcp;
+ sdsl::load_from_file(lcp, test_case_file_map[sdsl::conf::KEY_LCP]);
+ size_type n = lcp.size();
+ ASSERT_EQ(n, cst.lcp.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(lcp[j], cst.lcp[j])<<" j="<<j;
+ }
+}
+
+//! Test the id and inverse id method
+TYPED_TEST(CstByteTest, IdMethod)
+{
+ TypeParam cst;
+ // test empty iterator
+ ASSERT_EQ(cst.begin(), cst.end());
+
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ // doing a depth first traversal through the tree to count the nodes
+ typedef typename TypeParam::const_iterator const_iterator;
+ typedef typename TypeParam::node_type node_type;
+ size_type node_count=0;
+ for (const_iterator it = cst.begin(), end = cst.end(); it != end; ++it) {
+ if (it.visit() == 1) {
+ ++node_count;
+ }
+ }
+ // counted nodes should be equal to nodes
+ ASSERT_EQ(node_count, cst.nodes());
+ // check if the id method is working
+ bit_vector marked(cst.nodes(), 0);
+ for (const_iterator it = cst.begin(), end = cst.end(); it != end; ++it) {
+ if (it.visit() == 1) {
+ ++node_count;
+ node_type v = *it;
+ size_type id = cst.id(v);
+ ASSERT_EQ(0, marked[id]);
+ marked[id] = 1;
+ ASSERT_EQ(v, cst.inv_id(cst.id(v)));
+ }
+ }
+}
+
+TYPED_TEST(CstByteTest, SelectChild)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ if (cst.size() > 1) {
+ ASSERT_EQ(cst.csa.sigma, cst.degree(cst.root()));
+ size_type lb = 0;
+ for (size_type i=1; i <= cst.csa.sigma; ++i) {
+ auto v = cst.select_child(cst.root(), i);
+ ASSERT_EQ(lb, cst.lb(v));
+ lb = cst.rb(v)+1;
+ }
+ ASSERT_EQ(cst.rb(cst.root()), lb-1);
+
+ size_type i=1;
+ for (auto v : cst.children(cst.root())) {
+ ASSERT_TRUE(i <= cst.degree(cst.root()));
+ ASSERT_EQ(cst.select_child(cst.root(),i), v) << i << "!";
+ ++i;
+ }
+ } else if (cst.size() == 1) {
+ ASSERT_EQ(1U, cst.csa.sigma);
+ ASSERT_EQ(0U, cst.degree(cst.root()));
+ }
+}
+
+TYPED_TEST(CstByteTest, MoveSelectChild)
+{
+ TypeParam cst_load;
+ ASSERT_TRUE(load_from_file(cst_load, temp_file));
+ TypeParam cst = std::move(cst_load);
+ if (cst.size() > 1) {
+ ASSERT_EQ(cst.csa.sigma, cst.degree(cst.root()));
+ size_type lb = 0;
+ for (size_type i=1; i <= cst.csa.sigma; ++i) {
+ auto v = cst.select_child(cst.root(), i);
+ ASSERT_EQ(lb, cst.lb(v));
+ lb = cst.rb(v)+1;
+ }
+ ASSERT_EQ(cst.rb(cst.root()), lb-1);
+
+ size_type i=1;
+ for (auto v : cst.children(cst.root())) {
+ ASSERT_TRUE(i <= cst.degree(cst.root()));
+ ASSERT_EQ(cst.select_child(cst.root(),i), v) << i << "!";
+ ++i;
+ }
+ } else if (cst.size() == 1) {
+ ASSERT_EQ(1U, cst.csa.sigma);
+ ASSERT_EQ(0U, cst.degree(cst.root()));
+ }
+}
+
+
+
+TYPED_TEST(CstByteTest, SelectLeafAndSn)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ for (size_type i=0; i < std::min(cst.csa.size(), (size_type)100); ++i) {
+ ASSERT_EQ(cst.csa[i], cst.sn(cst.select_leaf(i+1)));
+ }
+}
+
+
+TYPED_TEST(CstByteTest, NodeDepth)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ auto v = cst.root();
+ ASSERT_EQ((size_type)0, cst.node_depth(v));
+ for (size_type i=1; i<=10 and !cst.is_leaf(v); ++i) {
+ v = cst.select_child(v, 2);
+ ASSERT_EQ(i, cst.node_depth(v));
+ }
+}
+
+
+TYPED_TEST(CstByteTest, Child)
+{
+ TypeParam cst;
+ typedef typename TypeParam::char_type char_type;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ if (cst.size() > 1) {
+ std::set<char_type> char_set;
+ ASSERT_EQ(cst.csa.sigma, cst.degree(cst.root()));
+ for (size_type i=0; i < cst.csa.sigma; ++i) {
+ auto c = cst.csa.comp2char[i];
+ char_set.insert(c);
+ auto v = cst.select_child(cst.root(), i+1);
+ auto w = cst.child(cst.root(), c);
+ ASSERT_EQ(v, w);
+ if (cst.is_leaf(v)) {
+ ASSERT_EQ(cst.root(), cst.select_child(v, c));
+ }
+ }
+ for (size_type i=0; i < 256; ++i) {
+ char_type c = (char_type)i;
+ if (char_set.find(c) == char_set.end()) {
+ ASSERT_EQ(cst.root(), cst.child(cst.root(), c));
+ }
+ }
+ }
+}
+
+TYPED_TEST(CstByteTest, Edge)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+
+ int_vector<8> data;
+ ASSERT_TRUE(load_vector_from_file(data, test_file, 1));
+
+ if (cst.csa.size() > 0) {
+ auto v = cst.select_leaf(cst.csa.isa[0]+1);
+ size_type max_depth = std::min(cst.depth(v), (size_type)20);
+ for (size_type i=0; i<max_depth; ++i) {
+ ASSERT_EQ(data[i], cst.edge(v, i+1))<<" i="<<i<<" v="<<v;
+ }
+ v = cst.parent(v);
+ max_depth = std::min(max_depth, cst.depth(v));
+ for (size_type i=0; i<max_depth; ++i) {
+ ASSERT_EQ(data[i], cst.edge(v, i+1))<<" i="<<i<<" v="<<v;
+ }
+ }
+}
+
+TYPED_TEST(CstByteTest, LeftmostRightmostLeaf)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ if (cst.size() > 0) {
+ auto v = cst.select_leaf(cst.size()/2+1);
+ while (true) {
+ auto v_l = cst.leftmost_leaf(v);
+ auto v_r = cst.rightmost_leaf(v);
+ ASSERT_TRUE(cst.is_leaf(v_l));
+ ASSERT_TRUE(cst.is_leaf(v_r));
+ ASSERT_EQ(cst.lb(v), cst.lb(v_l));
+ ASSERT_EQ(cst.rb(v), cst.rb(v_r));
+ if (v == cst.root())
+ break;
+ v = cst.parent(v);
+ }
+ }
+}
+
+TYPED_TEST(CstByteTest, SuffixAndWeinerLink)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ ASSERT_EQ(cst.root(),cst.sl(cst.root()));
+
+ if (cst.size() > 0) {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, cst.size()-1);
+ auto dice = bind(distribution, rng);
+
+ for (size_type i=0; i<100; ++i) {
+ auto v = cst.select_leaf(dice()+1);
+ auto c = cst.edge(v, 1);
+ ASSERT_EQ(v, cst.wl(cst.sl(v), c));
+ for (size_type j=0; j<5; ++j) {
+ v = cst.parent(v);
+ if (cst.root() == v)
+ break;
+ c = cst.edge(v, 1);
+ ASSERT_EQ(v, cst.wl(cst.sl(v), c));
+ }
+ }
+ }
+}
+
+TYPED_TEST(CstByteTest, LcaMethod)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ uint64_t mask;
+ uint8_t log_m = 6;
+ // create m/2 pairs of positions in [0..cst.csa.size()-1]
+ typedef typename TypeParam::node_type node_type;
+ int_vector<64> rnd_pos = util::rnd_positions<int_vector<64>>(log_m, mask, cst.csa.size());
+ // test for random sampled nodes
+ for (size_type i=0; i < rnd_pos.size()/2; ++i) {
+ // get two children
+ node_type v = cst.select_leaf(rnd_pos[2*i]+1);
+ node_type w = cst.select_leaf(rnd_pos[2*i+1]+1);
+ // calculate lca
+ node_type z = naive_lca(cst, v, w);
+ ASSERT_EQ(z, cst.lca(v, w));
+ }
+ // test for regular sampled nodes
+ size_type g = std::max(cst.csa.size()/30, (size_type)5);
+ for (size_type i=cst.csa.size()/2; i+g < cst.csa.size(); ++i) {
+ // get two children
+ node_type v = cst.select_leaf(i+1);
+ node_type w = cst.select_leaf(i+g+1);
+ // calculate lca
+ node_type z = naive_lca(cst, v, w);
+ node_type u = cst.lca(v, w);
+ ASSERT_EQ(z, u) << " naive_lca is "
+ << naive_lca(cst, v, w, true) << endl;
+ }
+}
+
+//! Test the bottom-up iterator
+TYPED_TEST(CstByteTest, BottomUpIterator)
+{
+// TypeParam cst;
+// ASSERT_TRUE(load_from_file(cst, temp_file));
+// doing a bottom-up traversal of the tree
+// TODO: implement
+}
+
+TYPED_TEST(CstByteTest, DeleteTest)
+{
+ sdsl::remove(temp_file);
+ util::delete_all_files(test_case_file_map);
+}
+
+}// end namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 4) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file temp_file tmp_dir [in-memory]" << endl;
+ cout << " (1) Generates a CST out of test_file; stores it in temp_file." << endl;
+ cout << " Temporary files (SA/BWT/LCP/TEXT) are stored in tmp_dir." << endl;
+ cout << " If `in-memory` is specified, the in-memory construction is tested." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_file = argv[2];
+ temp_dir = argv[3];
+ in_memory = argc > 4;
+ if (in_memory) {
+ temp_dir = "@";
+ int_vector<8> data;
+ load_vector_from_file(data, test_file, 1);
+ test_file = ram_file_name(test_file);
+ store_to_plain_array<uint8_t>(data, test_file);
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
+
diff --git a/test/CstHelper.hpp b/test/CstHelper.hpp
new file mode 100644
index 0000000..eda5b71
--- /dev/null
+++ b/test/CstHelper.hpp
@@ -0,0 +1,55 @@
+#ifndef SDSL_TEST_CST_HELPER
+#define SDSL_TEST_CST_HELPER
+
+#include <sstream>
+#include <iostream>
+#include "gtest/gtest.h"
+
+template<class Cst>
+std::string format_node(const Cst& cst, const typename Cst::node_type& v)
+{
+ std::stringstream ss;
+ ss << cst.depth(v) << "-["<<cst.lb(v)<<","<<cst.rb(v)<<"]";
+ return ss.str();
+}
+
+template<class tCst>
+void check_node_method(const tCst& cst)
+{
+ typedef typename tCst::const_iterator const_iterator;
+ typedef typename tCst::node_type node_type;
+ typedef typename tCst::size_type size_type;
+ for (const_iterator it = cst.begin(), end = cst.end(); it != end; ++it) {
+ if (it.visit() == 1) {
+ node_type v = *it;
+ size_type lb = cst.lb(v), rb = cst.rb(v);
+ ASSERT_EQ(v, cst.node(lb, rb));
+ }
+ }
+}
+
+template<class Cst>
+typename Cst::node_type naive_lca(const Cst& cst, typename Cst::node_type v, typename Cst::node_type w, bool output=false)
+{
+ typedef typename Cst::size_type size_type;
+ size_type steps = 0;
+ while (v != w and steps < cst.csa.size()) {
+ if (cst.depth(v) > cst.depth(w)) {
+ v = cst.parent(v);
+ if (output) {
+ std::cout << "v="<<format_node(cst, v) << std::endl;
+ }
+ } else {
+ w = cst.parent(w);
+ if (output) {
+ std::cout << "w="<<format_node(cst, v) << std::endl;
+ }
+ }
+ steps++;
+ }
+ return v;
+}
+
+
+
+#endif
diff --git a/test/CstIntTest.config b/test/CstIntTest.config
new file mode 100644
index 0000000..7a5b581
--- /dev/null
+++ b/test/CstIntTest.config
@@ -0,0 +1,10 @@
+# Texts which should be used in the CstIntTest.
+# Each line contains [TC_ID];[TC_PATH];[TC_NAME];[NUM_BYTE]
+TXT-EMPTY;test_cases/empty.txt;empty;1
+TXT-EXAMPE01;test_cases/example01.txt;example01;1
+TXT-100A;test_cases/100a.txt;100a;1
+TXT-FAUST;test_cases/faust.txt;faust-de;1
+#TXT-ZARATHUSTRA;test_cases/zarathustra.txt;zarathustra-de;1
+INT-KEEPER;test_cases/keeper.int;keeper.int;8
+INT-MOBY;test_cases/moby.int;moby.int;8
+INT-100000-18-R;test_cases/int-vec-sa.100000.18.r;int-100000-18-r;0
diff --git a/test/CstIntTest.cpp b/test/CstIntTest.cpp
new file mode 100644
index 0000000..7ce3694
--- /dev/null
+++ b/test/CstIntTest.cpp
@@ -0,0 +1,484 @@
+#include "sdsl/suffix_trees.hpp"
+#include "sdsl/lcp.hpp"
+#include "CstHelper.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <cstdlib> // for rand()
+#include <string>
+#include <random>
+
+using namespace sdsl;
+using namespace std;
+
+using namespace std::chrono;
+using timer = std::chrono::high_resolution_clock;
+
+namespace
+{
+
+typedef int_vector<>::size_type size_type;
+tMSS test_case_file_map;
+string test_file;
+uint8_t num_bytes;
+string temp_file;
+string temp_dir;
+bool in_memory;
+
+
+
+template<class T>
+class CstIntTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef csa_wt<wt_int<>, 32, 32, text_order_sa_sampling<>, int_vector<>, int_alphabet<> > tCSA1;
+typedef csa_sada<enc_vector<>, 32, 32, text_order_sa_sampling<>, int_vector<>, int_alphabet<> > tCSA2;
+typedef csa_bitcompressed<int_alphabet<> > tCSA3;
+
+typedef Types<
+cst_sct3<tCSA1, lcp_bitcompressed<> >,
+ cst_sct3<tCSA2, lcp_bitcompressed<> >,
+ cst_sct3<tCSA3, lcp_bitcompressed<> >,
+ cst_sada<tCSA1, lcp_dac<> >,
+ cst_sada<tCSA1, lcp_vlc<> >,
+ cst_sada<tCSA1, lcp_byte<> >,
+ cst_sada<tCSA1, lcp_support_tree2<>, bp_support_gg<> >,
+ cst_sct3<tCSA3, lcp_support_tree2<> >,
+ cst_sada<tCSA1, lcp_support_tree<> >,
+ cst_sct3<tCSA1, lcp_support_tree<>, bp_support_gg<> >,
+ cst_sct3<tCSA1, lcp_support_tree<>, bp_support_g<> >,
+ cst_sada<tCSA3, lcp_dac<> >,
+ cst_sct3<tCSA1, lcp_support_sada<> >,
+ cst_sct3<tCSA1, lcp_wt<> >
+ > Implementations;
+
+TYPED_TEST_CASE(CstIntTest, Implementations);
+
+
+TYPED_TEST(CstIntTest, CreateAndStoreTest)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ TypeParam cst;
+ cache_config config(false, temp_dir, util::basename(test_file));
+ construct(cst, test_file, config, num_bytes);
+ test_case_file_map = config.file_map;
+ ASSERT_TRUE(store_to_file(cst, temp_file));
+ TypeParam cst2;
+ cst2 = cst;
+ ASSERT_EQ(cst.size(), cst2.size());
+ ASSERT_TRUE(cst.size() <= TypeParam::max_size());
+}
+
+//! Test the swap method
+TYPED_TEST(CstIntTest, SwapMethod)
+{
+ TypeParam cst1;
+ ASSERT_TRUE(load_from_file(cst1, temp_file));
+ size_type n = cst1.size();
+ TypeParam cst2;
+ ASSERT_EQ((size_type)0, cst2.size());
+ cst1.swap(cst2);
+ ASSERT_EQ((size_type)0, cst1.size());
+ ASSERT_EQ(n, cst2.size());
+ ASSERT_EQ(n, cst2.csa.size());
+ bit_vector mark((size_type)0, cst2.size());
+ check_node_method(cst2);
+}
+
+//! Test the move method
+TYPED_TEST(CstIntTest, MoveMethod)
+{
+ TypeParam cst1;
+ ASSERT_TRUE(load_from_file(cst1, temp_file));
+ size_type n = cst1.size();
+ TypeParam cst2;
+ ASSERT_EQ((size_type)0, cst2.size());
+ cst2 = std::move(cst1);
+ ASSERT_EQ(n, cst2.size());
+ ASSERT_EQ(n, cst2.csa.size());
+ bit_vector mark((size_type)0, cst2.size());
+ check_node_method(cst2);
+}
+
+//! Test the node method
+TYPED_TEST(CstIntTest, NodeMethod)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ // doing a depth first traversal through the tree to count the nodes
+ check_node_method(cst);
+}
+
+//! Test basic methods
+TYPED_TEST(CstIntTest, BasicMethods)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ typedef typename TypeParam::node_type node_type;
+ node_type r = cst.root(); // get root node
+ // Size of the subtree rooted at r should the size of the suffix array
+ ASSERT_EQ(cst.csa.size(), cst.size(r));
+ // Check leaf methods
+ for (size_type i=0; i < cst.csa.size(); ++i) {
+ ASSERT_TRUE(cst.is_leaf(cst.select_leaf(i+1)));
+ }
+}
+
+//! Test suffix array access
+TYPED_TEST(CstIntTest, SaAccess)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ sdsl::int_vector<> sa;
+ sdsl::load_from_file(sa, test_case_file_map[sdsl::conf::KEY_SA]);
+ size_type n = sa.size();
+ ASSERT_EQ(n, cst.csa.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(sa[j], cst.csa[j])<<" j="<<j;
+ }
+}
+
+//! Test BWT access
+TYPED_TEST(CstIntTest, BwtAccess)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ sdsl::int_vector<> bwt;
+ sdsl::load_from_file(bwt, test_case_file_map[sdsl::conf::KEY_BWT_INT]);
+ size_type n = bwt.size();
+ ASSERT_EQ(n, cst.csa.bwt.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(bwt[j], cst.csa.bwt[j])<<" j="<<j;
+ }
+}
+
+//! Test BWT access
+TYPED_TEST(CstIntTest, MoveAndBwtAccess)
+{
+ TypeParam cst_load;
+ ASSERT_TRUE(load_from_file(cst_load, temp_file));
+ TypeParam cst = std::move(cst_load);
+ sdsl::int_vector<> bwt;
+ sdsl::load_from_file(bwt, test_case_file_map[sdsl::conf::KEY_BWT_INT]);
+ size_type n = bwt.size();
+ ASSERT_EQ(n, cst.csa.bwt.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(bwt[j], cst.csa.bwt[j])<<" j="<<j;
+ }
+}
+
+//! Test LCP access
+TYPED_TEST(CstIntTest, LcpAccess)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ sdsl::int_vector<> lcp;
+ sdsl::load_from_file(lcp, test_case_file_map[sdsl::conf::KEY_LCP]);
+ size_type n = lcp.size();
+ ASSERT_EQ(n, cst.lcp.size());
+ for (size_type j=0; j<n; ++j) {
+ ASSERT_EQ(lcp[j], cst.lcp[j])<<" j="<<j;
+ }
+}
+
+//! Test the id and inverse id method
+TYPED_TEST(CstIntTest, IdMethod)
+{
+ TypeParam cst;
+ // test empty iterator
+ ASSERT_EQ(cst.begin(), cst.end());
+
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ // doing a depth first traversal through the tree to count the nodes
+ typedef typename TypeParam::const_iterator const_iterator;
+ typedef typename TypeParam::node_type node_type;
+ size_type node_count=0;
+ for (const_iterator it = cst.begin(), end = cst.end(); it != end; ++it) {
+ if (it.visit() == 1) {
+ ++node_count;
+ }
+ }
+ // counted nodes should be equal to nodes
+ ASSERT_EQ(node_count, cst.nodes());
+ // check if the id method is working
+ bit_vector marked(cst.nodes(), 0);
+ for (const_iterator it = cst.begin(), end = cst.end(); it != end; ++it) {
+ if (it.visit() == 1) {
+ ++node_count;
+ node_type v = *it;
+ size_type id = cst.id(v);
+ ASSERT_EQ(0, marked[id]);
+ marked[id] = 1;
+ ASSERT_EQ(v, cst.inv_id(cst.id(v)));
+ }
+ }
+}
+
+template<class t_cst>
+size_type naive_degree(const t_cst& cst, const typename t_cst::node_type& v)
+{
+ if (cst.is_leaf(v)) {
+ return 0;
+ } else {
+ size_type res = 0;
+ auto w = cst.select_child(v, 1);
+ while (cst.root() != w) {
+ ++res;
+ w = cst.sibling(w);
+ }
+ return res;
+ }
+}
+
+template<class T>
+bool my_timeout(const timer::time_point& tp, T limit)
+{
+ return duration_cast<seconds>(timer::now()- tp).count() > limit;
+}
+
+TYPED_TEST(CstIntTest, DegreeAndSelectChild)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ if (cst.size() > 1) {
+ size_type degree = naive_degree(cst, cst.root());
+ ASSERT_EQ(degree, cst.degree(cst.root()));
+ ASSERT_EQ(cst.csa.sigma, cst.degree(cst.root()));
+ size_type lb = 0;
+ auto start = timer::now();
+ for (size_type i=1; i <= cst.csa.sigma; ++i) {
+ auto v = cst.select_child(cst.root(), i);
+ ASSERT_EQ(lb, cst.lb(v));
+ lb = cst.rb(v)+1;
+ if (my_timeout(start, 5)) { break; }
+ }
+ if (!my_timeout(start, 5)) {
+ ASSERT_EQ(cst.rb(cst.root()), lb-1);
+ }
+
+ start = timer::now();
+ size_type i=1;
+ for (auto v : cst.children(cst.root())) {
+ ASSERT_TRUE(i <= cst.degree(cst.root()));
+ ASSERT_EQ(cst.select_child(cst.root(),i), v) << i << "!";
+ ++i;
+ if (my_timeout(start, 5)) { break; }
+ }
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> dist(0, cst.csa.sigma);
+ auto dice = bind(dist, rng);
+ start = timer::now();
+ for (size_type i=1; i < 10; ++i) {
+ auto w = cst.root();
+ while (!cst.is_leaf(w)) {
+ degree = naive_degree(cst, w);
+ ASSERT_EQ(degree, cst.degree(w));
+ w = cst.select_child(w, (dice()%degree)+1);
+ if (my_timeout(start, 5)) { break; }
+ }
+ }
+ } else if (cst.size() == 1) {
+ ASSERT_EQ(1U, cst.csa.sigma);
+ ASSERT_EQ(0U, cst.degree(cst.root()));
+ }
+}
+
+TYPED_TEST(CstIntTest, SelectLeafAndSn)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ for (size_type i=0; i < std::min(cst.csa.size(), (size_type)100); ++i) {
+ ASSERT_EQ(cst.csa[i], cst.sn(cst.select_leaf(i+1)));
+ }
+}
+
+TYPED_TEST(CstIntTest, NodeDepth)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ auto v = cst.root();
+ ASSERT_EQ((size_type)0, cst.node_depth(v));
+ for (size_type i=1; i<=10 and !cst.is_leaf(v); ++i) {
+ v = cst.select_child(v, 2);
+ ASSERT_EQ(i, cst.node_depth(v));
+ }
+}
+
+TYPED_TEST(CstIntTest, Child)
+{
+ TypeParam cst;
+ typedef typename TypeParam::char_type char_type;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ if (cst.size() > 1) {
+ std::set<char_type> char_set;
+ ASSERT_EQ(cst.csa.sigma, cst.degree(cst.root()));
+ bool leaf_tested = false;
+ for (size_type i=0; i < cst.csa.sigma and i < 1024U; ++i) {
+ auto c = cst.csa.comp2char[i];
+ char_set.insert(c);
+ auto v = cst.select_child(cst.root(), i+1);
+ auto w = cst.child(cst.root(), c);
+ ASSERT_EQ(v, w);
+ if (!leaf_tested and cst.is_leaf(v)) {
+ ASSERT_EQ(cst.root(), cst.select_child(v, c));
+ }
+ }
+ }
+}
+
+TYPED_TEST(CstIntTest, Edge)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+
+ int_vector<> data;
+ ASSERT_TRUE(load_vector_from_file(data, test_file, num_bytes));
+
+ if (cst.csa.size() > 0) {
+ auto v = cst.select_leaf(cst.csa.isa[0]+1);
+ size_type max_depth = std::min(cst.depth(v), (size_type)20);
+ for (size_type i=0; i<max_depth; ++i) {
+ ASSERT_EQ(data[i], cst.edge(v, i+1))<<" i="<<i<<" v="<<v;
+ }
+ v = cst.parent(v);
+ max_depth = std::min(max_depth, cst.depth(v));
+ for (size_type i=0; i<max_depth; ++i) {
+ ASSERT_EQ(data[i], cst.edge(v, i+1))<<" i="<<i<<" v="<<v;
+ }
+ }
+}
+
+TYPED_TEST(CstIntTest, LeftmostRightmostLeaf)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ if (cst.size() > 0) {
+ auto v = cst.select_leaf(cst.size()/2+1);
+ while (true) {
+ auto v_l = cst.leftmost_leaf(v);
+ auto v_r = cst.rightmost_leaf(v);
+ ASSERT_TRUE(cst.is_leaf(v_l));
+ ASSERT_TRUE(cst.is_leaf(v_r));
+ ASSERT_EQ(cst.lb(v), cst.lb(v_l));
+ ASSERT_EQ(cst.rb(v), cst.rb(v_r));
+ if (v == cst.root())
+ break;
+ v = cst.parent(v);
+ }
+ }
+}
+
+TYPED_TEST(CstIntTest, SuffixAndWeinerLink)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ ASSERT_EQ(cst.root(),cst.sl(cst.root()));
+
+ if (cst.size() > 0) {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, cst.size()-1);
+ auto dice = bind(distribution, rng);
+
+ for (size_type i=0; i<100; ++i) {
+ auto v = cst.select_leaf(dice()+1);
+ auto c = cst.edge(v, 1);
+ ASSERT_EQ(v, cst.wl(cst.sl(v), c));
+ for (size_type j=0; j<5; ++j) {
+ v = cst.parent(v);
+ if (cst.root() == v)
+ break;
+ c = cst.edge(v, 1);
+ ASSERT_EQ(v, cst.wl(cst.sl(v), c));
+ }
+ }
+ }
+}
+
+
+
+TYPED_TEST(CstIntTest, LcaMethod)
+{
+ TypeParam cst;
+ ASSERT_TRUE(load_from_file(cst, temp_file));
+ uint64_t mask;
+ uint8_t log_m = 6;
+ // create m/2 pairs of positions in [0..cst.csa.size()-1]
+ typedef typename TypeParam::node_type node_type;
+ int_vector<64> rnd_pos = util::rnd_positions<int_vector<64>>(log_m, mask, cst.csa.size());
+ // test for random sampled nodes
+ for (size_type i=0; i < rnd_pos.size()/2; ++i) {
+ // get two children
+ node_type v = cst.select_leaf(rnd_pos[2*i]+1);
+ node_type w = cst.select_leaf(rnd_pos[2*i+1]+1);
+ // calculate lca
+ node_type z = naive_lca(cst, v, w);
+ ASSERT_EQ(z, cst.lca(v, w));
+ }
+ // test for regular sampled nodes
+ size_type g = std::max(cst.csa.size()/30, (size_type)5);
+ for (size_type i=cst.csa.size()/2; i+g < cst.csa.size(); ++i) {
+ // get two children
+ node_type v = cst.select_leaf(i+1);
+ node_type w = cst.select_leaf(i+g+1);
+ // calculate lca
+ node_type z = naive_lca(cst, v, w);
+ node_type u = cst.lca(v, w);
+ ASSERT_EQ(z, u) << " naive_lca is "
+ << naive_lca(cst, v, w, true) << endl;
+ }
+}
+
+//! Test the bottom-up iterator
+TYPED_TEST(CstIntTest, BottomUpIterator)
+{
+// TypeParam cst;
+// ASSERT_TRUE(load_from_file(cst, temp_file));
+// doing a bottom-up traversal of the tree
+// TODO: implement
+}
+
+TYPED_TEST(CstIntTest, DeleteTest)
+{
+ TypeParam cst;
+ sdsl::remove(temp_file);
+ util::delete_all_files(test_case_file_map);
+}
+
+}// end namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 4) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file num_bytes temp_file tmp_dir" << endl;
+ cout << " (1) Generates a CST out of test_file; stores it in temp_file." << endl;
+ cout << " Temporary files (SA/BWT/TEXT/LCP) are stored in tmp_dir." << endl;
+ cout << " num_bytes specifies who many bytes make a symbol in the"<< endl;
+ cout << " input sequence" << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ num_bytes = atoi(argv[2]);
+ temp_file = argv[3];
+ temp_dir = argv[4];
+ in_memory = argc > 5;
+ if (in_memory) {
+ temp_dir = "@";
+ int_vector<> data;
+ load_vector_from_file(data, test_file, num_bytes);
+ test_file = ram_file_name(test_file);
+ switch (num_bytes) {
+ case 0: store_to_file(data, test_file); break;
+ case 1: store_to_plain_array<uint8_t>(data, test_file); break;
+ case 2: store_to_plain_array<uint16_t>(data, test_file); break;
+ case 3: store_to_plain_array<uint32_t>(data, test_file); break;
+ case 4: store_to_plain_array<uint64_t>(data, test_file); break;
+ }
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/test/IntVectorBufferTest.cpp b/test/IntVectorBufferTest.cpp
new file mode 100644
index 0000000..5238603
--- /dev/null
+++ b/test/IntVectorBufferTest.cpp
@@ -0,0 +1,694 @@
+#include "sdsl/int_vector.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <fstream>
+#include <iostream>
+
+namespace
+{
+
+typedef sdsl::int_vector<>::size_type size_type;
+typedef sdsl::int_vector<>::value_type value_type;
+
+// The fixture for testing class int_vector.
+class IntVectorBufferTest : public ::testing::Test
+{
+ protected:
+
+ IntVectorBufferTest() {}
+
+ virtual ~IntVectorBufferTest() {}
+
+ virtual void SetUp() {
+ std::mt19937_64 rng;
+ {
+ std::uniform_int_distribution<uint64_t> distribution(0, 100000);
+ auto dice = bind(distribution, rng);
+ for (size_type i=0; i<128; ++i) {
+ vec_sizes.push_back(dice());
+ }
+ }
+ {
+ std::uniform_int_distribution<uint64_t> distribution(0, 10000000);
+ auto dice = bind(distribution, rng);
+ for (size_type i=0; i < 10; ++i) {
+ vec_sizes.push_back(dice());
+ }
+ }
+ }
+
+ virtual void TearDown() {}
+
+ std::vector<size_type> vec_sizes = {0, 64, 65, 127, 128}; // different sizes for the vectors
+};
+
+
+template<class t_T>
+void test_constructors(size_type template_width, size_type constructor_width, size_type exp_width)
+{
+ static_assert(std::is_default_constructible<t_T>::value, "Type is not default constructible");
+ static_assert(std::is_move_constructible<t_T>::value, "Type is not move constructible");
+ static_assert(std::is_move_assignable<t_T>::value, "Type is not move assignable");
+ std::string file_name = "tmp/int_vector_buffer";
+ {
+ // Default constructor
+ t_T ivb;
+ ASSERT_FALSE(ivb.is_open()); // int_vector_buffer is not ready for IO since no filename was given
+ ASSERT_EQ("", ivb.filename()); // filename should be empty
+ ASSERT_EQ((size_type)0, ivb.size()); // size should be 0
+ ASSERT_EQ((uint8_t)template_width, ivb.width()); // default width of each element should be template_width bits
+ }
+ {
+ // Constructor with 2 Parameters
+ t_T ivb(file_name, std::ios::out);
+ ASSERT_TRUE(ivb.is_open()); // int_vector_buffer should be open
+ ASSERT_EQ(file_name, ivb.filename()); // filename should be file_name
+ ASSERT_EQ((size_type)0, ivb.size()); // size should be 0
+ ASSERT_EQ((uint8_t)template_width, ivb.width()); // default width of each element should be template_width bits
+ ivb.close(true);
+ }
+ {
+ // Constructor with 4 Parameters
+ size_type buffersize = 1024*1024;
+ t_T ivb(file_name, std::ios::out, buffersize, constructor_width);
+ ASSERT_TRUE(ivb.is_open()); // int_vector_buffer should be open
+ ASSERT_EQ(file_name, ivb.filename()); // filename should be file_name
+ ASSERT_EQ((size_type)0, ivb.size()); // size should be 0
+ ASSERT_EQ((uint8_t)exp_width, ivb.width()); // default width of each element should be i bits
+ ivb.close(true);
+ }
+}
+
+//! Test constructors
+TEST_F(IntVectorBufferTest, Constructors)
+{
+ for (size_type width=1; width<=64; ++width) {
+ test_constructors< sdsl::int_vector_buffer<> >(64, width, width);
+ test_constructors< sdsl::int_vector_buffer<1> >(1, width, 1);
+ test_constructors< sdsl::int_vector_buffer<8> >(8, width, 8);
+ test_constructors< sdsl::int_vector_buffer<13> >(13, width, 13);
+ test_constructors< sdsl::int_vector_buffer<16> >(16, width, 16);
+ test_constructors< sdsl::int_vector_buffer<32> >(32, width, 32);
+ test_constructors< sdsl::int_vector_buffer<64> >(64, width, 64);
+ }
+}
+
+
+template<class t_T>
+void test_assign_and_modify(size_type width=1)
+{
+ std::mt19937_64 rng(13), rng2;
+ std::string file_name = "tmp/int_vector_buffer";
+ size_type buffersize = 1024;
+ t_T ivb(file_name, std::ios::out, buffersize, width);
+ for (size_type i=0; i < 100000; ++i) {
+ value_type exp_v = rng();
+ ivb[i] = exp_v;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Assign Operator failed";
+ }
+ rng.seed(13); // To get the same values
+ for (size_type i=0; i < 100000; ++i) {
+ value_type exp_v = rng(), tmp = rng2();
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Assign Operator failed";
+ ivb[i] += tmp;
+ exp_v += tmp;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Add Assign Operator failed";
+ ivb[i] -= tmp;
+ exp_v -= tmp;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Subtract Assign Operator failed";
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]++) << "Postfix Increment Operator failed";
+ exp_v++;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Postfix Increment Operator failed";
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]--) << "Postfix Decrement Operator failed";
+ exp_v--;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Postfix Decrement Operator failed";
+ ++exp_v;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)++ivb[i]) << "Prefix Increment Operator failed";
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Prefix Increment Operator failed";
+ --exp_v;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)--ivb[i]) << "Prefix Decrement Operator failed";
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]) << "Prefix Decrement Operator failed";
+ }
+ ivb.close(true);
+}
+
+template<>
+void test_assign_and_modify<sdsl::int_vector_buffer<1>>(size_type width)
+{
+ std::mt19937_64 rng(13);
+ std::uniform_int_distribution<uint64_t> distribution(0, 9);
+
+ std::string file_name = "tmp/int_vector_buffer";
+ size_type buffersize = 1024;
+ sdsl::int_vector_buffer<1> ivb(file_name, std::ios::out, buffersize, width);
+ for (size_type i=0; i < 100000; ++i) {
+ value_type exp_v = distribution(rng);
+ ivb[i] = exp_v;
+ ASSERT_EQ((bool)exp_v, (size_type)ivb[i]);
+ }
+ rng.seed(13); // To get the same values
+ for (size_type i=0; i < 100000; ++i) {
+ value_type exp_v = distribution(rng);
+ ASSERT_EQ((bool)exp_v, (size_type)ivb[i]);
+ }
+ ivb.close(true);
+}
+
+TEST_F(IntVectorBufferTest, AssignAndModifyElement)
+{
+ for (size_type width=1; width<=64; ++width) { // for each possible width
+ test_assign_and_modify< sdsl::int_vector_buffer<> >(width);
+ }
+ test_assign_and_modify< sdsl::int_vector_buffer<1> >();
+ test_assign_and_modify< sdsl::int_vector_buffer<8> >();
+ test_assign_and_modify< sdsl::int_vector_buffer<13> >();
+ test_assign_and_modify< sdsl::int_vector_buffer<16> >();
+ test_assign_and_modify< sdsl::int_vector_buffer<32> >();
+ test_assign_and_modify< sdsl::int_vector_buffer<64> >();
+}
+
+
+template<class t_T>
+void compare(size_type width=1)
+{
+ std::mt19937_64 rng(13);
+ std::string file_name_1 = "tmp/int_vector_buffer_1";
+ std::string file_name_2 = "tmp/int_vector_buffer_2";
+ size_type buffersize = 1024;
+ t_T ivb1(file_name_1, std::ios::out, buffersize, width);
+ t_T ivb2(file_name_2, std::ios::out, buffersize, width);
+ for (size_type i=0; i < 1000; ++i) {
+ ivb1[i] = rng() & sdsl::bits::lo_set[ivb1.width()];
+ ivb2[i] = ivb1[i];
+ ASSERT_TRUE(ivb1[i]==ivb2[i]);
+ ASSERT_FALSE(ivb1[i]!=ivb2[i]);
+ ASSERT_EQ((size_type)ivb1[i], (size_type)ivb2[i]);
+ }
+ for (size_type i=0; i < 1000; ++i) {
+ ivb1[i] = rng() & sdsl::bits::lo_set[ivb1.width()];
+ ivb2[i] = rng() & sdsl::bits::lo_set[ivb1.width()];
+ size_type v1 = ivb1[i];
+ size_type v2 = ivb2[i];
+ ASSERT_EQ((v1!=v2), (ivb1[i]!=ivb2[i]));
+ ASSERT_EQ((v1==v2), (ivb1[i]==ivb2[i]));
+ ASSERT_EQ((v1<=v2), (ivb1[i]<=ivb2[i]));
+ ASSERT_EQ((v1<v2), (ivb1[i]<ivb2[i]));
+ ASSERT_EQ((v1>=v2), (ivb1[i]>=ivb2[i]));
+ ASSERT_EQ((v1>v2), (ivb1[i]>ivb2[i]));
+ }
+ ivb1.close(true);
+ ivb2.close(true);
+}
+
+//! Test assign from int_vector_buffer to int_vector_buffer and compare operators
+TEST_F(IntVectorBufferTest, Compare)
+{
+ for (size_type width=1; width<=64; ++width) { // for each possible width
+ compare< sdsl::int_vector_buffer<> >(width);
+ }
+ compare< sdsl::int_vector_buffer<1> >();
+ compare< sdsl::int_vector_buffer<8> >();
+ compare< sdsl::int_vector_buffer<13> >();
+ compare< sdsl::int_vector_buffer<16> >();
+ compare< sdsl::int_vector_buffer<32> >();
+ compare< sdsl::int_vector_buffer<64> >();
+}
+
+
+template<class t_T>
+void test_sequential_access(size_type width=1)
+{
+ std::mt19937_64 rng;
+ std::string file_name = "tmp/int_vector_buffer";
+ size_type buffersize = 1024;
+ size_type size = 100000;
+ // fill ivb with push_back()
+ {
+ rng.seed(13); // To get the same values
+ t_T ivb(file_name, std::ios::out, buffersize, width);
+ for (size_type i=0; i < size; ++i) {
+ value_type x = rng() & sdsl::bits::lo_set[ivb.width()];
+ ivb.push_back(x);
+ ASSERT_EQ(x, (size_type)ivb[i]);
+ }
+ }
+ // verify values
+ {
+ rng.seed(13); // To get the same values
+ t_T ivb(file_name, std::ios::in, buffersize, width);
+ ASSERT_EQ(size, ivb.size());
+ for (size_type i=0; i < ivb.size(); ++i) {
+ value_type x = rng() & sdsl::bits::lo_set[ivb.width()];
+ ASSERT_EQ(x, (size_type)ivb[i]);
+ }
+ }
+ // iterate over ivb, verify and change values
+ {
+ rng.seed(13); // To get the same values
+ t_T ivb(file_name, std::ios::in, buffersize, width);
+ for (typename t_T::iterator it = ivb.begin(); it != ivb.end(); ++it) {
+ value_type x = rng() & sdsl::bits::lo_set[ivb.width()];
+ ASSERT_EQ(x, (size_type)*it);
+ *it = (x+1) & sdsl::bits::lo_set[ivb.width()];
+ }
+ }
+ // iterator test
+ {
+ t_T ivb(file_name, std::ios::in, buffersize, width);
+ typename t_T::iterator it = ivb.begin();
+ ASSERT_EQ(ivb[0], *it++);
+ ASSERT_EQ(ivb[1], *it);
+ it += 1;
+ ASSERT_EQ(ivb[2], *it);
+ it -= 1;
+ ASSERT_EQ(ivb[1], *it);
+ it -= -1;
+ ASSERT_EQ(ivb[2], *it);
+ it += -1;
+ ASSERT_EQ(ivb[1], *it);
+ ASSERT_EQ(ivb[2], *(++it));
+ typename t_T::iterator it2 = ivb.end();
+ --it2;
+ ASSERT_EQ(ivb[ivb.size()-1], *it2--);
+ ASSERT_EQ(ivb[ivb.size()-2], *it2);
+ ASSERT_EQ(ivb[ivb.size()-3], *(--it2));
+ }
+
+ // verify changed values
+ {
+ rng.seed(13); // To get the same values
+ t_T ivb(file_name, std::ios::in, buffersize, width);
+ ASSERT_EQ(size, ivb.size());
+ for (size_type i=0; i < ivb.size(); ++i) {
+ value_type x = (rng()+1) & sdsl::bits::lo_set[ivb.width()];
+ ASSERT_EQ(x, (size_type)ivb[i]) << "???";
+ }
+ ivb.close(true);
+ }
+}
+
+//! Test SequentialAccess: push_back and iterators
+TEST_F(IntVectorBufferTest, SequentialAccess)
+{
+ for (size_type width=1; width <= 64; ++width) { // for each possible width
+ test_sequential_access< sdsl::int_vector_buffer<> >(width);
+ }
+ test_sequential_access< sdsl::int_vector_buffer<1> >();
+ test_sequential_access< sdsl::int_vector_buffer<8> >();
+ test_sequential_access< sdsl::int_vector_buffer<13> >();
+ test_sequential_access< sdsl::int_vector_buffer<16> >();
+ test_sequential_access< sdsl::int_vector_buffer<32> >();
+ test_sequential_access< sdsl::int_vector_buffer<64> >();
+}
+
+
+template<class t_T>
+void test_random_access(size_type width=1)
+{
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, 999);
+ auto dice = bind(distribution, rng);
+ std::string file_name = "tmp/int_vector_buffer";
+ size_type buffersize = 100;
+ t_T ivb(file_name, std::ios::out, buffersize, width);
+ ASSERT_EQ((size_type)0, ivb.size());
+ ivb[999] = 999 & sdsl::bits::lo_set[ivb.width()];
+ ASSERT_EQ(999 & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[999]);
+ ASSERT_EQ((size_type)1000, ivb.size());
+ for (size_type i=0; i < 999; ++i) {
+ ASSERT_EQ((size_type)0, (size_type)ivb[i]);
+ }
+ // Test random access write
+ for (size_type i=0; i < 1000; ++i) {
+ value_type x = dice();
+ ivb[x] = x & sdsl::bits::lo_set[ivb.width()];
+ }
+ ASSERT_EQ((size_type)1000, ivb.size());
+ for (size_type i=0; i < ivb.size(); ++i) {
+ if (ivb[i]) {
+ ASSERT_EQ(i & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]);
+ }
+ }
+ // Test random access with different buffersize
+ buffersize = 50;
+ ivb.buffersize(buffersize);
+ ASSERT_EQ((size_type)1000, ivb.size());
+ for (size_type i=0; i < 1000; ++i) {
+ value_type x = dice();
+ ivb[x] = x & sdsl::bits::lo_set[ivb.width()];
+ }
+ for (size_type i=0; i < ivb.size(); ++i) {
+ if (ivb[i]) {
+ ASSERT_EQ(i & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[i]);
+ }
+ }
+ // Test random access read
+ for (size_type i=0; i < ivb.size(); ++i) {
+ value_type idx = dice();
+ if (ivb[idx]) {
+ ASSERT_EQ(idx & sdsl::bits::lo_set[ivb.width()], (size_type)ivb[idx]);
+ }
+ }
+ ivb.close(true);
+}
+
+//! Test RandomAcces, which should not be done in practice because it is expected to be very slow
+TEST_F(IntVectorBufferTest, RandomAccess)
+{
+ for (size_type width=1; width <= 64; ++width) {
+ test_random_access< sdsl::int_vector_buffer<> >(width);
+ }
+ test_random_access< sdsl::int_vector_buffer<1> >();
+ test_random_access< sdsl::int_vector_buffer<8> >();
+ test_random_access< sdsl::int_vector_buffer<16> >();
+ test_random_access< sdsl::int_vector_buffer<32> >();
+ test_random_access< sdsl::int_vector_buffer<64> >();
+}
+
+
+template<class t_T, class t_V>
+void test_file_handling(size_type exp_w)
+{
+ std::mt19937_64 rng(13);
+ std::string file_name = "tmp/int_vector_buffer";
+ size_type buffersize = 1024;
+
+ // write an int_vector-file using int_vector_buffer
+ t_T ivb(file_name, std::ios::out, buffersize, exp_w);
+ for (size_type i=0; i<100000; ++i) {
+ ivb[i] = rng() & sdsl::bits::lo_set[exp_w];
+ }
+ ivb.close();
+
+ // load int_vector from file and compare it with int_vector_buffer
+ t_V iv;
+ sdsl::load_from_file(iv, file_name);
+ ASSERT_EQ((size_type)100000, iv.size());
+ t_T ivb2(file_name, std::ios::in, buffersize, 5);
+ ASSERT_EQ((size_type)100000, ivb2.size());
+ ASSERT_EQ(exp_w, ivb2.width());
+ rng.seed(13);
+ for (size_type i=0; i<iv.size(); ++i) {
+ size_type exp_val = rng() & sdsl::bits::lo_set[exp_w];
+ ASSERT_EQ(exp_val, (size_type)ivb2[i]);
+ ASSERT_EQ(exp_val, (size_type)iv[i]);
+ }
+ ivb2.close(true);
+}
+
+template<class t_T>
+void test_plain_file_handling(uint8_t exp_w)
+{
+ std::mt19937_64 rng(13);
+ std::string file_name = "tmp/int_array";
+ size_type buffersize = 1024;
+
+ // write plain array using int_vector_buffer
+ t_T ivb(file_name, std::ios::out, buffersize, exp_w, true);
+ for (size_type i=0; i<100000; ++i) {
+ ivb[i] = rng();
+ }
+ ivb.close();
+
+ // load plain_array and compare it with int_vector_buffer
+ sdsl::int_vector<> iv;
+ sdsl::load_vector_from_file(iv, file_name, exp_w/8);
+ ASSERT_EQ((size_type)100000, iv.size()) << "written plain int-array has wrong size";
+ ASSERT_EQ(exp_w, iv.width()) << "written plain int-array has wrong width";
+ t_T ivb2(file_name, std::ios::in, buffersize, exp_w, true); // Load plain data with int_vector_buffer
+ ASSERT_EQ((size_type)100000, ivb2.size()); // Check size
+ ASSERT_EQ(exp_w, ivb2.width()); // Check width
+ rng.seed(13);
+ for (size_type i=0; i<iv.size(); ++i) { // Check content
+ size_type exp_val = rng() & sdsl::bits::lo_set[exp_w];
+ ASSERT_EQ(exp_val, (size_type)ivb2[i]);
+ ASSERT_EQ(exp_val, iv[i]);
+ }
+ ivb2.close(true);
+}
+
+//! Test opening of existing file, int_vector-format and close()
+TEST_F(IntVectorBufferTest, FileHandling)
+{
+ for (size_type width=1; width <= 64; ++width) { // for each possible width
+ test_file_handling< sdsl::int_vector_buffer<>, sdsl::int_vector<> >(width);
+ }
+ test_file_handling< sdsl::int_vector_buffer<>, sdsl::int_vector<> >(42);
+ test_file_handling< sdsl::int_vector_buffer<1>, sdsl::int_vector<1> >(1);
+ test_file_handling< sdsl::int_vector_buffer<8>, sdsl::int_vector<8> >(8);
+ test_file_handling< sdsl::int_vector_buffer<13>, sdsl::int_vector<13> >(13);
+ test_file_handling< sdsl::int_vector_buffer<16>, sdsl::int_vector<16> >(16);
+ test_file_handling< sdsl::int_vector_buffer<32>, sdsl::int_vector<32> >(32);
+ test_file_handling< sdsl::int_vector_buffer<64>, sdsl::int_vector<64> >(64);
+ test_plain_file_handling< sdsl::int_vector_buffer<> >(8);
+ test_plain_file_handling< sdsl::int_vector_buffer<> >(16);
+ test_plain_file_handling< sdsl::int_vector_buffer<> >(32);
+ test_plain_file_handling< sdsl::int_vector_buffer<> >(64);
+ test_plain_file_handling< sdsl::int_vector_buffer<8> >(8);
+ test_plain_file_handling< sdsl::int_vector_buffer<16> >(16);
+ test_plain_file_handling< sdsl::int_vector_buffer<32> >(32);
+ test_plain_file_handling< sdsl::int_vector_buffer<64> >(64);
+}
+
+
+template<class t_T>
+void test_swap(size_type exp_w_ivb1, size_type exp_w_ivb2, std::vector<size_type>& vec_sizes)
+{
+ std::string file_name_1 = "tmp/int_vector_buffer_1";
+ std::string file_name_2 = "tmp/int_vector_buffer_2";
+ for (auto size : vec_sizes) {
+ if (size < 1000) {
+ // Create, fill and verify ivb1
+ t_T ivb1(file_name_1, std::ios::out, 100, exp_w_ivb1);
+ for (size_type j=0; j < size; ++j) {
+ ivb1[j] = j & sdsl::bits::lo_set[exp_w_ivb1];
+ }
+ ASSERT_TRUE(ivb1.is_open());
+ ASSERT_EQ(file_name_1, ivb1.filename());
+ ASSERT_EQ(size, ivb1.size());
+ ASSERT_EQ(exp_w_ivb1, ivb1.width());
+ for (size_type j=0; j < size; ++j) {
+ ASSERT_EQ(j & sdsl::bits::lo_set[exp_w_ivb1], (size_type)ivb1[j]);
+ }
+ size_type buffersize_ivb1 = ivb1.buffersize();
+
+ // Create and verify ivb2
+ t_T ivb2(file_name_2, std::ios::out, 80, 2);
+ ASSERT_TRUE(ivb2.is_open());
+ ASSERT_EQ(file_name_2, ivb2.filename());
+ ASSERT_EQ((size_type)0, ivb2.size());
+ ASSERT_EQ(exp_w_ivb2, ivb2.width());
+ size_type buffersize_ivb2 = ivb2.buffersize();
+
+ // Swap ivb1 and ivb2
+ ivb1.swap(ivb2);
+
+ // Check ivb1
+ ASSERT_TRUE(ivb1.is_open());
+ ASSERT_EQ(file_name_2, ivb1.filename());
+ ASSERT_EQ((size_type)0, ivb1.size());
+ ASSERT_EQ(buffersize_ivb2, ivb1.buffersize());
+ ASSERT_EQ(exp_w_ivb2, ivb1.width());
+ ivb1.close(true);
+
+ // Check ivb2
+ ASSERT_TRUE(ivb2.is_open());
+ ASSERT_EQ(file_name_1, ivb2.filename());
+ ASSERT_EQ(size, ivb2.size());
+ ASSERT_EQ(buffersize_ivb1, ivb2.buffersize());
+ ASSERT_EQ(exp_w_ivb1, ivb2.width());
+ for (size_type j=0; j < ivb2.size(); ++j) {
+ ASSERT_EQ(j & sdsl::bits::lo_set[exp_w_ivb1], (size_type)ivb2[j]);
+ }
+ ivb2.close(true);
+ }
+ }
+}
+
+//! Test swap
+TEST_F(IntVectorBufferTest, Swap)
+{
+ for (size_type width=1; width <= 64; ++width) { // for each possible width
+ test_swap< sdsl::int_vector_buffer<> >(width, 2, vec_sizes);
+ }
+ test_swap< sdsl::int_vector_buffer<1> >(1, 1, vec_sizes);
+ test_swap< sdsl::int_vector_buffer<8> >(8, 8, vec_sizes);
+ test_swap< sdsl::int_vector_buffer<13> >(13, 13, vec_sizes);
+ test_swap< sdsl::int_vector_buffer<16> >(16, 16, vec_sizes);
+ test_swap< sdsl::int_vector_buffer<32> >(32, 32, vec_sizes);
+ test_swap< sdsl::int_vector_buffer<64> >(64, 64, vec_sizes);
+}
+
+
+template<class t_T>
+void test_move(size_type constructor_width)
+{
+ std::string file_name = "tmp/int_vector_buffer";
+ std::mt19937_64 rng;
+ size_type numbers = 10000;
+ // Test MoveConstructor in vector
+ {
+ std::vector<t_T> v;
+ for (uint64_t i=0; i<4; i++) {
+ v.push_back(t_T(file_name+sdsl::util::to_string(i), std::ios::out, 1000, i+1));
+ ASSERT_TRUE(v[i].is_open());
+ // fill
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[v[i].width()];
+ v[i][j] = value;
+ ASSERT_EQ(value, (size_type)v[i][j]);
+ }
+ }
+ // Check if all values are correct
+ for (uint64_t i=0; i<v.size(); i++) {
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[v[i].width()];
+ ASSERT_EQ(value, (size_type)v[i][j]);
+ }
+ v[i].close(true);
+ }
+ }
+ // Test MoveConstructor
+ {
+ t_T tmp(file_name, std::ios::out, 1000, 13);
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[tmp.width()];
+ tmp[j] = value;
+ }
+ // MoveConstructor
+ t_T ivb(std::move(tmp));
+
+ // Check ivb
+ ASSERT_TRUE(ivb.is_open());
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[ivb.width()];
+ ASSERT_EQ(value, (size_type)ivb[j]);
+ }
+ ASSERT_EQ(file_name, ivb.filename());
+ ASSERT_EQ((size_type)numbers, ivb.size());
+ ivb.close(true);
+
+ // Check tmp
+ ASSERT_FALSE(tmp.is_open());
+ ASSERT_EQ("", tmp.filename());
+ ASSERT_EQ((size_type)0, tmp.size());
+ ASSERT_EQ(constructor_width, tmp.width());
+ }
+
+ // Test MoveAssignment
+ {
+ std::vector<t_T> v(4);
+ for (uint64_t i=0; i<v.size(); i++) {
+ v[i] = t_T(file_name+sdsl::util::to_string(i), std::ios::out, 1000, i+1);
+ ASSERT_TRUE(v[i].is_open());
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[v[i].width()];
+ v[i][j] = value;
+ }
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[v[i].width()];
+ ASSERT_EQ(value, (size_type)v[i][j]);
+ }
+ v[i].close(true);
+ }
+ for (uint64_t i=0; i<v.size(); i++) {
+ t_T tmp(file_name+sdsl::util::to_string(i), std::ios::out, 1000, i+1);
+ size_type buffersize = tmp.buffersize();
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[v[i].width()];
+ tmp[j] = value;
+ }
+ v[i] = std::move(tmp);
+
+ // Check v[i]
+ ASSERT_TRUE(v[i].is_open());
+ rng.seed(13);
+ for (uint64_t j=0; j<numbers; ++j) {
+ size_type value = rng() & sdsl::bits::lo_set[v[i].width()];
+ ASSERT_EQ(value, (size_type)v[i][j]);
+ }
+ ASSERT_EQ(file_name+sdsl::util::to_string(i), v[i].filename());
+ ASSERT_EQ((size_type)numbers, v[i].size());
+ ASSERT_EQ(buffersize, v[i].buffersize());
+ v[i].close(true);
+
+ // Check tmp
+ ASSERT_FALSE(tmp.is_open());
+ ASSERT_EQ("", tmp.filename());
+ ASSERT_EQ((size_type)0, tmp.size());
+ ASSERT_EQ(constructor_width, tmp.width());
+ }
+ }
+}
+
+//! Test MoveConstructor and MoveAssignment
+TEST_F(IntVectorBufferTest, Move)
+{
+ test_move< sdsl::int_vector_buffer<> >(64);
+ test_move< sdsl::int_vector_buffer<1> >(1);
+ test_move< sdsl::int_vector_buffer<8> >(8);
+ test_move< sdsl::int_vector_buffer<16> >(16);
+ test_move< sdsl::int_vector_buffer<32> >(32);
+ test_move< sdsl::int_vector_buffer<64> >(64);
+}
+
+
+template<class t_T>
+void test_reset(std::vector<size_type>& vec_sizes, size_type width=1)
+{
+ std::mt19937_64 rng(13);
+ std::string file_name = "tmp/int_vector_buffer";
+ size_type buffersize = 1024;
+ for (auto size : vec_sizes) {
+ if (size < 1000) {
+ t_T ivb(file_name, std::ios::out, buffersize, width);
+ for (size_type j=0; j < size; ++j) {
+ ivb[j] = rng();
+ }
+ ASSERT_EQ(file_name, ivb.filename());
+ ASSERT_EQ(size, ivb.size());
+ size_type bsize = ivb.buffersize();
+ ivb.reset(); // reset should delete all content
+ ASSERT_EQ(file_name, ivb.filename()); // same filename as before
+ ASSERT_EQ((size_type)0, ivb.size()); // all content removed
+ ASSERT_EQ(bsize, ivb.buffersize()); // same buffersize as before
+ {
+ std::ifstream ifile(file_name, std::ios::in|std::ios::binary|std::ios::ate);
+ size_type file_end = ifile.tellg();
+ ifile.close();
+ ASSERT_EQ((size_type)0, file_end); // size of file after reset is 0
+ }
+ ivb.close(true);
+ }
+ }
+}
+
+//! Test reset
+TEST_F(IntVectorBufferTest, Reset)
+{
+ for (size_type width=1; width <= 64; ++width) {
+ test_reset< sdsl::int_vector_buffer<> >(vec_sizes, width);
+ }
+ test_reset< sdsl::int_vector_buffer<1> >(vec_sizes);
+ test_reset< sdsl::int_vector_buffer<8> >(vec_sizes);
+ test_reset< sdsl::int_vector_buffer<16> >(vec_sizes);
+ test_reset< sdsl::int_vector_buffer<32> >(vec_sizes);
+ test_reset< sdsl::int_vector_buffer<64> >(vec_sizes);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/IntVectorGenerator.cpp b/test/IntVectorGenerator.cpp
new file mode 100644
index 0000000..86642e8
--- /dev/null
+++ b/test/IntVectorGenerator.cpp
@@ -0,0 +1,46 @@
+#include "sdsl/int_vector.hpp"
+#include <cstdlib>
+#include <iostream>
+#include <algorithm>
+#include <string>
+
+using namespace std;
+using namespace sdsl;
+
+ptrdiff_t myrandom(ptrdiff_t i)
+{
+ return rand()%i;
+}
+ptrdiff_t (*p_myrandom)(ptrdiff_t) = myrandom;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 5) {
+ cout << "Usage: " << argv[0] << " FILE SIZE WIDTH DEFAULT_VALUE [PERM_SEED]" << endl;
+ cout << " (1) Generates an int_vector<>(SIZE, DEFAULT_VALUE, WIDTH)" << endl;
+ cout << " Vector will be initialized with random bits, if " << endl;
+ cout << " DEFAULT_VALUE=r. If DEFAULT_VALUE=i, v will be set to" << endl;
+ cout << " the identity." << endl;
+ cout << " (2) If PERM_SEED is specified, a random_shuffle seeded with" << endl;
+ cout << " PERM_SEED will be performed." << endl;
+ cout << " (3) Stores the vector to FILE." << endl;
+ return 1;
+ }
+ uint64_t size = stoull(argv[2]);
+ uint64_t width = stoull(argv[3]);
+ int_vector<> v(size, 0, width);
+ if ('r' == argv[4][0]) {
+ util::set_random_bits(v);
+ } else if ('i' == argv[4][0]) {
+ util::set_to_id(v);
+ } else {
+ uint64_t default_value = stoull(argv[4]);
+ util::set_to_value(v, default_value);
+ }
+ if (argc > 5) {
+ unsigned long seed = stoul(argv[5]);
+ srand(seed);
+ random_shuffle(v.begin(), v.end(), p_myrandom);
+ }
+ store_to_file(v, argv[1]);
+}
diff --git a/test/IntVectorMapperTest.cpp b/test/IntVectorMapperTest.cpp
new file mode 100644
index 0000000..a8a7e8f
--- /dev/null
+++ b/test/IntVectorMapperTest.cpp
@@ -0,0 +1,288 @@
+#include "sdsl/int_vector_mapper.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <random>
+#include <algorithm>
+
+namespace
+{
+
+typedef sdsl::int_vector<>::size_type size_type;
+typedef sdsl::int_vector<>::value_type value_type;
+
+// The fixture for testing class int_vector.
+class IntVectorMapperTest : public ::testing::Test
+{
+ protected:
+
+ IntVectorMapperTest() {}
+
+ virtual ~IntVectorMapperTest() {}
+
+ virtual void SetUp() {
+ std::mt19937_64 rng;
+ {
+ std::uniform_int_distribution<uint64_t> distribution(1, 100000);
+ auto dice = bind(distribution, rng);
+ for (size_type i=0; i<10; ++i) {
+ vec_sizes.push_back(dice());
+ }
+ }
+ }
+
+ virtual void TearDown() {}
+
+ std::vector<size_type> vec_sizes = {1,64,65,127,128}; // different sizes for the vectors
+};
+
+TEST_F(IntVectorMapperTest, iterator)
+{
+ static_assert(std::is_move_constructible<sdsl::int_vector_mapper<>>::value, "Type is not move constructible");
+ static_assert(std::is_move_assignable<sdsl::int_vector_mapper<>>::value, "Type is not move assignable");
+
+ // test plain
+ for (const auto& size : vec_sizes) {
+ std::vector<uint64_t> vec(size);
+ sdsl::util::set_to_id(vec);
+ {
+ std::ofstream ofs("tmp/int_vector_mapper_itrtest");
+ sdsl::serialize_vector(vec,ofs);
+ }
+ {
+ sdsl::int_vector_mapper<64> ivm("tmp/int_vector_mapper_itrtest",true);
+ ASSERT_EQ(size,ivm.size());
+ ASSERT_TRUE(std::equal(ivm.begin(),ivm.end(),vec.begin()));
+ ASSERT_EQ(size,(size_t)std::distance(ivm.begin(),ivm.end()));
+ }
+ {
+ sdsl::int_vector_mapper<64> ivm("tmp/int_vector_mapper_itrtest",true);
+ auto itr = ivm.end()-1;
+ for (size_t i=0; i<size; i++) {
+ ASSERT_EQ(*itr,vec[size-i-1]);
+ --itr;
+ }
+ }
+ sdsl::remove("tmp/int_vector_mapper_itrtest");
+ }
+
+ // test fixed width
+ for (const auto& size : vec_sizes) {
+ sdsl::int_vector<25> vec(size);
+ sdsl::util::set_to_id(vec);
+ store_to_file(vec,"tmp/int_vector_mapper_itrtest");
+ {
+ sdsl::int_vector_mapper<25> ivm("tmp/int_vector_mapper_itrtest");
+ ASSERT_EQ(size,ivm.size());
+ ASSERT_TRUE(std::equal(ivm.begin(),ivm.end(),vec.begin()));
+ ASSERT_EQ(size,(size_t)std::distance(ivm.begin(),ivm.end()));
+ }
+ {
+ sdsl::int_vector_mapper<25> ivm("tmp/int_vector_mapper_itrtest");
+ auto itr = ivm.end()-1;
+ for (size_t i=0; i<size; i++) {
+ ASSERT_EQ(*itr,vec[size-i-1]);
+ --itr;
+ }
+ }
+ sdsl::remove("tmp/int_vector_mapper_itrtest");
+ }
+
+ // test variable width
+ for (const auto& size : vec_sizes) {
+ sdsl::int_vector<> vec(size);
+ sdsl::util::set_to_id(vec);
+ sdsl::util::bit_compress(vec);
+ store_to_file(vec,"tmp/int_vector_mapper_itrtest");
+ {
+ sdsl::int_vector_mapper<> ivm("tmp/int_vector_mapper_itrtest");
+ ASSERT_EQ(size,ivm.size());
+ ASSERT_EQ(vec.width(),ivm.width());
+ ASSERT_TRUE(std::equal(ivm.begin(),ivm.end(),vec.begin()));
+ ASSERT_EQ(size,(size_t)std::distance(ivm.begin(),ivm.end()));
+ }
+ {
+ sdsl::int_vector_mapper<> ivm("tmp/int_vector_mapper_itrtest");
+ auto itr = ivm.end()-1;
+ for (size_t i=0; i<size; i++) {
+ ASSERT_EQ(*itr,vec[size-i-1]);
+ --itr;
+ }
+ }
+ sdsl::remove("tmp/int_vector_mapper_itrtest");
+ }
+}
+
+TEST_F(IntVectorMapperTest, push_back)
+{
+ // test plain
+ for (const auto& size : vec_sizes) {
+ std::vector<uint64_t> vec(size);
+ sdsl::util::set_to_id(vec);
+ {
+ std::ofstream ofs("tmp/int_vector_mapper_push_backtest");
+ sdsl::serialize_vector(vec,ofs);
+ }
+ {
+ sdsl::int_vector_mapper<64> ivm("tmp/int_vector_mapper_push_backtest",true);
+ ASSERT_EQ(size,ivm.size());
+ for (size_t i=0; i<size; i++) {
+ vec.push_back(vec.size());
+ ivm.push_back(ivm.size());
+ }
+ }
+ {
+ sdsl::int_vector_mapper<64> ivm("tmp/int_vector_mapper_push_backtest",true);
+ ASSERT_EQ(vec.size(),ivm.size());
+ ASSERT_TRUE(std::equal(ivm.begin(),ivm.end(),vec.begin()));
+ ASSERT_EQ(vec.size(),(size_t)std::distance(ivm.begin(),ivm.end()));
+ }
+ sdsl::remove("tmp/int_vector_mapper_itrtest");
+ }
+
+ // test fixed width
+ for (const auto& size : vec_sizes) {
+ sdsl::int_vector<31> vec(size);
+ std::vector<uint64_t> stdvec(size);
+ sdsl::util::set_to_id(vec);
+ sdsl::util::set_to_id(stdvec);
+ store_to_file(vec,"tmp/int_vector_mapper_push_backtest");
+ {
+ sdsl::int_vector_mapper<31> ivm("tmp/int_vector_mapper_push_backtest");
+ ASSERT_EQ(size,ivm.size());
+ for (size_t i=0; i<size; i++) {
+ stdvec.push_back(stdvec.size());
+ ivm.push_back(ivm.size());
+ }
+ }
+ {
+ sdsl::int_vector_mapper<31> ivm("tmp/int_vector_mapper_push_backtest");
+ ASSERT_EQ(stdvec.size(),ivm.size());
+ ASSERT_TRUE(std::equal(ivm.begin(),ivm.end(),stdvec.begin()));
+ ASSERT_EQ(stdvec.size(),(size_t)std::distance(ivm.begin(),ivm.end()));
+ }
+ sdsl::remove("tmp/int_vector_mapper_push_backtest");
+ }
+
+ // test variable width
+ for (const auto& size : vec_sizes) {
+ sdsl::int_vector<> vec(size);
+ std::vector<uint64_t> stdvec(size);
+ sdsl::util::set_to_id(vec);
+ sdsl::util::set_to_id(stdvec);
+ sdsl::util::bit_compress(vec);
+ store_to_file(vec,"tmp/int_vector_mapper_push_backtest");
+ {
+ sdsl::int_vector_mapper<> ivm("tmp/int_vector_mapper_push_backtest");
+ ASSERT_EQ(size,ivm.size());
+ for (size_t i=0; i<size; i++) {
+ stdvec.push_back(i);
+ ivm.push_back(i);
+ }
+ }
+ {
+ sdsl::int_vector_mapper<> ivm("tmp/int_vector_mapper_push_backtest");
+ ASSERT_EQ(stdvec.size(),ivm.size());
+ ASSERT_TRUE(std::equal(ivm.begin(),ivm.end(),stdvec.begin()));
+ ASSERT_EQ(stdvec.size(),(size_t)std::distance(ivm.begin(),ivm.end()));
+ }
+ sdsl::remove("tmp/int_vector_mapper_push_backtest");
+ }
+}
+
+TEST_F(IntVectorMapperTest, bit_compress)
+{
+ for (const auto& size : vec_sizes) {
+ sdsl::int_vector<> vec(size);
+ sdsl::util::set_to_id(vec);
+ store_to_file(vec,"tmp/int_vector_mapper_bit_compress_test_uncompressed");
+ sdsl::util::bit_compress(vec);
+ store_to_file(vec,"tmp/int_vector_mapper_bit_compress_test");
+ {
+ sdsl::int_vector_mapper<> ivmc("tmp/int_vector_mapper_bit_compress_test");
+ sdsl::int_vector_mapper<> ivmu("tmp/int_vector_mapper_bit_compress_test_uncompressed");
+ ASSERT_TRUE(std::equal(ivmc.begin(),ivmc.end(),ivmu.begin()));
+ ASSERT_TRUE(std::equal(ivmc.begin(),ivmc.end(),vec.begin()));
+ }
+ {
+ sdsl::int_vector_mapper<> ivmu("tmp/int_vector_mapper_bit_compress_test_uncompressed");
+ ASSERT_TRUE(std::equal(ivmu.begin(),ivmu.end(),vec.begin()));
+ sdsl::util::bit_compress(ivmu);
+ ASSERT_TRUE(std::equal(ivmu.begin(),ivmu.end(),vec.begin()));
+ }
+ {
+ sdsl::int_vector_mapper<> ivmc("tmp/int_vector_mapper_bit_compress_test");
+ sdsl::int_vector_mapper<> ivmu("tmp/int_vector_mapper_bit_compress_test_uncompressed");
+ ASSERT_EQ(ivmc.size(),ivmu.size());
+ ASSERT_EQ(ivmc.width(),ivmu.width());
+ ASSERT_TRUE(std::equal(ivmc.begin(),ivmc.end(),ivmu.begin()));
+ }
+ sdsl::remove("tmp/int_vector_mapper_bit_compress_test_uncompressed");
+ sdsl::remove("tmp/int_vector_mapper_bit_compress_test");
+ }
+}
+
+TEST_F(IntVectorMapperTest, bitvector_mapping)
+{
+ for (const auto& size : vec_sizes) {
+ sdsl::bit_vector bv(size);
+ sdsl::util::set_random_bits(bv,4711);
+ store_to_file(bv,"tmp/bit_vector_mapper_test");
+ {
+ // load/store test
+ sdsl::bit_vector_mapper bvm("tmp/bit_vector_mapper_test");
+ ASSERT_EQ(bvm.size(),bv.size());
+ ASSERT_EQ(bvm.width(),bv.width());
+ ASSERT_TRUE(std::equal(bvm.begin(),bvm.end(),bv.begin()));
+ ASSERT_EQ(sdsl::util::cnt_one_bits(bv),sdsl::util::cnt_one_bits(bvm));
+ }
+ {
+ // flip test
+ sdsl::bit_vector_mapper bvm("tmp/bit_vector_mapper_test");
+ bvm.flip();
+ bv.flip();
+ ASSERT_TRUE(std::equal(bvm.begin(),bvm.end(),bv.begin()));
+ ASSERT_EQ(sdsl::util::cnt_one_bits(bv),sdsl::util::cnt_one_bits(bvm));
+ }
+ {
+ // load/store after flip
+ sdsl::bit_vector_mapper bvm("tmp/bit_vector_mapper_test");
+ ASSERT_TRUE(std::equal(bvm.begin(),bvm.end(),bv.begin()));
+ ASSERT_EQ(sdsl::util::cnt_one_bits(bv),sdsl::util::cnt_one_bits(bvm));
+ }
+ sdsl::remove("tmp/bit_vector_mapper_test");
+ }
+}
+
+TEST_F(IntVectorMapperTest, temp_buffer_test)
+{
+ for (const auto& size : vec_sizes) {
+ sdsl::int_vector<> vec(size);
+ sdsl::util::set_to_id(vec);
+ std::string tmp_file_name;
+ {
+ auto tmp_buf = sdsl::temp_file_buffer<31>::create();
+ tmp_file_name = tmp_buf.file_name();
+ ASSERT_EQ(tmp_buf.width(),(uint8_t)31);
+ ASSERT_EQ(tmp_buf.size(),(size_t)0);
+ ASSERT_TRUE(tmp_buf.empty());
+ for (const auto& val : vec) {
+ tmp_buf.push_back(val);
+ }
+ ASSERT_EQ(tmp_buf.size(),vec.size());
+ ASSERT_TRUE(std::equal(tmp_buf.begin(),tmp_buf.end(),vec.begin()));
+ }
+ // check that the file is gone
+ std::ifstream cfs(tmp_file_name);
+ ASSERT_FALSE(cfs.is_open());
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/IntVectorTest.cpp b/test/IntVectorTest.cpp
new file mode 100644
index 0000000..daf5fd2
--- /dev/null
+++ b/test/IntVectorTest.cpp
@@ -0,0 +1,362 @@
+#include "sdsl/int_vector.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <random>
+#include <algorithm>
+
+namespace
+{
+
+typedef sdsl::int_vector<>::size_type size_type;
+typedef sdsl::int_vector<>::value_type value_type;
+
+// The fixture for testing class int_vector.
+class IntVectorTest : public ::testing::Test
+{
+ protected:
+
+ IntVectorTest() {}
+
+ virtual ~IntVectorTest() {}
+
+ virtual void SetUp() {
+ std::mt19937_64 rng;
+ {
+ std::uniform_int_distribution<uint64_t> distribution(0, 100000);
+ auto dice = bind(distribution, rng);
+ for (size_type i=0; i<128; ++i) {
+ vec_sizes.push_back(dice());
+ }
+ }
+ {
+ std::uniform_int_distribution<uint64_t> distribution(0, 10000000);
+ auto dice = bind(distribution, rng);
+ for (size_type i=0; i < 10; ++i) {
+ vec_sizes.push_back(dice());
+ }
+ }
+ }
+
+ virtual void TearDown() {}
+
+ std::vector<size_type> vec_sizes = {0,64,65,127,128}; // different sizes for the vectors
+};
+
+template<class t_iv>
+void test_Constructors(uint8_t template_width, size_type constructor_size, uint8_t constructor_width)
+{
+ static_assert(sdsl::util::is_regular<t_iv>::value, "Type is not regular");
+ std::mt19937_64 rng;
+ {
+ // Constructor without argument
+ t_iv iv;
+ ASSERT_EQ((size_type)0, iv.size()); // default size should be 0
+ ASSERT_EQ((uint8_t)template_width, iv.width()); // verify default width of each element
+ }
+ {
+ // Constructor with one argument
+ t_iv iv(constructor_size);
+ ASSERT_EQ(constructor_size, iv.size());
+ ASSERT_EQ(template_width, iv.width());
+ for (size_type j=0; j < iv.size(); ++j) { // should be initialized with 0s
+ ASSERT_EQ((typename t_iv::value_type)0, (typename t_iv::value_type)iv[j]);
+ }
+ }
+ {
+ // Constructor with two arguments
+ size_type expected_val = rng();
+ t_iv iv(constructor_size, expected_val);
+ ASSERT_EQ(constructor_size, iv.size());
+ ASSERT_EQ(template_width, iv.width());
+ expected_val &= sdsl::bits::lo_set[iv.width()];
+ for (size_type j=0; j < iv.size(); ++j) { // should be initialized with expected_val
+ ASSERT_EQ(expected_val, (size_type)iv[j]);
+ }
+ }
+ {
+ // Constructor with three arguments
+ size_type expected_val = rng();
+ t_iv iv(constructor_size, expected_val, constructor_width);
+ ASSERT_EQ(constructor_size, iv.size());
+ if (iv.fixed_int_width == 0) {
+ ASSERT_EQ(constructor_width, iv.width());
+ } else {
+ ASSERT_EQ(template_width, iv.width());
+ }
+ expected_val &= sdsl::bits::lo_set[iv.width()];
+ for (size_type j=0; j < iv.size(); ++j) { // should be initialized with expected_val
+ ASSERT_EQ(expected_val, (size_type)iv[j]);
+ }
+ }
+}
+
+
+
+//! Test Constructors
+TEST_F(IntVectorTest, Constructors)
+{
+ for (auto size : vec_sizes) {
+ if (size<1000) { // Test only for short sizes,
+ for (uint8_t width=1; width<=64; ++width) { // but for all possible widths
+ // unspecialized
+ test_Constructors<sdsl::int_vector<> >(64, size, width);
+ test_Constructors<sdsl::int_vector<3> >(3, size, width);
+ test_Constructors<sdsl::int_vector<31> >(31, size, width);
+ // specialized
+ test_Constructors<sdsl::bit_vector >(1, size, width);
+ test_Constructors<sdsl::int_vector<8> >(8, size, width);
+ test_Constructors<sdsl::int_vector<16> >(16, size, width);
+ test_Constructors<sdsl::int_vector<32> >(32, size, width);
+ test_Constructors<sdsl::int_vector<64> >(64, size, width);
+ }
+ }
+ }
+}
+
+TEST_F(IntVectorTest, Width)
+{
+ size_type len = 1000;
+ sdsl::int_vector<> v(len, 0xF0, 8);
+ ASSERT_EQ(len, v.size());
+ ASSERT_EQ((uint8_t)8, v.width());
+ v.width(4);
+ ASSERT_EQ((uint8_t)4, v.width());
+ ASSERT_EQ(2*len, v.size());
+ for (size_type i=0; i<v.size()/2; i+=2) {
+ ASSERT_EQ(0x0U, v[i*2]);
+ ASSERT_EQ(0xFU, v[i*2+1]);
+ }
+}
+
+TEST_F(IntVectorTest, Swap)
+{
+ std::mt19937_64 rng;
+ for (size_type i=0; i < vec_sizes.size(); ++i) {
+ const size_type val = rng();
+ sdsl::int_vector<> iv(vec_sizes[i], val);
+ {
+ sdsl::int_vector<> tmp;
+ ASSERT_EQ((size_type)0, tmp.size());
+ tmp.swap(iv);
+ ASSERT_EQ((size_type)0, iv.size());
+ ASSERT_EQ(vec_sizes[i], tmp.size());
+ for (size_type j=0; j < tmp.size(); ++j) {
+ ASSERT_EQ(val, tmp[j]);
+ }
+ }
+ }
+}
+
+template<class t_iv>
+void test_AssignAndModifyElement(uint64_t size, uint8_t width)
+{
+ std::mt19937_64 rng;
+ t_iv iv(size, 0, width);
+ for (size_type i=1; i<iv.size(); ++i) {
+ value_type exp_v = rng(), tmp = rng();
+
+ // Assign Test
+ iv[i] = exp_v;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+
+ // Modify Test
+ iv[i] += tmp;
+ exp_v += tmp;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ iv[i] += -1;
+ exp_v += -1;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ iv[i] -= tmp;
+ exp_v -= tmp;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ iv[i] -= -1;
+ exp_v -= -1;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]++);
+ exp_v++;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]--);
+ exp_v--;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ ++exp_v;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], ++iv[i]);
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+ --exp_v;
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], --iv[i]);
+ ASSERT_EQ(exp_v & sdsl::bits::lo_set[width], iv[i]);
+
+ // Compare Test
+ iv[i] = exp_v;
+ iv[i-1] = tmp;
+ exp_v &= sdsl::bits::lo_set[width];
+ tmp &= sdsl::bits::lo_set[width];
+ ASSERT_EQ((exp_v!=tmp), (iv[i]!=iv[i-1]));
+ ASSERT_EQ((exp_v==tmp), (iv[i]==iv[i-1]));
+ ASSERT_EQ((exp_v<=tmp), (iv[i]<=iv[i-1]));
+ ASSERT_EQ((exp_v< tmp), (iv[i]<iv[i-1]));
+ ASSERT_EQ((exp_v>=tmp), (iv[i]>=iv[i-1]));
+ ASSERT_EQ((exp_v> tmp), (iv[i]>iv[i-1]));
+ iv[i-1] = exp_v;
+ ASSERT_FALSE(iv[i]!=iv[i-1]);
+ ASSERT_TRUE(iv[i]==iv[i-1]);
+ }
+}
+
+template<>
+void test_AssignAndModifyElement<sdsl::bit_vector>(uint64_t size, uint8_t width)
+{
+ std::mt19937_64 rng(13);
+ std::uniform_int_distribution<uint64_t> distribution(0, 9);
+
+ sdsl::bit_vector bv(size, 0, width);
+ for (size_type i=0; i<bv.size(); ++i) {
+ value_type exp_v = distribution(rng);
+ bv[i] = exp_v;
+ ASSERT_EQ((bool)exp_v, bv[i]);
+ }
+ bv.flip();
+
+ rng.seed(13); // To get the same values
+ for (size_type i=0; i<bv.size(); ++i) {
+ value_type exp_v = !distribution(rng);
+ ASSERT_EQ((bool)exp_v, bv[i]);
+ }
+}
+
+TEST_F(IntVectorTest, AssignAndModifyElement)
+{
+ // unspecialized vector for each possible width
+ for (uint8_t width=1; width <= 64; ++width) {
+ test_AssignAndModifyElement< sdsl::int_vector<> >(100000, width);
+ }
+ // specialized vectors
+ test_AssignAndModifyElement<sdsl::bit_vector >(100000, 1);
+ test_AssignAndModifyElement<sdsl::int_vector< 8> >(100000, 8);
+ test_AssignAndModifyElement<sdsl::int_vector<16> >(100000, 16);
+ test_AssignAndModifyElement<sdsl::int_vector<32> >(100000, 32);
+ test_AssignAndModifyElement<sdsl::int_vector<64> >(100000, 64);
+}
+
+TEST_F(IntVectorTest, STL)
+{
+ for (size_type i=0; i < vec_sizes.size(); ++i) {
+ sdsl::int_vector<> iv(vec_sizes[i]);
+ ASSERT_EQ(vec_sizes[i], iv.size());
+ auto cnt = iv.size();
+ for (auto x : iv) {
+ x = --cnt;
+ }
+ std::sort(iv.begin(), iv.end());
+ sdsl::int_vector<>::value_type last = 0;
+ for (const auto& x : iv) {
+ ASSERT_TRUE(x >= last);
+ last = x;
+ }
+ }
+}
+
+template<class t_iv>
+void test_SerializeAndLoad(uint8_t width=1)
+{
+ std::mt19937_64 rng;
+ t_iv iv(sdsl::conf::SDSL_BLOCK_SIZE+1000000, 0, width);
+ for (size_type i=0; i<iv.size(); ++i)
+ iv[i] = rng();
+ std::string file_name = "tmp/int_vector";
+ sdsl::store_to_file(iv, file_name);
+ t_iv iv2;
+ sdsl::load_from_file(iv2, file_name);
+ ASSERT_EQ(iv.size(), iv2.size());
+ ASSERT_EQ(iv.width(), iv2.width());
+ for (size_type i=0; i<iv.size(); ++i)
+ ASSERT_EQ(iv[i], iv2[i]);
+ sdsl::remove(file_name);
+}
+
+TEST_F(IntVectorTest, SerializeAndLoad)
+{
+ // unspecialized vector for each possible width
+ for (uint8_t width=1; width <= 64; ++width) {
+ test_SerializeAndLoad< sdsl::int_vector<> >(width);
+ }
+ // specialized vectors
+ test_SerializeAndLoad<sdsl::bit_vector >();
+ test_SerializeAndLoad<sdsl::int_vector< 8> >();
+ test_SerializeAndLoad<sdsl::int_vector<16> >();
+ test_SerializeAndLoad<sdsl::int_vector<32> >();
+ test_SerializeAndLoad<sdsl::int_vector<64> >();
+}
+
+TEST_F(IntVectorTest, SerializeFixedToVariable)
+{
+ sdsl::int_vector<32> iv(123456,0x733D);
+ std::string file_name = "tmp/int_vector_fixed_to_var";
+ {
+ std::ofstream out(file_name);
+ iv.serialize(out, nullptr, "", true);
+ }
+ sdsl::int_vector<> iv2;
+ sdsl::load_from_file(iv2, file_name);
+ ASSERT_EQ(iv.size(), iv2.size());
+ for (size_type i=0; i < iv.size(); ++i) {
+ ASSERT_EQ(iv[i], iv2[i]);
+ }
+ sdsl::remove(file_name);
+}
+
+TEST_F(IntVectorTest, IteratorTest)
+{
+ for (auto i : vec_sizes) {
+ sdsl::int_vector<> iv(i+3);
+ sdsl::util::set_to_id(iv);
+ sdsl::int_vector<>::iterator it = iv.begin();
+ ASSERT_EQ(iv[0], *it++);
+ ASSERT_EQ(iv[1], *it);
+ it += 1;
+ ASSERT_EQ(iv[2], *it);
+ it -= 1;
+ ASSERT_EQ(iv[1], *it);
+ it -= -1;
+ ASSERT_EQ(iv[2], *it);
+ it += -1;
+ ASSERT_EQ(iv[1], *it);
+ ASSERT_EQ(iv[2], *(++it));
+ it = iv.end()-1;
+ ASSERT_EQ(iv[iv.size()-1], *it--);
+ ASSERT_EQ(iv[iv.size()-2], *it);
+ ASSERT_EQ(iv[iv.size()-3], *(--it));
+ }
+ for (auto i : vec_sizes) {
+ sdsl::int_vector<> iv(i+3);
+ sdsl::util::set_to_id(iv);
+ sdsl::int_vector<>::const_iterator it(iv.begin());
+ ASSERT_EQ(iv[0], *it++);
+ ASSERT_EQ(iv[1], *it);
+ it += 1;
+ ASSERT_EQ(iv[2], *it);
+ it -= 1;
+ ASSERT_EQ(iv[1], *it);
+ it -= -1;
+ ASSERT_EQ(iv[2], *it);
+ it += -1;
+ ASSERT_EQ(iv[1], *it);
+ ASSERT_EQ(iv[2], *(++it));
+ it = iv.end()-1;
+ ASSERT_EQ(iv[iv.size()-1], *it--);
+ ASSERT_EQ(iv[iv.size()-2], *it);
+ ASSERT_EQ(iv[iv.size()-3], *(--it));
+ }
+}
+
+
+
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/InvPermSupportTest.cpp b/test/InvPermSupportTest.cpp
new file mode 100644
index 0000000..b96a50d
--- /dev/null
+++ b/test/InvPermSupportTest.cpp
@@ -0,0 +1,135 @@
+#include "sdsl/inv_perm_support.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <random>
+#include <algorithm>
+
+namespace
+{
+
+typedef sdsl::int_vector<>::size_type size_type;
+typedef sdsl::int_vector<>::value_type value_type;
+
+// The fixture for testing class int_vector.
+class InvPermSupportTest : public ::testing::Test
+{
+ protected:
+
+ InvPermSupportTest() {}
+
+ virtual ~InvPermSupportTest() {}
+
+ virtual void SetUp() {
+ for (size_t z=0; z < (1ULL<<20); z=(z+1)*2) {
+ sdsl::int_vector<> iv(z);
+ sdsl::util::set_to_id(iv);
+ random_shuffle(iv.begin(), iv.end());
+ perms.emplace_back(iv);
+ }
+ for (size_t i=0; i<perms.size(); ++i) {
+ auto iiv = perms[i];
+ for (size_t j=0; j<perms[i].size(); ++j) {
+ iiv[perms[i][j]] = j;
+ }
+ inv_perms.emplace_back(iiv);
+ }
+ }
+
+ virtual void TearDown() {}
+
+ std::vector<sdsl::int_vector<>> perms;
+ std::vector<sdsl::int_vector<>> inv_perms;
+};
+
+void compare(const sdsl::int_vector<>& inv_perm, const sdsl::inv_perm_support<>& ips)
+{
+ ASSERT_EQ(inv_perm.size(), ips.size());
+ for (size_t j=0; j<ips.size(); ++j) {
+ ASSERT_EQ(inv_perm[j], ips[j]);
+ }
+}
+
+//! Test Constructors
+TEST_F(InvPermSupportTest, Constructors)
+{
+ static_assert(sdsl::util::is_regular<sdsl::inv_perm_support<>>::value, "Type is not regular");
+ for (size_t i=0; i<perms.size(); ++i) {
+ // Constructor
+ sdsl::inv_perm_support<> ips(&perms[i]);
+ compare(inv_perms[i], ips);
+
+ // Copy-constructor
+ sdsl::inv_perm_support<> ips2(ips);
+ compare(inv_perms[i], ips2);
+
+ // Move-constructor
+ sdsl::inv_perm_support<> ips3(std::move(ips2));
+ compare(inv_perms[i], ips3);
+
+ // Copy-assign
+ sdsl::inv_perm_support<> ips4;
+ ips4 = ips;
+ compare(inv_perms[i], ips4);
+
+ // Move-assign
+ sdsl::inv_perm_support<> ips5;
+ ips5 = std::move(ips);
+ compare(inv_perms[i], ips5);
+ }
+}
+
+TEST_F(InvPermSupportTest, Swap)
+{
+ for (size_type i=0; i < perms.size(); ++i) {
+ sdsl::inv_perm_support<> ips(&perms[i]);
+ {
+ sdsl::inv_perm_support<> tmp;
+ ASSERT_EQ((size_type)0, tmp.size());
+ sdsl::util::swap_support(tmp, ips,
+ &perms[i], (const sdsl::int_vector<>*)nullptr);
+ ASSERT_EQ((size_type)0, ips.size());
+ compare(inv_perms[i], tmp);
+ }
+ }
+}
+
+TEST_F(InvPermSupportTest, SerializeAndLoad)
+{
+ for (size_type i=0; i < perms.size(); ++i) {
+ std::string file_name = "tmp/inv_perm_support";
+ {
+ sdsl::inv_perm_support<> ips(&perms[i]);
+ sdsl::store_to_file(ips, file_name);
+ }
+ sdsl::inv_perm_support<> ips2;
+ sdsl::load_from_file(ips2, file_name);
+ ips2.set_vector(&perms[i]);
+ compare(inv_perms[i], ips2);
+ sdsl::remove(file_name);
+ }
+}
+
+TEST_F(InvPermSupportTest, IteratorTest)
+{
+ for (size_type i=0; i < perms.size(); ++i) {
+ sdsl::inv_perm_support<> ips(&perms[i]);
+ auto iv_it = inv_perms[i].begin();
+ auto ips_it = ips.begin();
+ while (ips_it != ips.end()) {
+ ASSERT_TRUE(iv_it != inv_perms[i].end());
+ ASSERT_EQ(*iv_it, *ips_it);
+ ++iv_it;
+ ++ips_it;
+ }
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/K2TreapTest.config b/test/K2TreapTest.config
new file mode 100644
index 0000000..4c0ea25
--- /dev/null
+++ b/test/K2TreapTest.config
@@ -0,0 +1,6 @@
+# Inputs which should be used
+EMPTY-TEST;test_cases/int-vec-k2t.0.1.0.0.x;test_cases/int-vec-k2t.0.1.0.0.y;test_cases/int-vec-k2t.0.1.0.0.w
+SML-TEST;test_cases/int-vec-k2t.100.16.r.42.x;test_cases/int-vec-k2t.100.16.r.23.y;test_cases/int-vec-k2t.100.8.r.81.w
+MED-TEST;test_cases/int-vec-k2t.10000.16.r.42.x;test_cases/int-vec-k2t.10000.16.r.23.y;test_cases/int-vec-k2t.10000.8.r.81.w
+BIG-TEST;test_cases/int-vec-k2t.100000.39.r.42.x;test_cases/int-vec-k2t.100000.47.r.23.y;test_cases/int-vec-k2t.100000.35.r.81.w
+LRG-TEST;test_cases/int-vec-k2t.1000000.52.r.42.x;test_cases/int-vec-k2t.1000000.57.r.23.y;test_cases/int-vec-k2t.1000000.45.r.81.w
diff --git a/test/K2TreapTest.cpp b/test/K2TreapTest.cpp
new file mode 100644
index 0000000..e2d0706
--- /dev/null
+++ b/test/K2TreapTest.cpp
@@ -0,0 +1,274 @@
+#include "sdsl/k2_treap.hpp"
+#include "sdsl/bit_vectors.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <tuple>
+#include <string>
+#include <algorithm> // for std::min. std::sort
+#include <random>
+
+namespace
+{
+
+using namespace sdsl;
+using namespace std;
+
+typedef int_vector<>::size_type size_type;
+
+string test_file;
+string temp_file;
+bool in_memory;
+
+template<class T>
+class K2TreapTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<
+k2_treap<2, bit_vector>,
+ k2_treap<2, rrr_vector<63>>,
+ k2_treap<3, bit_vector>,
+ k2_treap<4, rrr_vector<63>>,
+ k2_treap<5, rrr_vector<63>>,
+ k2_treap<6, rrr_vector<63>>,
+ k2_treap<16, rrr_vector<63>>
+ > Implementations;
+
+TYPED_TEST_CASE(K2TreapTest, Implementations);
+
+TYPED_TEST(K2TreapTest, CreateAndStoreTest)
+{
+ TypeParam k2treap;
+ construct(k2treap, test_file);
+ ASSERT_TRUE(store_to_file(k2treap, temp_file));
+}
+
+template<class t_k2treap>
+void topk_test(
+ const t_k2treap& k2treap,
+ complex<uint64_t> min_xy,
+ complex<uint64_t> max_xy,
+ const int_vector<>& x,
+ const int_vector<>& y,
+ const int_vector<>& w)
+{
+ auto res_it = top_k(k2treap, {real(min_xy),imag(min_xy)}, {real(max_xy),imag(max_xy)});
+ typedef tuple<uint64_t, uint64_t, uint64_t> t_xyw;
+ vector<t_xyw> vec;
+ for (uint64_t i = 0; i < x.size(); ++i) {
+ if (x[i] >= real(min_xy) and x[i] <= real(max_xy)
+ and y[i] >= imag(min_xy) and y[i] <= imag(max_xy)) {
+ vec.emplace_back(x[i], y[i], w[i]);
+ }
+ }
+ sort(vec.begin(), vec.end(), [](const t_xyw& a, const t_xyw& b) {
+ if (get<2>(a) != get<2>(b))
+ return get<2>(a) > get<2>(b);
+ else if (get<0>(a) != get<0>(b))
+ return get<0>(a) < get<0>(b);
+ return get<1>(a) < get<1>(b);
+ });
+ uint64_t cnt = 0;
+ while (res_it) {
+ ASSERT_TRUE(cnt < vec.size());
+ auto p = *res_it;
+ ASSERT_EQ(get<2>(vec[cnt]), p.second);
+ ASSERT_EQ(get<0>(vec[cnt]), real(p.first));
+ ASSERT_EQ(get<1>(vec[cnt]), imag(p.first));
+ ++res_it;
+ ++cnt;
+ }
+ ASSERT_FALSE(res_it);
+}
+
+TYPED_TEST(K2TreapTest, SizeAndTopk)
+{
+ TypeParam k2treap;
+ ASSERT_TRUE(load_from_file(k2treap, temp_file));
+ int_vector<> x,y,w;
+ ASSERT_TRUE(load_from_file(x, test_file+".x"));
+ ASSERT_TRUE(load_from_file(y, test_file+".y"));
+ ASSERT_EQ(x.size(), y.size());
+ ASSERT_TRUE(load_from_file(w, test_file+".w"));
+ ASSERT_EQ(x.size(), w.size());
+ ASSERT_EQ(x.size(), k2treap.size());
+ uint64_t maxx=0, maxy=0;
+ if (x.size() > 0) {
+ maxx = *max_element(x.begin(), x.end());
+ maxy = *max_element(y.begin(), y.end());
+ }
+ uint64_t minx=0, miny=0;
+ topk_test(k2treap, {minx,maxx}, {miny,maxy}, x, y, w);
+
+ if (x.size() > 0) {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, x.size()-1);
+ auto dice = bind(distribution, rng);
+ for (size_t i=0; i<20; ++i) {
+ auto idx = dice();
+ uint64_t xx = x[idx];
+ uint64_t yy = y[idx];
+ uint64_t dd = 20;
+ uint64_t minx=0, miny=0, maxx=xx+dd, maxy=yy+dd;
+ if (xx >= dd)
+ minx = xx - dd;
+ if (y >= dd)
+ miny = yy - dd;
+ topk_test(k2treap, {minx, miny}, {maxx,maxy}, x, y, w);
+ }
+ }
+}
+
+template<class t_k2treap>
+void range3d_test(
+ const t_k2treap& k2treap,
+ complex<uint64_t> min_xy,
+ complex<uint64_t> max_xy,
+ complex<uint64_t> z,
+ const int_vector<>& x,
+ const int_vector<>& y,
+ const int_vector<>& w)
+{
+ auto res_it = range_3d(k2treap, {real(min_xy),imag(min_xy)},
+ {real(max_xy),imag(max_xy)},
+ {real(z), imag(z)});
+ typedef tuple<uint64_t, uint64_t, uint64_t> t_xyw;
+ vector<t_xyw> vec;
+ for (uint64_t i = 0; i < x.size(); ++i) {
+ if (x[i] >= real(min_xy) and x[i] <= real(max_xy)
+ and y[i] >= imag(min_xy) and y[i] <= imag(max_xy)) {
+ vec.emplace_back(x[i], y[i], w[i]);
+ }
+ }
+ sort(vec.begin(), vec.end(), [](const t_xyw& a, const t_xyw& b) {
+ if (get<2>(a) != get<2>(b))
+ return get<2>(a) > get<2>(b);
+ else if (get<0>(a) != get<0>(b))
+ return get<0>(a) < get<0>(b);
+ return get<1>(a) < get<1>(b);
+ });
+ uint64_t cnt = 0;
+ while (res_it) {
+ ASSERT_TRUE(cnt < vec.size());
+ auto p = *res_it;
+ ASSERT_EQ(get<2>(vec[cnt]), p.second);
+ ASSERT_EQ(get<0>(vec[cnt]), real(p.first));
+ ASSERT_EQ(get<1>(vec[cnt]), imag(p.first));
+ ++res_it;
+ ++cnt;
+ }
+ ASSERT_FALSE(res_it);
+}
+
+TYPED_TEST(K2TreapTest, Range3d)
+{
+ TypeParam k2treap;
+ ASSERT_TRUE(load_from_file(k2treap, temp_file));
+ int_vector<> x,y,w;
+ ASSERT_TRUE(load_from_file(x, test_file+".x"));
+ ASSERT_TRUE(load_from_file(y, test_file+".y"));
+ ASSERT_EQ(x.size(), y.size());
+ ASSERT_TRUE(load_from_file(w, test_file+".w"));
+ ASSERT_EQ(x.size(), w.size());
+ ASSERT_EQ(x.size(), k2treap.size());
+ if (x.size() > 0) {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, x.size()-1);
+ auto dice = bind(distribution, rng);
+ for (size_t i=0; i<20; ++i) {
+ auto idx = dice();
+ uint64_t xx = x[idx];
+ uint64_t yy = y[idx];
+ uint64_t ww = w[idx];
+ uint64_t dd = 20;
+ uint64_t dw = 100;
+ uint64_t minx=0, miny=0, maxx=xx+dd, maxy=yy+dd, minw=0, maxw=ww+dw;
+ if (xx >= dd)
+ minx = xx - dd;
+ if (yy >= dd)
+ miny = yy - dd;
+ if (ww >= dw)
+ minw = ww - dw;
+ range3d_test(k2treap, {minx, miny}, {maxx,maxy}, {minw,maxw}, x, y, w);
+ }
+ }
+}
+
+template<class t_k2treap>
+void count_test(
+ const t_k2treap& k2treap,
+ complex<uint64_t> min_xy,
+ complex<uint64_t> max_xy,
+ const int_vector<>& x,
+ const int_vector<>& y)
+{
+ uint64_t cnt = 0;
+ for (uint64_t i = 0; i < x.size(); ++i) {
+ if (x[i] >= real(min_xy) and x[i] <= real(max_xy)
+ and y[i] >= imag(min_xy) and y[i] <= imag(max_xy)) {
+ ++cnt;
+ }
+ }
+ ASSERT_EQ(cnt, count(k2treap, {real(min_xy),imag(min_xy)}, {real(max_xy),imag(max_xy)}));
+}
+
+TYPED_TEST(K2TreapTest, Count)
+{
+ TypeParam k2treap;
+ ASSERT_TRUE(load_from_file(k2treap, temp_file));
+ int_vector<> x,y;
+ ASSERT_TRUE(load_from_file(x, test_file+".x"));
+ ASSERT_TRUE(load_from_file(y, test_file+".y"));
+ ASSERT_EQ(x.size(), y.size());
+ ASSERT_EQ(x.size(), k2treap.size());
+ if (x.size() > 0) {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, x.size()-1);
+ auto dice = bind(distribution, rng);
+ for (size_t i=0; i<3; ++i) {
+ auto idx1 = dice();
+ auto idx2 = dice();
+ uint64_t x1 = x[idx1];
+ uint64_t y1 = y[idx1];
+ uint64_t x2 = x[idx2];
+ uint64_t y2 = y[idx2];
+ count_test(k2treap, {std::min(x1,x2), std::min(y1,y2)}, {std::max(x1,x2),std::max(y1,y2)}, x, y);
+ }
+ }
+}
+
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 3) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " file temp_file [in-memory]" << endl;
+ cout << " (1) Generates a k2-treap out of file.x, file.y, and file.w." << endl;
+ cout << " Result is stored in temp_file." << endl;
+ cout << " If `in-memory` is specified, the in-memory construction is tested." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_file = argv[2];
+ in_memory = argc > 3;
+ if (in_memory) {
+ auto load_and_store_in_mem = [&](string suf) {
+ int_vector<> data;
+ string file = temp_file + suf;
+ load_vector_from_file(data,file);
+ string ram_file = ram_file_name(file);
+ store_to_file(data, ram_file);
+ };
+ load_and_store_in_mem("x");
+ load_and_store_in_mem("y");
+ load_and_store_in_mem("w");
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/test/LcpConstructTest.config b/test/LcpConstructTest.config
new file mode 100644
index 0000000..05168e0
--- /dev/null
+++ b/test/LcpConstructTest.config
@@ -0,0 +1,7 @@
+# Texts which should be used in the LcpConstructTest.
+# Format: [TC_ID];[TC_PATH]
+LCP-EMPTY-TXT;test_cases/empty.txt
+LCP-EXAMPLE-01;test_cases/example01.txt
+LCP-100A-TXT;test_cases/100a.txt
+LCP-FAUST-TXT;test_cases/faust.txt
+LCP-ZARATHUSTRA-TXT;test_cases/zarathustra.txt
diff --git a/test/LcpConstructTest.cpp b/test/LcpConstructTest.cpp
new file mode 100644
index 0000000..bd20860
--- /dev/null
+++ b/test/LcpConstructTest.cpp
@@ -0,0 +1,117 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <sdsl/construct_lcp.hpp>
+#include <sdsl/construct_bwt.hpp>
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <map>
+
+using namespace sdsl;
+using namespace std;
+
+namespace
+{
+
+string test_file, temp_dir, test_id;
+typedef map<string, void (*)(cache_config&)> tMSFP;// map <name, lcp method>
+
+// The fixture for testing class int_vector.
+class LcpConstructTest : public ::testing::Test
+{
+ protected:
+ LcpConstructTest():CHECK_KEY("CHECK_"+string(conf::KEY_LCP)) { }
+
+ virtual ~LcpConstructTest() { }
+
+ // If the constructor and destructor are not enough for setting up
+ // and cleaning up each test, you can define the following methods:
+ virtual void SetUp() {
+ test_config = cache_config(false, temp_dir, test_id);
+ lcp_function["bwt_based"] = &construct_lcp_bwt_based;
+ lcp_function["bwt_based2"] = &construct_lcp_bwt_based2;
+ lcp_function["PHI"] = &construct_lcp_PHI<8>;
+ lcp_function["semi_extern_PHI"] = &construct_lcp_semi_extern_PHI;
+ lcp_function["go"] = &construct_lcp_go;
+ lcp_function["goPHI"] = &construct_lcp_goPHI;
+
+ uint8_t num_bytes = 1;
+ {
+ // Prepare Input
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, num_bytes));
+ ASSERT_TRUE(contains_no_zero_symbol(text, test_file));
+ append_zero_symbol(text);
+ ASSERT_TRUE(store_to_cache(text, conf::KEY_TEXT, test_config));
+ // Construct SA
+ int_vector<> sa(text.size(), 0, bits::hi(text.size())+1);
+ algorithm::calculate_sa((const unsigned char*)text.data(), text.size(), sa);
+ ASSERT_TRUE(store_to_cache(sa, conf::KEY_SA, test_config));
+ }
+ {
+ // Construct BWT
+ construct_bwt<8>(test_config);
+ }
+ {
+ // Construct LCP
+ construct_lcp_kasai<8>(test_config);
+ std::rename(cache_file_name(conf::KEY_LCP, test_config).c_str(),
+ cache_file_name(CHECK_KEY, test_config).c_str());
+ test_config.file_map.erase(conf::KEY_LCP);
+ }
+ }
+
+ virtual void TearDown() {
+ sdsl::remove(cache_file_name(CHECK_KEY, test_config));
+ }
+
+ cache_config test_config;
+ tMSFP lcp_function;
+ string CHECK_KEY;
+};
+
+TEST_F(LcpConstructTest, construct_lcp)
+{
+ for (tMSFP::const_iterator it = this->lcp_function.begin(), end = this->lcp_function.end(); it != end; ++it) {
+ string info = "construct_lcp_" + (it->first) + " on test file " + test_file;
+ // Construct LCP array
+ (it->second)(this->test_config);
+ // Check LCP array
+ int_vector<> lcp_check, lcp;
+ string lcp_check_file = cache_file_name(CHECK_KEY, this->test_config);
+ string lcp_file = cache_file_name(conf::KEY_LCP, this->test_config);
+ ASSERT_TRUE(load_from_file(lcp_check, lcp_check_file))
+ << info << " could not load reference lcp array";
+ ASSERT_TRUE(load_from_file(lcp, lcp_file))
+ << info << " could not load created lcp array";
+ ASSERT_EQ(lcp_check.size(), lcp.size())
+ << info << " lcp array size differ";
+ for (uint64_t j=0; j<lcp.size(); ++j) {
+ ASSERT_EQ(lcp_check[j], lcp[j])
+ << info << " value differ:" << " lcp_check[" << j << "]="
+ << lcp_check[j] << "!=" << lcp[j] << "=lcp["<< j << "]";
+ }
+ // Clean up LCP array
+ sdsl::remove(cache_file_name(conf::KEY_LCP, this->test_config));
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 4) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file tmp_dir ID" << endl;
+ cout << " (1) Generates the SA, BWT and LCP; arrays are stored in tmp_dir." << endl;
+ cout << " File contain ID as substring." << endl;
+ cout << " (2) Generates LCP with other algorithm and checks the result." << endl;
+ cout << " (3) Deletes all generated files." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_dir = argv[2];
+ test_id = argv[3];
+ return RUN_ALL_TESTS();
+}
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..119b88d
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,299 @@
+include ../Make.helper
+CXX_FLAGS=$(MY_CXX_FLAGS) -Wall -Werror -Wunused-parameter -g -O3 \
+ -I$(INC_DIR) \
+ -I../build/external/gtest-1.6.0/include \
+ -L$(LIB_DIR) \
+ -L../build/external/gtest-1.6.0
+LIB_SDSL=$(LIB_DIR)/libsdsl.a
+CCLIB=-lsdsl -ldivsufsort -ldivsufsort64 -lgtest
+TMP_DIR=tmp
+SOURCES=$(wildcard *Test.cpp)
+EXECS=$(SOURCES:.cpp=.x)
+EXEC_LIST=$(patsubst %,./%;,$(EXECS)) # list of executables
+
+GCDAs=$(SOURCES:.cpp=.gcda)
+GCNOs=$(SOURCES:.cpp=.gcno)
+
+BIT_VECTOR_TC_PATH:=$(call config_column,BitVectorTest.config,2)
+BIT_VECTOR_TESTS:=$(patsubst %,bit-vector-test/%,$(BIT_VECTOR_TC_PATH))
+
+RANK_SUPPORT_TESTS:=$(patsubst %,rank-support-test/%,$(BIT_VECTOR_TC_PATH))
+
+SELECT_SUPPORT_TESTS:=$(patsubst %,select-support-test/%,$(BIT_VECTOR_TC_PATH))
+
+WT_BYTE_TC_PATHS:=$(call config_column,WtByteTest.config,2)
+WT_BYTE_TESTS:=$(patsubst %,wt-byte-test/%,$(WT_BYTE_TC_PATHS))
+
+WT_INT_TC_PATHS:=$(call config_column,WtIntTest.config,2)
+WT_INT_TESTS:=$(patsubst %,wt-int-test/%,$(WT_INT_TC_PATHS))
+
+CSA_BYTE_TC_PATHS:=$(call config_column,CsaByteTest.config,2)
+CSA_BYTE_TESTS:=$(patsubst %,csa-byte-test/%,$(CSA_BYTE_TC_PATHS))
+
+CSA_INT_TC_PATHS:=$(call config_column,CsaIntTest.config,2)
+CSA_INT_TESTS:=$(patsubst %,csa-int-test/%,$(CSA_INT_TC_PATHS))
+
+CST_BYTE_TC_PATHS:=$(call config_column,CstByteTest.config,2)
+CST_BYTE_TESTS:=$(patsubst %,cst-byte-test/%,$(CST_BYTE_TC_PATHS))
+
+CST_INT_TC_PATHS:=$(call config_column,CstIntTest.config,2)
+CST_INT_TESTS:=$(patsubst %,cst-int-test/%,$(CST_INT_TC_PATHS))
+
+RMQ_TC_PATHS:=$(call config_column,RMQTest.config,2)
+RMQ_TESTS:=$(patsubst %,rmq-test/%,$(RMQ_TC_PATHS))
+
+LCP_CONSTRUCT_PATHS:=$(call config_column,LcpConstructTest.config,2)
+LCP_CONSTRUCT_TESTS:=$(patsubst %,lcp-construct-test/%,$(LCP_CONSTRUCT_PATHS))
+
+SA_CONSTRUCT_PATHS:=$(call config_column,SaConstructTest.config,2)
+SA_CONSTRUCT_TESTS:=$(patsubst %,sa-construct-test/%,$(SA_CONSTRUCT_PATHS))
+
+SEARCH_BIDIRECTIONAL_PATHS:=$(call config_column,SearchBidirectionalTest.config,2)
+SEARCH_BIDIRECTIONAL_TESTS:=$(patsubst %,search-bidirectional-test/%,$(SEARCH_BIDIRECTIONAL_PATHS))
+
+K2TREAP_TC_PATH:=$(call config_column,K2TreapTest.config,1)
+K2TREAP_TESTS:=$(patsubst %,k2treap-test/%,$(K2TREAP_TC_PATH))
+
+TC_PATHS:= $(WT_BYTE_TC_PATHS) $(WT_INT_TC_PATHS) \
+ $(CSA_BYTE_TC_PATHS) $(CSA_INT_TC_PATHS) \
+ $(CST_BYTE_TC_PATHS) $(CST_INT_TC_PATHS)
+
+
+
+# do not delete the generated/downloaded test_cases
+.SECONDARY: $(TC_PATHS)
+
+test: bits-test \
+ coder-test \
+ int-vector-test \
+ inv-perm-support-test \
+ int-vector-mapper-test \
+ int-vector-buffer-test \
+ bit-vector-test \
+ rank-support-test\
+ select-support-test\
+ wt-byte-test \
+ wt-int-test \
+ csa-byte-test \
+ csa-int-test \
+ cst-byte-test \
+ cst-int-test \
+ rmq-test \
+ sa-construct-test \
+ search-bidirectional-test \
+ sorted-int-stack-test \
+ nn-dict-dynamic-test \
+ k2treap-test
+
+build-test: $(EXECS)
+ cd ../tutorial; make build-test
+ cd ../examples; make build-test
+ cd ../benchmark/indexing_count; make
+ cd ../benchmark/indexing_locate; make
+ cd ../benchmark/indexing_extract; make
+ cd ../benchmark/rrr_vector; make
+ cd ../benchmark/document_retrieval; make
+ cd ../benchmark/wavelet_trees; make
+
+build-test-clean: clean
+ cd ../tutorial; make clean
+ cd ../examples; make clean
+ cd ../benchmark/indexing_count; make clean-build
+ cd ../benchmark/indexing_locate; make clean-build
+ cd ../benchmark/indexing_extract; make clean-build
+ cd ../benchmark/rrr_vector; make clean-build
+ cd ../benchmark/document_retrieval; make clean-build
+ cd ../benchmark/wavelet_trees; make clean-build
+
+generators: BitVectorGenerator.x IntVectorGenerator.x ReplaceIntVectorValue.x
+
+bits-test: ./BitsTest.x
+ @$(PREFIX) ./BitsTest.x
+
+coder-test: ./CoderTest.x
+ @$(PREFIX) ./CoderTest.x
+
+int-vector-test: ./IntVectorTest.x
+ @$(PREFIX) ./IntVectorTest.x
+
+inv-perm-support-test: ./InvPermSupportTest.x
+ @$(PREFIX) ./InvPermSupportTest.x
+
+int-vector-buffer-test: ./IntVectorBufferTest.x
+ @$(PREFIX) ./IntVectorBufferTest.x
+
+int-vector-mapper-test: ./IntVectorMapperTest.x
+ @$(PREFIX) ./IntVectorMapperTest.x
+
+sorted-int-stack-test: ./SortedIntStackTest.x
+ @$(PREFIX) ./SortedIntStackTest.x
+
+nn-dict-dynamic-test: ./NNDictDynamicTest.x
+ @$(PREFIX) ./NNDictDynamicTest.x
+
+
+bit-vector-test: generators $(BIT_VECTOR_TESTS)
+
+rank-support-test: generators $(RANK_SUPPORT_TESTS)
+
+select-support-test: generators $(SELECT_SUPPORT_TESTS)
+
+wt-byte-test: generators $(WT_BYTE_TESTS)
+
+wt-int-test: generators $(WT_INT_TESTS)
+
+csa-byte-test: generators $(CSA_BYTE_TESTS)
+
+csa-int-test: generators $(CSA_INT_TESTS)
+
+cst-byte-test: generators $(CST_BYTE_TESTS)
+
+cst-int-test: generators $(CST_INT_TESTS)
+
+rmq-test: generators $(RMQ_TESTS)
+
+lcp-construct-test: generators $(LCP_CONSTRUCT_TESTS)
+
+sa-construct-test: generators $(SA_CONSTRUCT_TESTS)
+
+search-bidirectional-test: generators $(SEARCH_BIDIRECTIONAL_TESTS)
+
+k2treap-test: ./K2TreapTest.x generators $(K2TREAP_TESTS)
+
+bit-vector-test/test_cases/%: ./BitVectorTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$*"
+ @$(PREFIX) ./BitVectorTest.x test_cases/$*
+
+rank-support-test/test_cases/%: ./RankSupportTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$*"
+ @$(PREFIX) ./RankSupportTest.x test_cases/$*
+
+select-support-test/test_cases/%: ./SelectSupportTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$*"
+ @$(PREFIX) ./SelectSupportTest.x test_cases/$*
+
+wt-byte-test/test_cases/%: ./WtByteTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$* semi-external"
+ @$(PREFIX) ./WtByteTest.x test_cases/$* $(TMP_DIR)/wt-byte.tmp
+ @echo "TEST_CASE: test_cases/$* in-memory"
+ @$(PREFIX) ./WtByteTest.x test_cases/$* $(TMP_DIR)/wt-byte.tmp in-memory
+
+wt-int-test/test_cases/%: ./WtIntTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$* semi-external"
+ @$(PREFIX) ./WtIntTest.x test_cases/$* $(TMP_DIR)/wt-int.tmp
+ @echo "TEST_CASE: test_cases/$* in-memory"
+ @$(PREFIX) ./WtIntTest.x test_cases/$* $(TMP_DIR)/wt-int.tmp in-memory
+
+csa-byte-test/test_cases/%: ./CsaByteTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$* semi-external"
+ @$(PREFIX) ./CsaByteTest.x test_cases/$* $(TMP_DIR)/csa-byte.tmp $(TMP_DIR)
+ @echo "TEST_CASE: test_cases/$* in-memory"
+ @$(PREFIX) ./CsaByteTest.x test_cases/$* $(TMP_DIR)/csa-byte.tmp $(TMP_DIR) in-memory
+
+csa-int-test/test_cases/%: ./CsaIntTest.x test_cases/%
+ $(eval NUM_BYTES:=$(call config_filter,CsaIntTest.config,test_cases/$*,4))
+ @echo "TEST_CASE: test_cases/$* NUM_BYTES=$(NUM_BYTES) semi-external"
+ @$(PREFIX) ./CsaIntTest.x test_cases/$* $(NUM_BYTES) $(TMP_DIR)/csa-int.tmp $(TMP_DIR)
+ @echo "TEST_CASE: test_cases/$* NUM_BYTES=$(NUM_BYTES) in-memory"
+ @$(PREFIX) ./CsaIntTest.x test_cases/$* $(NUM_BYTES) $(TMP_DIR)/csa-int.tmp $(TMP_DIR) in-memory
+
+cst-byte-test/test_cases/%: ./CstByteTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$* semi-external"
+ $(PREFIX) ./CstByteTest.x test_cases/$* $(TMP_DIR)/cst-byte.tmp $(TMP_DIR)
+ @echo "TEST_CASE: test_cases/$* in-memory"
+ $(PREFIX) ./CstByteTest.x test_cases/$* $(TMP_DIR)/cst-byte.tmp $(TMP_DIR) in-memory
+
+cst-int-test/test_cases/%: ./CstIntTest.x test_cases/%
+ $(eval NUM_BYTES:=$(call config_filter,CstIntTest.config,test_cases/$*,4))
+ @echo "TEST_CASE: test_cases/$* NUM_BYTES=$(NUM_BYTES) semi-external"
+ @$(PREFIX) ./CstIntTest.x test_cases/$* $(NUM_BYTES) $(TMP_DIR)/cst-int.tmp $(TMP_DIR)
+ @echo "TEST_CASE: test_cases/$* NUM_BYTES=$(NUM_BYTES) in-memory"
+ @$(PREFIX) ./CstIntTest.x test_cases/$* $(NUM_BYTES) $(TMP_DIR)/cst-int.tmp $(TMP_DIR) in-memory
+
+rmq-test/test_cases/%: ./RMQTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$*"
+ @$(PREFIX) ./RMQTest.x test_cases/$* $(TMP_DIR)/rmq.tmp
+
+lcp-construct-test/test_cases/%: ./LcpConstructTest.x test_cases/%
+ $(eval TC_ID:=$(call config_filter,LcpConstructTest.config,test_cases/$*,1))
+ @echo "TEST_CASE: test_cases/$*; TC_ID=$(TC_ID)"
+ @$(PREFIX) ./LcpConstructTest.x test_cases/$* $(TMP_DIR) $(TC_ID)
+
+sa-construct-test/test_cases/%: ./SaConstructTest.x test_cases/%
+ $(eval TC_ID:=$(call config_filter,SaConstructTest.config,test_cases/$*,1))
+ @echo "TEST_CASE: test_cases/$*; TC_ID=$(TC_ID)"
+ @$(PREFIX) ./SaConstructTest.x test_cases/$* $(TMP_DIR) $(TC_ID)
+
+search-bidirectional-test/test_cases/%: ./SearchBidirectionalTest.x test_cases/%
+ @echo "TEST_CASE: test_cases/$*"
+ @$(PREFIX) ./SearchBidirectionalTest.x test_cases/$*
+
+k2treap-test/%: ./K2TreapTest.x
+ $(eval X:=$(call config_select,K2TreapTest.config,$*,2))
+ $(eval Y:=$(call config_select,K2TreapTest.config,$*,3))
+ $(eval W:=$(call config_select,K2TreapTest.config,$*,4))
+ make $(X) $(Y) $(W)
+ @echo "X=$X, Y=$Y, W=$W"
+ mv $(X) test_cases/K2T.$*.x
+ mv $(Y) test_cases/K2T.$*.y
+ mv $(W) test_cases/K2T.$*.w
+ @echo "TEST_CASE: $* semi-external"
+ $(PREFIX) ./K2TreapTest.x test_cases/K2T.$* $(TMP_DIR)/K2T.$*
+ @echo "TEST_CASE: test_cases/$* in-memory"
+ $(PREFIX) ./K2TreapTest.x test_cases/K2T.$* $(TMP_DIR)/K2T.$* in-memory
+
+# Format: test_cases/int-vec.[LEN].[WIDTH].[DEFAULT].[SEED]
+test_cases/int-vec.%: IntVectorGenerator.x
+ @echo "Generate input test_cases/int-vec.$*"
+ $(eval LEN:=$(call dim,1,$*))
+ $(eval WIDTH:=$(call dim,2,$*))
+ $(eval DEFAULT:=$(call dim,3,$*))
+ $(eval SEED:=$(call dim,4,$*))
+ @./IntVectorGenerator.x $@ $(LEN) $(WIDTH) $(DEFAULT) $(SEED)
+
+# Format: test_cases/int-vec-sa.[LEN].[WIDTH].[DEFAULT].[SEED]
+test_cases/int-vec-sa.%: IntVectorGenerator.x
+ @echo "Generate input test_cases/int-vec-sa.$*"
+ $(eval LEN:=$(call dim,1,$*))
+ $(eval WIDTH:=$(call dim,2,$*))
+ $(eval DEFAULT:=$(call dim,3,$*))
+ $(eval SEED:=$(call dim,4,$*))
+ @./IntVectorGenerator.x $@ $(LEN) $(WIDTH) $(DEFAULT) $(SEED)
+ @./ReplaceIntVectorValue.x $@ 0 1
+
+# Format: test_cases/int-vec-k2t.[LEN].[WIDTH].[DEFAULT].[SEED].[x|y|w]
+test_cases/int-vec-k2t.%: IntVectorGenerator.x
+ @echo "Generate input test_cases/int-vec-k2t.$*"
+ $(eval LEN:=$(call dim,1,$*))
+ $(eval WIDTH:=$(call dim,2,$*))
+ $(eval DEFAULT:=$(call dim,3,$*))
+ $(eval SEED:=$(call dim,4,$*))
+ @./IntVectorGenerator.x $@ $(LEN) $(WIDTH) $(DEFAULT) $(SEED)
+
+test_cases/bit-vec.%: BitVectorGenerator.x
+ @echo "Generate input test_cases/bit-vec.$*"
+ @./BitVectorGenerator.x $@ $*
+
+%.x:%.cpp $(LIB_SDSL)
+ $(MY_CXX) $(CXX_FLAGS) -o $@ $< $(CCLIB)
+
+test_cases/%:
+ $(eval URL:=$(call config_filter,download.config,$@,2))
+ @$(if $(URL),,\
+ $(error "No download link specified for test case $@") )
+ @echo "Download input from $(URL) using curl"
+ $(eval DEST_DIR:=$(shell dirname $@))
+ cd $(DEST_DIR); curl -O $(URL)
+ $(eval FILE:=$(DEST_DIR)/$(notdir $(URL)))
+ @$(if $(filter-out ".gz",$(FILE)),\
+ echo "Extract file $(FILE) using gunzip";\
+ gunzip $(FILE))
+
+
+clean:
+ rm -f $(EXECS) $(GCDAs) $(GCNOs)
+ rm -f tmp/*
+ rm -rf *.dSYM
+
+cleanall: clean
+ rm -f $(TC_PATHS)
diff --git a/test/NNDictDynamicTest.cpp b/test/NNDictDynamicTest.cpp
new file mode 100644
index 0000000..398c531
--- /dev/null
+++ b/test/NNDictDynamicTest.cpp
@@ -0,0 +1,155 @@
+#include "sdsl/nn_dict_dynamic.hpp"
+#include "sdsl/nearest_neighbour_dictionary.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <string>
+#include <random>
+
+namespace
+{
+
+// The fixture for testing class nn_dict_dynamic.
+class NNDictDynamicTest : public ::testing::Test
+{
+ protected:
+
+ NNDictDynamicTest() {}
+
+ virtual ~NNDictDynamicTest() {}
+
+ virtual void SetUp() {}
+
+ virtual void TearDown() {}
+};
+
+void compare_bv_and_nndd(const sdsl::bit_vector& bv, const sdsl::nn_dict_dynamic& nndd)
+{
+ sdsl::nearest_neighbour_dictionary<32> exp(bv);
+ uint64_t first_one = exp.select(1);
+ uint64_t last_one = exp.select(exp.rank(exp.size()));
+ for (uint64_t i=0; i<first_one; ++i) {
+ ASSERT_EQ(exp.size(), nndd.prev(i));
+ ASSERT_EQ(exp.next(i), nndd.next(i));
+ }
+ for (uint64_t i=first_one; i<=last_one; ++i) {
+ ASSERT_EQ(exp.prev(i), nndd.prev(i));
+ ASSERT_EQ(exp.next(i), nndd.next(i));
+ }
+ for (uint64_t i=last_one+1; i<exp.size(); ++i) {
+ ASSERT_EQ(exp.prev(i), nndd.prev(i));
+ ASSERT_EQ(exp.size(), nndd.next(i));
+ }
+}
+
+//! Test Constructors
+TEST_F(NNDictDynamicTest, Constructors)
+{
+ static_assert(sdsl::util::is_regular<sdsl::nn_dict_dynamic>::value, "Type is not regular");
+ uint64_t testsize = 100000;
+ sdsl::bit_vector bv(testsize, 0);
+ sdsl::nn_dict_dynamic nndd(testsize);
+
+ // Fill nndd
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, testsize-1);
+ auto dice = bind(distribution, rng);
+ for (uint64_t i=0; i<testsize/4; ++i) {
+ uint64_t value = dice();
+ if (bv[value]) {
+ bv[value] = 0;
+ nndd[value] = 0;
+ } else {
+ bv[value] = 1;
+ nndd[value] = 1;
+ }
+ }
+
+ // Copy-constructor
+ sdsl::nn_dict_dynamic nndd2(nndd);
+ compare_bv_and_nndd(bv, nndd2);
+
+ // Move-constructor
+ sdsl::nn_dict_dynamic nndd3(std::move(nndd2));
+ compare_bv_and_nndd(bv, nndd3);
+ ASSERT_EQ((uint64_t)0, nndd2.size());
+
+ // Copy-Assign
+ sdsl::nn_dict_dynamic nndd4;
+ nndd4 = nndd3;
+ compare_bv_and_nndd(bv, nndd4);
+
+ // Move-Assign
+ sdsl::nn_dict_dynamic nndd5;
+ nndd5 = std::move(nndd4);
+ compare_bv_and_nndd(bv, nndd5);
+ ASSERT_EQ((uint64_t)0, nndd4.size());
+}
+
+//! Test Operations next and prev
+TEST_F(NNDictDynamicTest, NextAndPrev)
+{
+ uint64_t testsize = 100000;
+ sdsl::bit_vector bv(testsize, 0);
+ sdsl::nn_dict_dynamic nndd(testsize);
+ for (uint64_t ones=1; ones<testsize; ones *= 2) {
+ std::mt19937_64 rng(ones);
+ std::uniform_int_distribution<uint64_t> distribution(0, testsize-1);
+ auto dice = bind(distribution, rng);
+ for (uint64_t i=0; i<ones; ++i) {
+ uint64_t value = dice();
+ if (bv[value]) {
+ bv[value] = 0;
+ nndd[value] = 0;
+ } else {
+ bv[value] = 1;
+ nndd[value] = 1;
+ }
+ }
+ bv[testsize/4] = 1;
+ nndd[testsize/4] = 1;
+ bv[3*testsize/4] = 1;
+ nndd[3*testsize/4] = 1;
+ compare_bv_and_nndd(bv, nndd);
+ }
+}
+
+//! Test Serialize and Load
+TEST_F(NNDictDynamicTest, SerializeAndLoad)
+{
+ std::string file_name = "tmp/nn_dict_dynamic";
+ uint64_t testsize = 100000;
+ sdsl::bit_vector bv(testsize, 0);
+ {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, testsize-1);
+ auto dice = bind(distribution, rng);
+ sdsl::nn_dict_dynamic nndd(testsize);
+ for (uint64_t i=0; i<testsize/4; ++i) {
+ uint64_t value = dice();
+ if (bv[value]) {
+ bv[value] = 0;
+ nndd[value] = 0;
+ } else {
+ bv[value] = 1;
+ nndd[value] = 1;
+ }
+ }
+ sdsl::store_to_file(nndd, file_name);
+ }
+ {
+ sdsl::nn_dict_dynamic nndd(0);
+ sdsl::load_from_file(nndd, file_name);
+ compare_bv_and_nndd(bv, nndd);
+ }
+ sdsl::remove(file_name);
+}
+
+
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 0000000..fb351eb
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,57 @@
+# Library test suite
+
+This directory contains test code for various data structures.
+We used the [googletest][GTEST] framework for testing.
+
+A call of `make test` will execute all tests. If you only want to
+run a test of a specific component `X` then run
+`make X`, where X should be in the following list:
+
+ * `bits-test` (tests basic bit operations)
+ * `int-vector-test` (tests [int_vector](../include/sdsl/int_vector.hpp))
+ * `int-vector-buffer-test` (tests [int_vector_buffer](../include/sdsl/int_vector_buffer.hpp))
+ * `bit-vector-test` (tests [bit_vector](../include/sdsl/bit_vectors.hpp) strucutres)
+ * `rank-support-test` (tests [rank_support](../include/sdsl/rank_support.hpp) structures)
+ * `select-support-test` and `select-support-0-test`
+ (tests [select_support](../include/sdsl/select_support.hpp) structures)
+ * `wt-byte-test` (tests [wavelet trees](../include/sdsl/wavelet_trees.hpp) on byte alphabets)
+ * `wt-int-test` (tests [wavelet trees](../include/sdsl/wavelet_trees.hpp) on integer alphabets)
+ * `csa-byte-test` (tests [CSAs](../include/sdsl/suffix_arrays.hpp) on byte alphabets)
+ * `csa-int-test` (tests [CSAs](../include/sdsl/suffix_arrays.hpp) on integer alphabets)
+ * `cst-byte-test` (tests [CSTs](../include/sdsl/suffix_trees.hpp) on byte alphabets)
+ * `cst-int-test` (tests [CSTs](../include/sdsl/suffix_trees.hpp) on integer alphabets)
+ * `rmq-test` (tests [RMQ structures](../include/sdsl/rmq_support.hpp))
+
+Test inputs are downloaded as needed before the first execution of the test.
+See the [download.config](./download.config) files for details on the sources.
+Two tools have to be installed for the downloading and extracting process:
+
+ * [cURL][CURL] is required by the test input download script.
+ * [gzip][GZIP] is required to extract compressed files.
+
+Executing `make test` should take about 30 minutes on a recent machine.
+
+You can run also run the test with the [valgrind][VG] tool by
+calling `make PREFIX=valgrind test`.
+
+Please report, if a test fails. Thanks.
+
+## Customization
+
+ * Tests can be customized by editing the `.config` files.
+ Test files should be located in [test_cases](./test_cases).
+
+
+## Acknowledgements
+ We thank
+ * Project Gutenberg for providing text files `faust.txt` and
+ `zarathustra.txt`.
+ * Shane Culpepper for providing the test inputs
+ `keeper.int` and `moby.int` for the integer-alphabet CSAs and CSTs.
+
+
+[VG]: http://valgrind.org/ "Valgrind"
+[PG]: http://www.gutenberg.org/ "Project Gutenberg"
+[CURL]: http://curl.haxx.se/ "cURL"
+[GZIP]: http://www.gnu.org/software/gzip/ "Gzip Compressor"
+[GTEST]: https://code.google.com/p/googletest/ "Google C++ Testing Framework"
diff --git a/test/RMQTest.config b/test/RMQTest.config
new file mode 100644
index 0000000..8a93d74
--- /dev/null
+++ b/test/RMQTest.config
@@ -0,0 +1,7 @@
+#
+#
+EMPTY;test_cases/int-vec.0.1.0
+INT-1-64-42;test_cases/int-vec.1.64.42
+INT-1000000-64-i;test_cases/int-vec.1000000.64.i
+INT-1000000-32-i-42;test_cases/int-vec.1000000.32.i.42
+INT-1000000-64-i-17;test_cases/int-vec.1000000.64.i.17
diff --git a/test/RMQTest.cpp b/test/RMQTest.cpp
new file mode 100644
index 0000000..29cad8b
--- /dev/null
+++ b/test/RMQTest.cpp
@@ -0,0 +1,156 @@
+#include "sdsl/rmq_support.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <stack>
+
+using namespace std;
+using namespace sdsl;
+
+namespace
+{
+
+typedef vector<uint64_t> tVUI;
+
+string test_file;
+string temp_file;
+
+template<class T>
+class RMQTest : public ::testing::Test { };
+
+
+using testing::Types;
+
+typedef Types<sdsl::rmq_succinct_sct<>,
+ sdsl::rmq_succinct_sada<>
+ > Implementations;
+
+TYPED_TEST_CASE(RMQTest, Implementations);
+
+
+TYPED_TEST(RMQTest, ConstructAndStore)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ int_vector<> v;
+ load_from_file(v, test_file);
+ TypeParam rmq(&v);
+ ASSERT_TRUE(sdsl::store_to_file(rmq, temp_file));
+}
+
+// helper class for next test
+class state
+{
+ public:
+ uint64_t l, r; // left and right border of interval
+ uint64_t idx; // index of the min value
+ uint64_t min; // min value in the interval
+ state(uint64_t fl=0, uint64_t fr=0, uint64_t fidx = 0, uint64_t fmin=0) :
+ l(fl), r(fr), idx(fidx), min(fmin) {}
+};
+
+//! Test range minimum queries
+TYPED_TEST(RMQTest, RmqLoadAndQuery)
+{
+ int_vector<> v;
+ ASSERT_TRUE(load_from_file(v, test_file));
+ TypeParam rmq;
+ ASSERT_TRUE(load_from_file(rmq, temp_file));
+ ASSERT_EQ(v.size(), rmq.size());
+ if (rmq.size() > 0) {
+ stack<state> s;
+ uint64_t idx = rmq(0, rmq.size()-1);
+ ASSERT_TRUE(idx < rmq.size());
+ s.push(state(0, rmq.size()-1, idx, v[idx]));
+ while (!s.empty()) {
+ state st = s.top(); s.pop();
+ if (st.l < st.idx) {
+ idx = rmq(st.l, st.idx-1);
+ ASSERT_TRUE(idx >= st.l); ASSERT_TRUE(idx <= st.idx-1);
+ ASSERT_TRUE(v[idx] >= v[st.idx])
+ << "v["<<idx<<"]="<< v[idx]
+ << " < " << "v["<<st.idx<<"]="
+ << v[st.idx] << endl
+ << "[" << st.l << "," << st.r << "]" << endl;
+ s.push(state(st.l, st.idx-1, idx, v[idx]));
+ }
+ if (st.idx < st.r) {
+ idx = rmq(st.idx+1, st.r);
+ ASSERT_TRUE(idx >= st.idx+1); ASSERT_TRUE(idx <= st.r);
+ ASSERT_TRUE(v[idx] >= v[st.idx])
+ << "v["<<idx<<"]="<< v[idx]
+ << " < " << "v["<<st.idx<<"]="
+ << v[st.idx] << endl
+ << "[" << st.l << "," << st.r << "]" << endl;
+ s.push(state(st.idx+1, st.r, idx, v[idx]));
+ }
+ }
+ }
+}
+
+//! Test range minimum queries
+TYPED_TEST(RMQTest, RmqLoadAndMoveAndQuery)
+{
+ int_vector<> v;
+ ASSERT_TRUE(load_from_file(v, test_file));
+ TypeParam rmq_load;
+ ASSERT_TRUE(load_from_file(rmq_load, temp_file));
+ TypeParam rmq = std::move(rmq_load);
+ ASSERT_EQ(v.size(), rmq.size());
+ if (rmq.size() > 0) {
+ stack<state> s;
+ uint64_t idx = rmq(0, rmq.size()-1);
+ ASSERT_TRUE(idx < rmq.size());
+ s.push(state(0, rmq.size()-1, idx, v[idx]));
+ while (!s.empty()) {
+ state st = s.top(); s.pop();
+ if (st.l < st.idx) {
+ idx = rmq(st.l, st.idx-1);
+ ASSERT_TRUE(idx >= st.l); ASSERT_TRUE(idx <= st.idx-1);
+ ASSERT_TRUE(v[idx] >= v[st.idx])
+ << "v["<<idx<<"]="<< v[idx]
+ << " < " << "v["<<st.idx<<"]="
+ << v[st.idx] << endl
+ << "[" << st.l << "," << st.r << "]" << endl;
+ s.push(state(st.l, st.idx-1, idx, v[idx]));
+ }
+ if (st.idx < st.r) {
+ idx = rmq(st.idx+1, st.r);
+ ASSERT_TRUE(idx >= st.idx+1); ASSERT_TRUE(idx <= st.r);
+ ASSERT_TRUE(v[idx] >= v[st.idx])
+ << "v["<<idx<<"]="<< v[idx]
+ << " < " << "v["<<st.idx<<"]="
+ << v[st.idx] << endl
+ << "[" << st.l << "," << st.r << "]" << endl;
+ s.push(state(st.idx+1, st.r, idx, v[idx]));
+ }
+ }
+ }
+}
+
+
+
+TYPED_TEST(RMQTest, DeleteTest)
+{
+ sdsl::remove(temp_file);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 3) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file temp_file" << endl;
+ cout << " (1) Generates a RMQ out of the serialized int_vector in test_file." << endl;
+ cout << " in test_file. Stores RMQ in temp_file." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_file = argv[2];
+
+ return RUN_ALL_TESTS();
+}
diff --git a/test/RankSupportTest.cpp b/test/RankSupportTest.cpp
new file mode 100644
index 0000000..d86fad3
--- /dev/null
+++ b/test/RankSupportTest.cpp
@@ -0,0 +1,90 @@
+#include "sdsl/bit_vectors.hpp"
+#include "sdsl/rank_support.hpp"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+string test_file;
+
+namespace
+{
+
+template<class T>
+class RankSupportTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<rank_support_il<1, 256>,
+ rank_support_il<1, 512>,
+ rank_support_il<1, 1024>,
+ rank_support_rrr<>,
+ rank_support_v<>,
+ rank_support_v5<>,
+ rank_support_rrr<1, 64>,
+ rank_support_rrr<1, 192>,
+ rank_support_rrr<1, 256>,
+ rank_support_rrr<1, 255>,
+ rank_support_rrr<1, 15>,
+ rank_support_rrr<1, 31>,
+ rank_support_rrr<1, 63>,
+ rank_support_rrr<1, 83>,
+ rank_support_rrr<1, 127>,
+ rank_support_rrr<1, 128>,
+ rank_support_rrr<1, 129>,
+ rank_support_sd<1>,
+ rank_support_il<0, 256>,
+ rank_support_il<0, 512>,
+ rank_support_il<0, 1024>,
+ rank_support_rrr<0>,
+ rank_support_v<0>,
+ rank_support_v5<0>,
+ rank_support_rrr<0, 64>,
+ rank_support_rrr<0, 192>,
+ rank_support_rrr<0, 256>,
+ rank_support_rrr<0, 255>,
+ rank_support_rrr<0, 15>,
+ rank_support_rrr<0, 30>,
+ rank_support_rrr<0, 63>,
+ rank_support_rrr<0, 83>,
+ rank_support_rrr<0, 127>,
+ rank_support_rrr<0, 128>,
+ rank_support_rrr<0, 129>,
+ rank_support_sd<0>
+ > Implementations;
+
+TYPED_TEST_CASE(RankSupportTest, Implementations);
+
+//! Test the rank method
+TYPED_TEST(RankSupportTest, RankMethod)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ bit_vector bvec;
+ ASSERT_TRUE(load_from_file(bvec, test_file));
+ typename TypeParam::bit_vector_type bv(bvec);
+ TypeParam rs(&bv);
+ uint64_t rank=0;
+ for (uint64_t j=0; j < bvec.size(); ++j) {
+ ASSERT_EQ(rank, rs.rank(j));
+ rank += (bvec[j] == TypeParam::bit_pat);
+ }
+ EXPECT_EQ(rank, rs.rank(bvec.size()));
+}
+
+}// end namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 2) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " FILE " << endl;
+ cout << " Reads a bitvector from FILE and executes tests." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ return RUN_ALL_TESTS();
+}
+
diff --git a/test/ReplaceIntVectorValue.cpp b/test/ReplaceIntVectorValue.cpp
new file mode 100644
index 0000000..2bf4d26
--- /dev/null
+++ b/test/ReplaceIntVectorValue.cpp
@@ -0,0 +1,31 @@
+#include "sdsl/int_vector.hpp"
+#include <string>
+#include <cstdlib>
+
+using namespace std;
+using namespace sdsl;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 4) {
+ cout << "Usage: " << argv[0] << " FILE X Y" << endl;
+ cout << " Loads an int_vector<>(SIZE, DEFAULT_VALUE, WIDTH)" << endl;
+ cout << " and replaces all values X with Y and stores the " << endl;
+ cout << " result in the same file." << endl;
+ return 1;
+ }
+ uint64_t x = atoi(argv[2]);
+ uint64_t y = atoi(argv[3]);
+ int_vector_buffer<> v(argv[1]);
+ if (v.good()) {
+ for (size_t i=0; i<v.size(); ++i) {
+ uint64_t val = v[i];
+ if (val == x) {
+ v[i] = y;
+ }
+ }
+ } else {
+ cerr << "Could not open int_vector<> file " << argv[1] << endl;
+ return 1;
+ }
+}
diff --git a/test/SaConstructTest.config b/test/SaConstructTest.config
new file mode 100644
index 0000000..5622ca2
--- /dev/null
+++ b/test/SaConstructTest.config
@@ -0,0 +1,8 @@
+# Texts which should be used in the SaConstructTest.
+# Format: [TC_ID];[TC_PATH]
+SA-EMPTY-TXT;test_cases/empty.txt
+SA-ONEBYTE-TXT;test_cases/one_byte.txt
+SA-EXAMPLE-01;test_cases/example01.txt
+SA-100A-TXT;test_cases/100a.txt
+SA-FAUST-TXT;test_cases/faust.txt
+SA-ZARATHUSTRA-TXT;test_cases/zarathustra.txt
diff --git a/test/SaConstructTest.cpp b/test/SaConstructTest.cpp
new file mode 100644
index 0000000..ef7aaef
--- /dev/null
+++ b/test/SaConstructTest.cpp
@@ -0,0 +1,102 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <sdsl/construct_sa.hpp>
+#include <sdsl/construct_sa_se.hpp>
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <map>
+
+using namespace sdsl;
+using namespace std;
+
+namespace
+{
+cache_config config;
+uint64_t n;
+
+class SaConstructTest : public ::testing::Test
+{
+ protected:
+ SaConstructTest() { }
+
+ virtual ~SaConstructTest() { }
+
+ // If the constructor and destructor are not enough for setting up
+ // and cleaning up each test, you can define the following methods:
+ virtual void SetUp() {}
+
+ virtual void TearDown() {}
+};
+
+TEST_F(SaConstructTest, divsufsort)
+{
+ // Construct SA with divsufsort
+ memory_monitor::start();
+ construct_config::byte_algo_sa = LIBDIVSUFSORT;
+ construct_sa<8>(config);
+ memory_monitor::stop();
+ // Rename sa-file
+ sdsl::rename(cache_file_name(conf::KEY_SA, config), cache_file_name("check_sa", config));
+ config.file_map.erase(conf::KEY_SA);
+ register_cache_file("check_sa", config);
+ cout << "# constructs_space = " << (1.0*memory_monitor::peak())/n << " byte per byte, =>" << memory_monitor::peak() << " bytes in total" << endl;
+}
+
+TEST_F(SaConstructTest, sesais)
+{
+ // Construct SA with seSAIS
+ memory_monitor::start();
+ construct_config::byte_algo_sa = SE_SAIS;
+ construct_sa<8>(config);
+ memory_monitor::stop();
+ cout << "# constructs_space = " << (1.0*memory_monitor::peak())/n << " byte per byte, =>" << memory_monitor::peak() << " bytes in total" << endl;
+}
+
+TEST_F(SaConstructTest, compare)
+{
+ // Load both SAs
+ int_vector_buffer<> sa_check(cache_file_name("check_sa", config));
+ int_vector_buffer<> sa(cache_file_name(conf::KEY_SA, config));
+
+ // Verify
+ ASSERT_EQ(sa_check.size(), sa.size()) << " suffix array size differ";
+ for (uint64_t i=0; i<sa_check.size(); ++i) {
+ ASSERT_EQ(sa_check[i], sa[i]) << " sa differs at position " << i;
+ }
+
+ // Remove all files
+ util::delete_all_files(config.file_map);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 4) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file tmp_dir ID" << endl;
+ cout << " (1) Generates the SA and stores it in tmp_dir." << endl;
+ cout << " All generated files contains ID as substring." << endl;
+ cout << " (2) Checks the suffix array." << endl;
+ cout << " (3) Deletes all generated files." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ string test_file = argv[1];
+ string temp_dir = argv[2];
+ string test_id = argv[3];
+ config = cache_config(false, temp_dir, test_id);
+ if (!cache_file_exists(conf::KEY_TEXT, config)) {
+ int_vector<8> text;
+ load_vector_from_file(text, test_file, 1);
+ if (contains_no_zero_symbol(text, test_file)) {
+ append_zero_symbol(text);
+ store_to_cache(text, conf::KEY_TEXT, config);
+ }
+ n = text.size();
+ }
+ register_cache_file(conf::KEY_TEXT, config);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/test/SearchBidirectionalTest.config b/test/SearchBidirectionalTest.config
new file mode 100644
index 0000000..fd9ce5e
--- /dev/null
+++ b/test/SearchBidirectionalTest.config
@@ -0,0 +1,7 @@
+# Texts which should be used in the SerachBidirectionalTest.
+# Format: [TC_ID];[TC_PATH];[TC_NAME]
+TXT-EMPTY;test_cases/empty.txt;empty
+TXT-EXAMPE01;test_cases/example01.txt;example01
+TXT-100A;test_cases/100a.txt;100a
+TXT-FAUST;test_cases/faust.txt;faust-de
+TXT-ZARATHUSTRA;test_cases/zarathustra.txt;zarathustra-de
diff --git a/test/SearchBidirectionalTest.cpp b/test/SearchBidirectionalTest.cpp
new file mode 100644
index 0000000..bdb539c
--- /dev/null
+++ b/test/SearchBidirectionalTest.cpp
@@ -0,0 +1,153 @@
+#include <sdsl/suffix_arrays.hpp>
+#include "gtest/gtest.h"
+#include <iostream>
+#include <vector>
+#include <string>
+
+namespace
+{
+
+using namespace sdsl;
+using namespace std;
+
+typedef sdsl::int_vector<>::size_type size_type;
+
+string test_file;
+string test_file_rev;
+
+template<class T>
+class SearchBidirectionalTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<
+csa_wt<wt_blcd<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, byte_alphabet>,
+ csa_wt<wt_blcd<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, succinct_byte_alphabet<> >,
+ csa_wt<wt_hutu<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, byte_alphabet>,
+ csa_wt<wt_hutu<>, 32, 32, sa_order_sa_sampling<>, int_vector<>, succinct_byte_alphabet<> >,
+ csa_wt<wt_hutu<bit_vector_il<> >, 32, 32, sa_order_sa_sampling<>, int_vector<>, byte_alphabet>
+ > Implementations;
+
+TYPED_TEST_CASE(SearchBidirectionalTest, Implementations);
+
+//! Compare bidirectional search and backward search
+TYPED_TEST(SearchBidirectionalTest, BidirectionalSearch)
+{
+ bool debug = false;
+
+ TypeParam csa1;
+ TypeParam csa1_rev;
+ construct(csa1, test_file, 1);
+ construct(csa1_rev, test_file_rev, 1);
+
+ std::mt19937_64 rng(13);
+ std::uniform_int_distribution<uint64_t> distribution(0, csa1.size()-1);
+
+ for (size_type h = 0; h<1000; ++h) {
+ //search for an existing pattern forward and backward using bidirectional_search:
+ size_type x = 4; // number of characters that are added to the pattern in each step
+ size_type steps = 10; // maximal number of patternparts that are searched for
+ size_type start = distribution(rng); //inclusive
+ size_type end = start; //exclusive
+ bool forward = false;
+
+ size_type l_rev = 0;
+ size_type r_rev = csa1_rev.size()-1;
+ size_type l = 0;
+ size_type r = csa1.size()-1;
+ size_type occ = csa1.size(); // size of the interval equals the number of occurrences of the pattern in the text (init empty pattern)
+ size_type i,pos;
+
+ // alternating forward and backward search using bidirectional_search: alternating every x characters
+ for (size_type rep = 0; rep<steps and start>=x and end<=csa1.size()-x ; ++rep) {
+ string newpat = "";
+ if (forward) {
+ //forward
+ i = 0;
+ pos = end;
+ for (size_type j=0; j<x; ++j) {
+ newpat.push_back(csa1.text[pos+j]);
+ }
+ occ = bidirectional_search_forward(csa1, csa1_rev, l, r, l_rev, r_rev, newpat.begin(), newpat.end(), l, r, l_rev, r_rev);
+ i = newpat.size();
+ end += i;
+ } else {
+ //backward
+ i = 0;
+ pos = start-1;
+ for (size_type j=0; j<x; ++j) {
+ newpat.push_back(csa1.text[pos-x+1+j]);
+ }
+ occ = bidirectional_search_backward(csa1, csa1_rev, l, r, l_rev, r_rev, newpat.begin(), newpat.end(), l, r, l_rev, r_rev);
+ i = newpat.size();
+ start -= i;
+ }
+
+ //output
+ if (debug) {
+ cout << "pattern (at text[" << start << ".." << end-1 << "]):" << endl;
+ for (size_type j=start; j<end; ++j) {
+ cout << csa1.text[j];
+ }
+ cout << endl;
+ if (occ) {
+ cout << "interval of pattern in csa1 is [" << l << ".." << r << "]" << endl;
+ cout << "interval of reverse pattern in csa1_rev is [" << l_rev << ".." << r_rev << "]" << endl;
+ }
+ cout << endl;
+ }
+ ASSERT_LT((size_type)0, occ) << "Pattern not found in input."; // make sure pattern was found in input (it has to be because we took part of the input as pattern)
+
+ {
+ //check using backward_search
+ string pat = "";
+ for (size_type j=0; j<end-start; ++j) {
+ pat.push_back(csa1.text[start+j]);
+ }
+ size_type b_l,b_r;
+ size_type b_occ = backward_search(csa1, 0, csa1.size()-1, pat.begin(), pat.end(), b_l, b_r);
+ ASSERT_EQ(b_occ, occ) << "Bidirectional_search and backward_search found different number of occurrences of the pattern.";
+ ASSERT_EQ(b_l, l) << "Bidirectional_search and backward_search found different left border";
+ ASSERT_EQ(b_r, r) << "Bidirectional_search and backward_search found different right border";
+ }
+
+ //change direction
+ forward = !forward;
+ }
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (argc!=2) {
+ cout << "Usage: " << argv[0] << " test_file" << endl;
+ cout << " (1) Reverses test_file; stores it in test_file_rev." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes test_file_reverse." << endl;
+ return 1;
+ }
+ test_file = argv[1];
+ test_file_rev = test_file + "_rev";
+
+ {
+ //reverse input
+ int_vector<8> text;
+ load_vector_from_file(text, test_file, 1);
+ size_type n = text.size();
+ int_vector<8> text_rev(n);
+ for (size_type i=0; i<n; i++) {
+ text_rev[n-1-i] = text[i];
+ }
+ char* text2 = (char*)text_rev.data();
+ ofstream of(test_file_rev, ofstream::binary);
+ of.write(text2, n);
+ of.close();
+ }
+ int result = RUN_ALL_TESTS();
+ sdsl::remove(test_file_rev);
+ return result;
+}
diff --git a/test/SelectSupportTest.cpp b/test/SelectSupportTest.cpp
new file mode 100644
index 0000000..80f0b27
--- /dev/null
+++ b/test/SelectSupportTest.cpp
@@ -0,0 +1,79 @@
+#include "sdsl/bit_vectors.hpp"
+#include "sdsl/select_support.hpp"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+string test_file;
+
+namespace
+{
+
+template<class T>
+class SelectSupportTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<select_support_mcl<>,
+ select_support_rrr<1, 256>,
+ select_support_rrr<1, 129>,
+ select_support_rrr<1, 192>,
+ select_support_rrr<1, 255>,
+ select_support_rrr<1, 15>,
+ select_support_rrr<1, 31>,
+ select_support_rrr<1, 63>,
+ select_support_rrr<1, 127>,
+ select_support_rrr<1, 128>,
+ select_support_sd<1>,
+ select_support_sd<0>,
+ select_0_support_sd<>,
+ select_support_il<1, 256>,
+ select_support_il<1, 512>,
+ select_support_il<1, 1024>,
+ select_support_mcl<0>,
+ select_support_rrr<0, 256>,
+ select_support_rrr<0>,
+ select_support_rrr<0, 15>,
+ select_support_rrr<0, 31>,
+ select_support_rrr<0, 63>,
+ select_support_rrr<0, 127>,
+ select_support_il<0, 256>,
+ select_support_il<0, 512>,
+ select_support_il<0, 1024>
+ > Implementations;
+
+TYPED_TEST_CASE(SelectSupportTest, Implementations);
+
+//! Test the select method
+TYPED_TEST(SelectSupportTest, SelectMethod)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ bit_vector bvec;
+ ASSERT_TRUE(load_from_file(bvec, test_file));
+ typename TypeParam::bit_vector_type bv(bvec);
+ TypeParam ss(&bv);
+ for (uint64_t j=0, select=0; j < bvec.size(); ++j) {
+ if (bvec[j] == TypeParam::bit_pat) {
+ ++select;
+ ASSERT_EQ(j, ss.select(select));
+ }
+ }
+}
+
+}// end namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 2) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " FILE " << endl;
+ cout << " Reads a bitvector from FILE and executes tests." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ return RUN_ALL_TESTS();
+}
diff --git a/test/SortedIntStackTest.cpp b/test/SortedIntStackTest.cpp
new file mode 100644
index 0000000..b2884e6
--- /dev/null
+++ b/test/SortedIntStackTest.cpp
@@ -0,0 +1,151 @@
+#include "sdsl/sorted_int_stack.hpp"
+#include "sdsl/util.hpp"
+#include "gtest/gtest.h"
+#include <string>
+#include <random>
+
+namespace
+{
+
+// The fixture for testing class sorted_int_stack.
+class SortedStackTest : public ::testing::Test
+{
+ protected:
+
+ SortedStackTest() {}
+
+ virtual ~SortedStackTest() {}
+
+ virtual void SetUp() {}
+
+ virtual void TearDown() {}
+};
+
+void compare_stacks(std::stack<uint64_t>& exp, sdsl::sorted_int_stack& sis)
+{
+ ASSERT_EQ(exp.size(), sis.size());
+ std::stack<uint64_t> tmp;
+ while (!exp.empty()) {
+ ASSERT_EQ(exp.top(), sis.top());
+ tmp.push(exp.top());
+ exp.pop();
+ sis.pop();
+ }
+ ASSERT_EQ(exp.size(), sis.size());
+ // Restore stacks
+ while (!tmp.empty()) {
+ exp.push(tmp.top());
+ sis.push(tmp.top());
+ tmp.pop();
+ }
+}
+
+//! Test Constructors
+TEST_F(SortedStackTest, Constructors)
+{
+ static_assert(std::is_copy_constructible<sdsl::sorted_int_stack>::value, "Type is not copy constructible");
+ static_assert(std::is_move_constructible<sdsl::sorted_int_stack>::value, "Type is not move constructible");
+ static_assert(std::is_copy_assignable<sdsl::sorted_int_stack>::value, "Type is not copy assignable");
+ static_assert(std::is_move_assignable<sdsl::sorted_int_stack>::value, "Type is not move assignable");
+ std::stack<uint64_t> exp;
+ sdsl::sorted_int_stack sis1(100000+10);
+ {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, 10);
+ auto dice = bind(distribution, rng);
+ for (uint64_t k=0; k<100000; ++k) {
+ uint64_t value = k+dice();
+ if (exp.empty() or exp.top() < value) {
+ exp.push(value);
+ sis1.push(value);
+ }
+ }
+ }
+
+ // Copy-constructor
+ sdsl::sorted_int_stack sis2(sis1);
+ compare_stacks(exp, sis2);
+
+ // Move-constructor
+ sdsl::sorted_int_stack sis3(std::move(sis2));
+ compare_stacks(exp, sis3);
+ // ASSERT_EQ((uint64_t)0, sis2.size());
+
+ // Copy-Assign
+ sdsl::sorted_int_stack sis4(0);
+ sis4 = sis3;
+ compare_stacks(exp, sis4);
+
+ // Move-Assign
+ sdsl::sorted_int_stack sis5(0);
+ sis5 = std::move(sis4);
+ compare_stacks(exp, sis5);
+ // ASSERT_EQ((uint64_t)0, sis4.size());
+}
+
+//! Test Operations push, top and pop
+TEST_F(SortedStackTest, PushTopAndPop)
+{
+ for (uint64_t i=0; i<20; ++i) {
+ std::mt19937_64 rng(i);
+ std::uniform_int_distribution<uint64_t> distribution(0, i*i);
+ auto dice = bind(distribution, rng);
+ std::stack<uint64_t> exp;
+ sdsl::sorted_int_stack sis(1000000+i*i);
+ ASSERT_TRUE(sis.empty());
+ for (uint64_t k=0; k<1000000; ++k) {
+ ASSERT_EQ(exp.size(), sis.size());
+ uint64_t value = k+dice();
+ if (exp.empty()) {
+ exp.push(value);
+ sis.push(value);
+ } else {
+ ASSERT_EQ(exp.top(), sis.top());
+ if (exp.top() >= value) {
+ exp.pop();
+ sis.pop();
+ } else {
+ exp.push(value);
+ sis.push(value);
+ }
+ }
+ }
+ }
+}
+
+//! Test Serialize and Load
+TEST_F(SortedStackTest, SerializeAndLoad)
+{
+ std::string file_name = "tmp/sorted_int_stack";
+ std::stack<uint64_t> exp;
+ {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, 10);
+ auto dice = bind(distribution, rng);
+ sdsl::sorted_int_stack sis(1000000+10);
+ for (uint64_t k=0; k<1000000; ++k) {
+ uint64_t value = k+dice();
+ if (exp.empty() or exp.top() < value) {
+ exp.push(value);
+ sis.push(value);
+ }
+ }
+ sdsl::store_to_file(sis, file_name);
+ }
+ {
+ sdsl::sorted_int_stack sis(0);
+ sdsl::load_from_file(sis, file_name);
+ compare_stacks(exp, sis);
+ }
+ sdsl::remove(file_name);
+}
+
+
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/WtByteTest.config b/test/WtByteTest.config
new file mode 100644
index 0000000..ff8589f
--- /dev/null
+++ b/test/WtByteTest.config
@@ -0,0 +1,8 @@
+# Texts which should be used in the WtByteTest.
+# Each line contains [TC_ID];[TC_PATH]
+TXT-EMPTY;test_cases/empty.txt;empty
+TXT-EXAMPE01;test_cases/example01.txt;example01
+TXT-100A;test_cases/100a.txt;100a
+TXT-all;test_cases/all_symbols.txt;all_symbols
+TXT-FAUST;test_cases/faust.txt;faust-de
+#TXT-ZARATHUSTRA;test_cases/zarathustra.txt;zarathustra-de
diff --git a/test/WtByteTest.cpp b/test/WtByteTest.cpp
new file mode 100644
index 0000000..0d5adc7
--- /dev/null
+++ b/test/WtByteTest.cpp
@@ -0,0 +1,582 @@
+#include "sdsl/wavelet_trees.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <algorithm> // for std::min
+#include <random>
+
+namespace
+{
+
+using namespace sdsl;
+using namespace std;
+
+typedef int_vector<>::size_type size_type;
+
+string test_file;
+string temp_file;
+bool in_memory;
+
+template<class T>
+class WtByteTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<
+wt_pc<balanced_shape>
+,wt_blcd<rrr_vector<63>>
+ ,wt_blcd<bit_vector_il<>>
+ ,wt_blcd<bit_vector>
+ ,wt_huff<bit_vector_il<>>
+ ,wt_huff<bit_vector, rank_support_v<>>
+ ,wt_huff<bit_vector, rank_support_v5<>>
+ ,wt_huff<rrr_vector<63>>
+ ,wt_rlmn<>
+ ,wt_rlmn<bit_vector>
+ ,wt_gmr_rs<>
+ ,wt_hutu<bit_vector_il<>>
+ ,wt_hutu<bit_vector, rank_support_v<>>
+ ,wt_hutu<bit_vector, rank_support_v5<>>
+ ,wt_hutu<rrr_vector<63>>
+ > Implementations;
+
+TYPED_TEST_CASE(WtByteTest, Implementations);
+
+TYPED_TEST(WtByteTest, CreateAndStoreTest)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ TypeParam wt;
+ construct(wt, test_file, 1);
+ ASSERT_TRUE(store_to_file(wt, temp_file));
+}
+
+//! Test sigma
+TYPED_TEST(WtByteTest, Sigma)
+{
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ ASSERT_EQ(text.size(), wt.size());
+ bit_vector occur(256, 0);
+ uint16_t sigma = 0;
+ for (size_type j=0; j<text.size(); ++j) {
+ if (!occur[(unsigned char)text[j]]) {
+ occur[(unsigned char)text[j]] = 1;
+ ++sigma;
+ }
+ }
+ ASSERT_EQ(sigma, wt.sigma);
+}
+
+template<class t_wt>
+void compare_wt(const int_vector<8>& text, const t_wt& wt)
+{
+ ASSERT_EQ(text.size(), wt.size());
+ for (size_type j=0; j<text.size(); ++j) {
+ ASSERT_EQ((typename t_wt::value_type)text[j], wt[j])<<" j="<<j;
+ }
+}
+
+//! Test Access method, Copy-construtor, Move-constructor, Copy-assign and Move-assign
+TYPED_TEST(WtByteTest, AccessCopyMoveAndSwap)
+{
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ compare_wt(text, wt);
+
+ // Copy-constructor
+ TypeParam wt2(wt);
+ compare_wt(text, wt2);
+
+ // Move-constructor
+ TypeParam wt3(std::move(wt2));
+ compare_wt(text, wt3);
+
+ // Copy-Assign
+ TypeParam wt4;
+ wt4 = wt3;
+ compare_wt(text, wt4);
+
+ // Move-Assign
+ TypeParam wt5;
+ wt5 = std::move(wt4);
+ compare_wt(text, wt5);
+
+ // Swap
+ TypeParam wt6;
+ wt6.swap(wt5);
+ compare_wt(text, wt6);
+}
+
+//! Test rank methods
+TYPED_TEST(WtByteTest, Rank)
+{
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+
+ vector<size_type> cnt(256, 0);
+ ASSERT_EQ(text.size(), wt.size());
+ for (size_type j=0; j < wt.size(); ++j) {
+ cnt[text[j]]++;
+ ASSERT_EQ(cnt[text[j]], wt.rank(j+1, text[j]))<< " j = "<<j<<" text[j]"<<text[j];
+ }
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, wt.size());
+ auto dice = bind(distribution, rng);
+ // Do random queries for all characters that do not occur in the string
+ for (size_type j=0; j<cnt.size(); ++j) {
+ if (cnt[j] == 0) {
+ for (size_type k=0; k<1000; ++k) {
+ size_type pos = dice();
+ ASSERT_EQ((size_type)0, wt.rank(pos, (unsigned char)j))<<" pos="<<pos;
+ }
+ }
+ }
+ // Test rank(size(), c) for each character c
+ for (size_type c=0; c < 256; ++c) {
+ ASSERT_EQ(cnt[c], wt.rank(wt.size(), (unsigned char)c))<<" c="<<c;
+ }
+}
+
+//! Test select methods
+TYPED_TEST(WtByteTest, Select)
+{
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ vector<size_type> cnt(256, 0);
+ ASSERT_EQ(text.size(), wt.size());
+ for (size_type j=0; j<text.size(); ++j) {
+ cnt[text[j]]++;
+ ASSERT_EQ(j, wt.select(cnt[text[j]], text[j]))<< " j = "<<j<<" text[j] = "<<text[j];
+ }
+}
+
+//! Test inverse select method
+TYPED_TEST(WtByteTest, InverseSelect)
+{
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ std::vector<size_type> cnt(256, 0);
+ ASSERT_EQ(text.size(), wt.size());
+ for (size_type j=0; j<text.size(); ++j) {
+ auto rc = wt.inverse_select(j);
+ ASSERT_EQ(cnt[text[j]], rc.first);
+ ASSERT_EQ(text[j], rc.second);
+ cnt[text[j]]++;
+ }
+}
+
+template<class t_wt>
+void
+test_interval_symbols(typename std::enable_if<!(has_node_type<t_wt>::value),
+ t_wt>::type&)
+{
+ // interval_symbols not implemented
+}
+
+template<class t_wt>
+void
+test_interval_symbols(typename std::enable_if<has_node_type<t_wt>::value,
+ t_wt>::type& wt)
+{
+
+ typedef typename t_wt::value_type value_type;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, wt.size());
+ auto dice = bind(distribution, rng);
+ size_type k;
+ std::vector<value_type> cs(wt.sigma);
+ std::vector<size_type> rank_c_i(wt.sigma);
+ std::vector<size_type> rank_c_j(wt.sigma);
+ for (size_type t=0; t<(wt.size()/100+100); ++t) {
+ size_type i = dice(), j = dice();
+ if (i>j) {
+ std::swap(j,i);
+ }
+ interval_symbols(wt, i, j, k, cs, rank_c_i, rank_c_j);
+
+ size_type symbols = (j-i);
+ for (size_type m = 0; m<k; ++m) {
+ ASSERT_EQ(wt.rank(i, cs[m]), rank_c_i[m]);
+ ASSERT_EQ(wt.rank(j, cs[m]), rank_c_j[m]);
+ ASSERT_LT((size_type)0, rank_c_j[m]-rank_c_i[m]);
+ symbols -= (rank_c_j[m]-rank_c_i[m]);
+ if (m>0 and t_wt::lex_ordered) {
+ ASSERT_LT(cs[m-1],cs[m]);
+ }
+ }
+
+ ASSERT_EQ((size_type)0, symbols);
+ if (!t_wt::lex_ordered) {
+ sort(cs.begin(), cs.begin()+k);
+ for (size_type m=1; m<k; m++) {
+ ASSERT_LT(cs[m-1], cs[m]);
+ }
+ }
+ }
+}
+
+//! Test interval symbols method
+TYPED_TEST(WtByteTest, IntervalSymbols)
+{
+ TypeParam wt;
+ test_interval_symbols<TypeParam>(wt);
+}
+
+
+template<class t_wt>
+void
+test_symbol_gte(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // symbol_gte not implemented
+}
+
+template<class t_wt>
+void
+test_symbol_gte(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ using value_type = typename t_wt::value_type;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> iv;
+ ASSERT_TRUE(load_vector_from_file(iv, test_file, 1));
+ ASSERT_EQ(iv.size(), wt.size());
+ mt19937_64 rng;
+ value_type min = numeric_limits<value_type>::max(), max = 0;
+ std::set<value_type> syms;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ syms.insert(iv[j]);
+ }
+
+ if (iv.size() == 0) {
+ return;
+ }
+
+ // check symbols that are in there also are reported as "equal"
+ auto itr = syms.begin();
+ auto end = syms.end();
+ while (itr != end) {
+ auto value = *itr;
+ auto ret = symbol_gte(wt,value);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(value,ret.second);
+ ++itr;
+ }
+
+ // check symbols symbols that are smaller than than min
+ for (size_t i=0; i<min; i++) {
+ auto ret = symbol_gte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,min);
+ }
+
+ // check symbols that are larget than max
+ value_type test_max = numeric_limits<value_type>::max();
+ for (value_type i=test_max; i>max; i--) {
+ auto ret = symbol_gte(wt,i);
+ ASSERT_FALSE(ret.first);
+ }
+
+ // check values in between that do not exist
+ for (size_t i=min; i<max; i++) {
+ auto itr = syms.find(i);
+ if (itr == syms.end()) {
+ size_t j=i+1;
+ auto next = syms.find(j);
+ while (next == syms.end()) {
+ next = syms.find(j+1);
+ j++;
+ }
+ if (next != syms.end()) {
+ auto next_val = *next;
+ auto ret = symbol_gte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,next_val);
+ }
+ }
+ }
+}
+
+//! Test the load method and intersect
+TYPED_TEST(WtByteTest, symbol_gte)
+{
+ TypeParam wt;
+ test_symbol_gte<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_symbol_lte(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // symbol_lte not implemented
+}
+
+
+
+template<class t_wt>
+void
+test_symbol_lte(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ using value_type = typename t_wt::value_type;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> iv;
+ ASSERT_TRUE(load_vector_from_file(iv, test_file, 1));
+ ASSERT_EQ(iv.size(), wt.size());
+ mt19937_64 rng;
+ value_type min = numeric_limits<value_type>::max(), max = 0;
+ std::set<value_type> syms;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ syms.insert(iv[j]);
+ }
+
+ if (iv.size() == 0) {
+ return;
+ }
+
+ // check symbols that are in there also are reported as "equal"
+ auto itr = syms.begin();
+ auto end = syms.end();
+ while (itr != end) {
+ auto value = *itr;
+ auto ret = symbol_lte(wt,value);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(value,ret.second);
+ ++itr;
+ }
+
+ // check symbols symbols that are smaller than than min
+ for (size_t i=0; i<min; i++) {
+ auto ret = symbol_lte(wt,i);
+ ASSERT_FALSE(ret.first);
+ //ASSERT_EQ(ret.second,min);
+ }
+
+ // check symbols that are larget than max
+ value_type test_max = numeric_limits<value_type>::max();
+ for (size_t i=test_max; i>max; i--) {
+ auto ret = symbol_lte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,max);
+ }
+
+ // check values in between that do not exist
+ for (size_t i=min+1; i<max; i++) {
+ auto itr = syms.find(i);
+ if (itr == syms.end()) {
+ size_t j=i-1;
+ auto prev = syms.find(j);
+ while (prev == syms.end()) {
+ prev = syms.find(j-1);
+ j--;
+ }
+ if (prev != syms.end()) {
+ auto prev_val = *prev;
+ auto ret = symbol_lte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,prev_val);
+ }
+ }
+ }
+}
+
+
+//! Test the load method and intersect
+TYPED_TEST(WtByteTest, symbol_lte)
+{
+ TypeParam wt;
+ test_symbol_lte<TypeParam>(wt);
+}
+
+
+template<class t_wt>
+void
+test_range_unique_values(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // test_range_unique_values not implemented
+}
+
+template<class t_wt>
+void
+test_range_unique_values(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ using value_type = typename t_wt::value_type;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> iv;
+ ASSERT_TRUE(load_vector_from_file(iv, test_file, 1));
+ ASSERT_EQ(iv.size(), wt.size());
+ value_type min = numeric_limits<value_type>::max(), max = 0;
+ std::set<value_type> syms;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ syms.insert(iv[j]);
+ }
+
+ if (iv.size() == 0) {
+ return;
+ }
+
+ // try 128 random queries
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> x_dist(0, wt.size()-1);
+ std::uniform_int_distribution<uint64_t> y_dist(0, max);
+ auto xdice = bind(x_dist, rng);
+ auto ydice = bind(y_dist, rng);
+ for (size_t i=0; i<128; i++) {
+ size_t x_i = xdice();
+ size_t x_j = xdice();
+ if (x_i>x_j) std::swap(x_i,x_j);
+ size_t y_i = ydice();
+ size_t y_j = ydice();
+ if (y_i>y_j) std::swap(y_i,y_j);
+ auto uniq_values = restricted_unique_range_values(wt,x_i,x_j,y_i,y_j);
+
+ /* verify */
+ std::set<value_type> syms;
+ for (size_t j=x_i; j<=x_j; j++) {
+ if (iv[j] >= y_i && iv[j] <= y_j) syms.insert(iv[j]);
+ }
+ auto itr = syms.begin();
+ auto end = syms.end();
+ size_t r = 0;
+ while (itr != end) {
+ auto value = *itr;
+ ASSERT_EQ(value,uniq_values[r]);
+ r++;
+ itr++;
+ }
+ }
+}
+
+//! Test the load method and intersect
+TYPED_TEST(WtByteTest, restricted_unique_range_values)
+{
+ TypeParam wt;
+ test_range_unique_values<TypeParam>(wt);
+}
+
+
+template<class t_wt>
+void
+test_lex_count(typename std::enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // lex_count not implemented
+}
+
+template<class t_wt>
+void
+test_lex_count(typename std::enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ typedef typename t_wt::value_type value_type;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ if (wt.size()) {
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> distribution(0, wt.size());
+ auto dice = bind(distribution, rng);
+ for (size_type t=0; t<1000; ++t) {
+ size_type i = dice();
+ size_type j = dice();
+ if (j<i) {
+ std::swap(j,i);
+ }
+ std::vector<size_type> rank_c_i_n(256,0);
+ std::vector<size_type> rank_c_j_n(256,0);
+ for (size_type c=0; c<256; ++c) {
+ rank_c_i_n[c] = wt.rank(i,(value_type)c);
+ rank_c_j_n[c] = wt.rank(j,(value_type)c);
+ }
+ size_type num_i_s = 0;
+ size_type num_j_s = 0;
+ size_type num_c = 0;
+ size_type num_s = 0;
+ size_type num_g = j-i;
+ for (size_type c=0; c<256; ++c) {
+ // Test lex_count
+ num_s += num_c;
+ num_c = rank_c_j_n[c]-rank_c_i_n[c];
+ num_g -= num_c;
+ auto res = wt.lex_count(i, j, (value_type)c);
+ ASSERT_EQ(rank_c_i_n[c], std::get<0>(res));
+ ASSERT_EQ(num_s, std::get<1>(res));
+ ASSERT_EQ(num_g, std::get<2>(res));
+ // Test lex_smaller_count
+ auto res2 = wt.lex_smaller_count(i, (value_type)c);
+ ASSERT_EQ(rank_c_i_n[c], std::get<0>(res2)) << "lex_smaller_count(" << i << "," << c << ")";
+ ASSERT_EQ(num_i_s, std::get<1>(res2)) << "lex_smaller_count(" << i << "," << c << ")";
+ num_i_s += rank_c_i_n[c];
+ auto res3 = wt.lex_smaller_count(j, (value_type)c);
+ ASSERT_EQ(rank_c_j_n[c], std::get<0>(res3)) << "lex_smaller_count(" << i << "," << c << ")";
+ ASSERT_EQ(num_j_s, std::get<1>(res3)) << "lex_smaller_count(" << i << "," << c << ")";
+ num_j_s += rank_c_j_n[c];
+ }
+ }
+ }
+}
+
+//! Test lex_count method
+TYPED_TEST(WtByteTest, LexCount)
+{
+ TypeParam wt;
+ test_lex_count<TypeParam>(wt);
+}
+
+TYPED_TEST(WtByteTest, CreatePartiallyTest)
+{
+ int_vector_buffer<8> text_buf(test_file, std::ios::in, 1024*1024, 8, true);
+ int_vector<8> text;
+ ASSERT_TRUE(load_vector_from_file(text, test_file, 1));
+ size_type n = min(text.size(), (size_type)50);
+ text.resize(n);
+ TypeParam wt(text_buf, n);
+ compare_wt(text, wt);
+}
+
+TYPED_TEST(WtByteTest, DeleteTest)
+{
+ sdsl::remove(temp_file);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 3) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file temp_file [in-memory]" << endl;
+ cout << " (1) Generates a WT out of test_file; stores it in temp_file." << endl;
+ cout << " If `in-memory` is specified, the in-memory construction is tested." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_file = argv[2];
+ in_memory = argc > 3;
+ if (in_memory) {
+ int_vector<8> data;
+ load_vector_from_file(data, test_file, 1);
+ test_file = ram_file_name(test_file);
+ store_to_plain_array<uint8_t>(data, test_file);
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/test/WtIntTest.config b/test/WtIntTest.config
new file mode 100644
index 0000000..982f14a
--- /dev/null
+++ b/test/WtIntTest.config
@@ -0,0 +1,8 @@
+# Inputs which should be used in the WtIntTest.
+# Each line contains an ID and a path to a text.
+WT-EMPTY;test_cases/int-vec.0.1.0;
+WT-INT-1023-1-0;test_cases/int-vec.1023.1.0;
+WT-INT-100023-1-0;test_cases/int-vec.100023.1.0;
+WT-INT-64-2-0;test_cases/int-vec.64.2.0
+WT-INT-100000-18-R;test_cases/int-vec.100000.18.r;
+#WT-INT-10000000-18-R;test_cases/int-vec.10000000.18.r;
diff --git a/test/WtIntTest.cpp b/test/WtIntTest.cpp
new file mode 100644
index 0000000..9d4ce08
--- /dev/null
+++ b/test/WtIntTest.cpp
@@ -0,0 +1,865 @@
+#include "sdsl/wavelet_trees.hpp"
+#include "gtest/gtest.h"
+#include <vector>
+#include <string>
+#include <map>
+#include <queue>
+#include <algorithm>
+
+namespace
+{
+
+using namespace sdsl;
+using namespace std;
+
+typedef int_vector<>::size_type size_type;
+typedef map<int_vector<>::value_type,size_type> tMII;
+
+string test_file;
+string temp_file;
+bool in_memory;
+
+template<class T>
+class WtIntTest : public ::testing::Test { };
+
+using testing::Types;
+
+typedef Types<
+wt_blcd<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>
+ ,wt_huff<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>
+ ,wt_huff<rrr_vector<63>, rrr_vector<63>::rank_1_type, rrr_vector<63>::select_1_type, rrr_vector<63>::select_0_type, int_tree<>>
+ ,wt_hutu<bit_vector, rank_support_v<>, select_support_mcl<1>, select_support_mcl<0>, int_tree<>>
+ ,wt_gmr<>
+ ,wm_int<>
+ ,wt_int<>
+ ,wt_int<rrr_vector<15>>
+ ,wt_int<rrr_vector<63>>
+ ,wt_rlmn<bit_vector, rank_support_v5<>, select_support_mcl<1>, wt_int<>>
+ > Implementations;
+
+TYPED_TEST_CASE(WtIntTest, Implementations);
+
+//! Test the parametrized constructor
+TYPED_TEST(WtIntTest, Constructor)
+{
+ static_assert(sdsl::util::is_regular<TypeParam>::value, "Type is not regular");
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ double iv_size = size_in_mega_bytes(iv);
+ cout << "tc = " << test_file << endl;
+ {
+ TypeParam wt;
+ sdsl::construct(wt, test_file);
+ cout << "compression = " << size_in_mega_bytes(wt)/iv_size << endl;
+ ASSERT_EQ(iv.size(), wt.size());
+ set<uint64_t> sigma_set;
+ for (size_type j=0; j < iv.size(); ++j) {
+ ASSERT_EQ(iv[j], wt[j])<<j;
+ sigma_set.insert(iv[j]);
+ }
+ ASSERT_EQ(sigma_set.size(), wt.sigma);
+ ASSERT_TRUE(store_to_file(wt, temp_file));
+ }
+ {
+ int_vector_buffer<> iv_buf(test_file);
+ TypeParam wt(iv_buf, 0);
+ ASSERT_EQ((size_type)0, wt.size());
+ }
+ {
+ int_vector_buffer<> iv_buf(test_file);
+ size_type len = (iv.size() >= 6) ? 6 : iv.size();
+ TypeParam wt(iv_buf, len);
+ ASSERT_EQ(len, wt.size());
+ for (size_type j=0; j < len; ++j) {
+ ASSERT_EQ(iv[j], wt[j])<<j;
+ }
+ }
+}
+
+//! Test loading and accessing the wavelet tree
+TYPED_TEST(WtIntTest, LoadAndAccess)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ for (size_type j=0; j < iv.size(); ++j) {
+ ASSERT_EQ(iv[j], wt[j])<<j;
+ }
+}
+
+//! Test the load method and rank method
+TYPED_TEST(WtIntTest, LoadAndRank)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ tMII check_rank;
+ for (size_type j=0; j < iv.size(); ++j) {
+ ASSERT_EQ(wt.rank(j, iv[j]), check_rank[iv[j]]);
+ check_rank[iv[j]]++;
+ }
+ for (auto it=check_rank.begin(); it!=check_rank.end(); ++it) {
+ ASSERT_EQ(wt.rank(wt.size(), it->first), it->second);
+ }
+}
+
+//! Test the load method and rank method
+TYPED_TEST(WtIntTest, LoadAndMoveAndRank)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ TypeParam wt_load;
+ ASSERT_TRUE(load_from_file(wt_load, temp_file));
+ TypeParam wt = move(wt_load);
+ ASSERT_EQ(iv.size(), wt.size());
+ tMII check_rank;
+ for (size_type j=0; j < iv.size(); ++j) {
+ ASSERT_EQ(wt.rank(j, iv[j]), check_rank[iv[j]]);
+ check_rank[iv[j]]++;
+ }
+ for (auto it=check_rank.begin(); it!=check_rank.end(); ++it) {
+ ASSERT_EQ(wt.rank(wt.size(), it->first), it->second);
+ }
+}
+
+//! Test the load method and select method
+TYPED_TEST(WtIntTest, LoadAndSelect)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ tMII count;
+ for (size_type j=0; j < iv.size(); ++j) {
+ count[iv[j]]++;
+ ASSERT_EQ(j, wt.select(count[iv[j]], iv[j]))
+ << "iv[j]=" << iv[j] << " j="<<j;
+ }
+}
+
+//! Test the load method and select method
+TYPED_TEST(WtIntTest, LoadAndMoveAndSelect)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ TypeParam wt_load;
+ ASSERT_TRUE(load_from_file(wt_load, temp_file));
+ TypeParam wt = move(wt_load);
+ ASSERT_EQ(iv.size(), wt.size());
+ tMII count;
+ for (size_type j=0; j < iv.size(); ++j) {
+ count[iv[j]]++;
+ ASSERT_EQ(j, wt.select(count[iv[j]], iv[j]))
+ << "iv[j]=" << iv[j] << " j="<<j;
+ }
+}
+
+//! Test the load method and inverse_select method
+TYPED_TEST(WtIntTest, LoadAndInverseSelect)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ TypeParam wt;
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ tMII check_rank;
+ for (size_type j=0; j < iv.size(); ++j) {
+ auto rc = wt.inverse_select(j);
+ ASSERT_EQ(check_rank[iv[j]], rc.first);
+ ASSERT_EQ(iv[j], rc.second);
+ check_rank[iv[j]]++;
+ }
+}
+
+template<class t_wt>
+void
+test_interval_symbols(typename enable_if<!(has_node_type<t_wt>::value),
+ t_wt>::type&)
+{
+ // interval_symbols not implemented
+}
+
+template<class t_wt>
+void
+test_interval_symbols(typename enable_if<has_node_type<t_wt>::value,
+ t_wt>::type& wt)
+{
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+
+ size_type k = 0;
+ vector<size_type> rank_c_i(wt.sigma);
+ vector<size_type> rank_c_j(wt.sigma);
+ vector<int_vector<>::value_type> cs(wt.sigma);
+
+ mt19937_64 rng;
+ for (size_type n=1; n<4; ++n) {
+ uniform_int_distribution<uint64_t> distribution(0, n*n*n*10);
+ auto dice = bind(distribution, rng);
+ for (size_type i=0, j=0; i < wt.size(); i=j) {
+ j = min(wt.size(),i+dice());
+
+ interval_symbols(wt, i, j, k, cs, rank_c_i, rank_c_j);
+
+ size_type symbols = (j-i);
+ for (size_type m = 0; m<k; ++m) {
+ ASSERT_EQ(wt.rank(i, cs[m]), rank_c_i[m]);
+ ASSERT_EQ(wt.rank(j, cs[m]), rank_c_j[m]);
+ ASSERT_LT((size_type)0, rank_c_j[m]-rank_c_i[m]);
+ symbols -= (rank_c_j[m]-rank_c_i[m]);
+ if (m>0 and t_wt::lex_ordered) {
+ ASSERT_LT(cs[m-1],cs[m]);
+ }
+ }
+
+ ASSERT_EQ((size_type)0, symbols);
+ if (!t_wt::lex_ordered) {
+ sort(cs.begin(), cs.begin()+k);
+ for (size_type m=1; m<k; m++) {
+ ASSERT_LT(cs[m-1], cs[m]);
+ }
+ }
+ }
+ }
+}
+
+//! Test the load method and interval_symbols method
+TYPED_TEST(WtIntTest, LoadAndIntervalSymbols)
+{
+ TypeParam wt;
+ test_interval_symbols<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_lex_count(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // lex_count not implemented
+}
+
+template<class t_wt>
+void
+test_lex_count(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ mt19937_64 rng;
+ uint64_t min = numeric_limits<uint64_t>::max(), max = 0;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ }
+ uniform_int_distribution<uint64_t> symbol_distribution(min, max);
+ auto dice_symbol = bind(symbol_distribution, rng);
+ for (size_type k=1; k<4; ++k) {
+ uniform_int_distribution<uint64_t> distribution(0, k*k*k*10);
+ auto dice = bind(distribution, rng);
+ for (size_type idx=0; idx < iv.size();) {
+ size_type i = idx, j = std::min(wt.size(),i+dice());
+ size_type smaller_c1=0, greater_c1=0, smaller_c2=0, greater_c2=0;
+ int_vector<>::value_type c1=iv[i], c2=dice_symbol();
+ for (; idx<j; ++idx) {
+ if (iv[idx]<c1) ++smaller_c1;
+ if (iv[idx]>c1) ++greater_c1;
+ if (iv[idx]<c2) ++smaller_c2;
+ if (iv[idx]>c2) ++greater_c2;
+
+ }
+ auto res1 = wt.lex_count(i, j, c1);
+ ASSERT_EQ(wt.rank(i, c1), get<0>(res1));
+ ASSERT_EQ(smaller_c1, get<1>(res1));
+ ASSERT_EQ(greater_c1, get<2>(res1));
+
+ auto res2 = wt.lex_count(i, j, c2);
+ ASSERT_EQ(wt.rank(i, c2), get<0>(res2));
+ ASSERT_EQ(smaller_c2, get<1>(res2));
+ ASSERT_EQ(greater_c2, get<2>(res2));
+
+ auto res3 = wt.lex_count(i, j, max+1+dice_symbol());
+ ASSERT_EQ((size_type)0, get<0>(res3));
+ ASSERT_EQ(j-i, get<1>(res3));
+ ASSERT_EQ((size_type)0, get<2>(res3));
+ }
+ }
+}
+
+//! Test the load method and lex_count method
+TYPED_TEST(WtIntTest, LoadAndLexCount)
+{
+ TypeParam wt;
+ test_lex_count<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_lex_smaller_count(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // lex_smaller_count not implemented
+}
+
+template<class t_wt>
+void
+test_lex_smaller_count(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ mt19937_64 rng;
+ uint64_t min = numeric_limits<uint64_t>::max(), max = 0;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ }
+ uniform_int_distribution<uint64_t> symbol_distribution(min, max);
+ auto dice_symbol = bind(symbol_distribution, rng);
+ int_vector<> chars(3);
+ for (size_type idx=0; idx < iv.size(); ++idx) {
+ chars[0] = iv[idx];
+ chars[1] = dice_symbol();
+ chars[2] = max+1+dice_symbol();
+
+ for (uint64_t i = 0; i<chars.size(); ++i) {
+ auto exp = wt.lex_count(0, idx, chars[i]);
+ auto res = wt.lex_smaller_count(idx, chars[i]);
+ ASSERT_EQ(idx-get<2>(exp)-get<1>(exp), get<0>(res));
+ ASSERT_EQ(get<1>(exp), get<1>(res));
+ }
+ }
+}
+
+//! Test the load method and lex_smaller_count method
+TYPED_TEST(WtIntTest, LoadAndLexSmallerCount)
+{
+ TypeParam wt;
+ test_lex_smaller_count<TypeParam>(wt);
+}
+
+
+template<class t_wt>
+void
+test_range_search_2d(typename enable_if<!(has_range_search_2d<t_wt>::value),
+ t_wt>::type&) {}
+
+template<class t_wt>
+void
+test_range_search_2d(typename enable_if<has_range_search_2d<t_wt>::value,
+ t_wt>::type& wt)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+
+ if (wt.size() == 0)
+ return;
+
+ vector<uint64_t> buf(100);
+ vector<uint64_t> unique_buf(buf.size());
+
+ mt19937_64 rng;
+ uniform_int_distribution<uint64_t> range_distr(0, wt.size()-1);
+ auto dice_range = bind(range_distr, rng);
+
+ uniform_int_distribution<uint64_t> rank_distr(0, buf.size());
+ auto dice_rank = bind(rank_distr, rng);
+
+ for (size_type n=0; n<1000; ++n) {
+ size_type lb = dice_range();
+ size_type rb = lb+buf.size()-1;
+ rb = (rb >= wt.size()) ? wt.size()-1 : rb;
+
+ auto buf_end = copy(iv.begin()+lb, iv.begin()+rb+1, buf.begin());
+ sort(buf.begin(), buf_end);
+ auto unique_end = unique_copy(buf.begin(), buf_end,
+ unique_buf.begin());
+ size_type r1 = dice_rank() % (unique_end - unique_buf.begin());
+ size_type r2 = dice_rank() % (unique_end - unique_buf.begin());
+ if (r1 > r2)
+ swap(r1, r2);
+ auto vlb = unique_buf[r1];
+ auto vrb = unique_buf[r2];
+
+ size_t cnt = upper_bound(buf.begin(), buf_end, vrb) -
+ lower_bound(buf.begin(), buf_end, vlb);
+
+ auto res = wt.range_search_2d(lb, rb, vlb, vrb);
+ ASSERT_EQ(cnt, res.first);
+
+ for (auto point : res.second) {
+ // check that position is in range
+ ASSERT_TRUE(point.first >= lb);
+ ASSERT_TRUE(point.first <= rb);
+ // check that value is in range
+ ASSERT_TRUE(point.second >= vlb);
+ ASSERT_TRUE(point.second <= vrb);
+ // check that in the original data
+ ASSERT_EQ(iv[point.first], point.second);
+ }
+ }
+}
+
+//! Test the load method and range_search_2d
+TYPED_TEST(WtIntTest, RangeSearch2d)
+{
+ TypeParam wt;
+ test_range_search_2d<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_quantile_freq(typename enable_if<!t_wt::lex_ordered, t_wt>::type&) {}
+
+template<class t_wt>
+void
+test_quantile_freq(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+
+ if (wt.size() == 0)
+ return;
+
+ vector<uint64_t> buf(100);
+
+ mt19937_64 rng;
+ uniform_int_distribution<uint64_t> range_distr(0, wt.size()-1);
+ auto dice_lb = bind(range_distr, rng);
+
+ uniform_int_distribution<uint64_t> rank_distr(1, buf.size());
+ auto dice_range = bind(rank_distr, rng);
+
+ for (size_type n=0; n<1000; ++n) {
+ size_type lb = dice_lb();
+ size_type rb = lb+dice_range()-1;
+ rb = (rb >= wt.size()) ? wt.size()-1 : rb;
+
+ auto buf_end = copy(iv.begin()+lb, iv.begin()+rb+1, buf.begin());
+ sort(buf.begin(), buf_end);
+
+ for (auto it = buf.begin(); it!=buf_end; ++it) {
+ auto val = *it;
+ size_type freq = upper_bound(buf.begin(), buf_end, val) -
+ lower_bound(buf.begin(), buf_end, val);
+ size_type q = it - buf.begin();
+ auto res = quantile_freq(wt, lb, rb, q);
+ ASSERT_EQ(val, res.first);
+ ASSERT_EQ(freq, res.second);
+ }
+ }
+}
+
+//! Test the load method and quantile_freq
+TYPED_TEST(WtIntTest, QuantileFreq)
+{
+ TypeParam wt;
+ test_quantile_freq<TypeParam>(wt);
+}
+
+
+template<class t_wt>
+void
+test_intersect(typename enable_if<!(has_node_type<t_wt>::value),t_wt>::type&)
+{
+ // intersect not implemented
+}
+
+template<class t_wt>
+void
+test_intersect(typename enable_if<has_node_type<t_wt>::value,t_wt>::type& wt)
+{
+ using t_pvs = pair<typename t_wt::value_type,
+ typename t_wt::size_type>;
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+
+ if (wt.size() == 0)
+ return;
+
+ vector<vector<uint64_t>> buf(2, vector<uint64_t>(300));
+ vector<uint64_t> res_buf(buf[0].size()*2);
+ vector<vector<uint64_t>::iterator> buf_end(2);
+
+ mt19937_64 rng;
+ uniform_int_distribution<uint64_t> range_distr(0, wt.size()-1);
+ auto dice_lb = bind(range_distr, rng);
+
+ uniform_int_distribution<uint64_t> rank_distr(1, buf[0].size()-1);
+ auto dice_range = bind(rank_distr, rng);
+
+ for (size_type n=0; n<1000; ++n) {
+ range_vec_type ranges;
+
+ for (size_t i=0; i<2; ++i) {
+ size_type lb = dice_lb();
+ size_type rb = lb+dice_range()-1;
+ rb = (rb >= wt.size()) ? wt.size()-1 : rb;
+ ranges.emplace_back(lb,rb);
+ buf_end[i] = copy(iv.begin()+lb,
+ iv.begin()+rb+1, buf[i].begin());
+ sort(buf[i].begin(), buf_end[i]);
+ }
+
+ auto res_end =
+ set_intersection(buf[0].begin(), buf_end[0],
+ buf[1].begin(), buf_end[1],
+ res_buf.begin());
+ res_end = unique(res_buf.begin(), res_end);
+
+ auto itsct = intersect(wt, ranges);
+ size_type res_size = res_end-res_buf.begin();
+ ASSERT_EQ(res_size, itsct.size());
+ if (!t_wt::lex_ordered) {
+ sort(itsct.begin(), itsct.end(), [](const t_pvs& x, const t_pvs& y) {
+ return x.first < y.first;
+ });
+ }
+ for (size_t i=0; i< itsct.size(); ++i) {
+ ASSERT_EQ(res_buf[i], itsct[i].first);
+ }
+ }
+}
+
+//! Test the load method and intersect
+TYPED_TEST(WtIntTest, intersect)
+{
+ TypeParam wt;
+ test_intersect<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_nodes(typename enable_if<!(has_node_type<t_wt>::value),t_wt>::type&)
+{
+ // not implemented
+}
+
+template<class t_wt>
+void
+test_nodes(typename enable_if<has_node_type<t_wt>::value,t_wt>::type& wt)
+{
+ using node_type = typename t_wt::node_type;
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ if (wt.size() < 1)
+ return;
+ std::vector<node_type> v;
+ {
+ std::queue<node_type> q;
+ q.push(wt.root());
+ while (!q.empty() and v.size() < 100000) {
+ node_type x = q.front();
+ q.pop();
+ if (!wt.is_leaf(x)) {
+ auto children = wt.expand(x);
+ if (!wt.empty(std::get<0>(children)))
+ q.emplace(std::get<0>(children));
+ if (!wt.empty(std::get<1>(children)))
+ q.emplace(std::get<1>(children));
+ }
+ v.push_back(x);
+ }
+ }
+ std::sort(v.begin(), v.end());
+ for (size_t i=1; i<v.size(); ++i) {
+ ASSERT_TRUE(v[i-1] < v[i]);
+ }
+}
+
+//! Test the load method and nodes
+TYPED_TEST(WtIntTest, nodes)
+{
+ TypeParam wt;
+ test_nodes<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_symbol_gte(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // symbol_gte not implemented
+}
+
+template<class t_wt>
+void
+test_symbol_gte(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ mt19937_64 rng;
+ uint64_t min = numeric_limits<uint64_t>::max(), max = 0;
+ std::set<uint64_t> syms;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ syms.insert(iv[j]);
+ }
+
+ if (iv.size() == 0) {
+ return;
+ }
+
+ // check symbols that are in there also are reported as "equal"
+ auto itr = syms.begin();
+ auto end = syms.end();
+ while (itr != end) {
+ auto value = *itr;
+ auto ret = symbol_gte(wt,value);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(value,ret.second);
+ ++itr;
+ }
+
+ // check symbols symbols that are smaller than than min
+ for (size_t i=0; i<min; i++) {
+ auto ret = symbol_gte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,min);
+ }
+
+ // check symbols that are largest than max
+ for (size_t i=max+100; i>max; i--) {
+ auto ret = symbol_gte(wt,i);
+ ASSERT_FALSE(ret.first);
+ }
+
+ // check values in between that do not exist
+ for (size_t i=min; i<max; i++) {
+ auto itr = syms.find(i);
+ if (itr == syms.end()) {
+ size_t j=i+1;
+ auto next = syms.find(j);
+ while (next == syms.end()) {
+ next = syms.find(j+1);
+ j++;
+ }
+ if (next != syms.end()) {
+ auto next_val = *next;
+ auto ret = symbol_gte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,next_val);
+ }
+ }
+ }
+}
+
+//! Test the load method and symbol_gte
+TYPED_TEST(WtIntTest, symbol_gte)
+{
+ TypeParam wt;
+ test_symbol_gte<TypeParam>(wt);
+}
+
+template<class t_wt>
+void
+test_symbol_lte(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // symbol_lte not implemented
+}
+
+
+
+template<class t_wt>
+void
+test_symbol_lte(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ mt19937_64 rng;
+ uint64_t min = numeric_limits<uint64_t>::max(), max = 0;
+ std::set<uint64_t> syms;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ syms.insert(iv[j]);
+ }
+
+ if (iv.size() == 0) {
+ return;
+ }
+
+ // check symbols that are in there also are reported as "equal"
+ auto itr = syms.begin();
+ auto end = syms.end();
+ while (itr != end) {
+ auto value = *itr;
+ auto ret = symbol_lte(wt,value);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(value,ret.second);
+ ++itr;
+ }
+
+ // check symbols symbols that are smaller than than min
+ for (size_t i=0; i<min; i++) {
+ auto ret = symbol_lte(wt,i);
+ ASSERT_FALSE(ret.first);
+ //ASSERT_EQ(ret.second,min);
+ }
+
+ // check symbols that are larget than max
+ for (size_t i=max+100; i>max; i--) {
+ auto ret = symbol_lte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,max);
+ }
+
+ // check values in between that do not exist
+ for (size_t i=min+1; i<max; i++) {
+ auto itr = syms.find(i);
+ if (itr == syms.end()) {
+ size_t j=i-1;
+ auto prev = syms.find(j);
+ while (prev == syms.end()) {
+ prev = syms.find(j-1);
+ j--;
+ }
+ if (prev != syms.end()) {
+ auto prev_val = *prev;
+ auto ret = symbol_lte(wt,i);
+ ASSERT_TRUE(ret.first);
+ ASSERT_EQ(ret.second,prev_val);
+ }
+ }
+ }
+}
+
+
+//! Test the load method and symbol_lte
+TYPED_TEST(WtIntTest, symbol_lte)
+{
+ TypeParam wt;
+ test_symbol_lte<TypeParam>(wt);
+}
+
+
+template<class t_wt>
+void
+test_range_unique_values(typename enable_if<!(t_wt::lex_ordered), t_wt>::type&)
+{
+ // test_range_unique_values not implemented
+}
+
+template<class t_wt>
+void
+test_range_unique_values(typename enable_if<t_wt::lex_ordered, t_wt>::type& wt)
+{
+ using value_type = typename t_wt::value_type;
+ int_vector<> iv;
+ load_from_file(iv, test_file);
+ ASSERT_TRUE(load_from_file(wt, temp_file));
+ ASSERT_EQ(iv.size(), wt.size());
+ value_type min = numeric_limits<value_type>::max(), max = 0;
+ std::set<value_type> syms;
+ for (size_type j=0; j < iv.size(); ++j) {
+ if (min>iv[j]) min = iv[j];
+ if (max<iv[j]) max = iv[j];
+ syms.insert(iv[j]);
+ }
+
+ if (iv.size() == 0) {
+ return;
+ }
+
+ // try 128 random queries
+ std::mt19937_64 rng;
+ std::uniform_int_distribution<uint64_t> x_dist(0, wt.size()-1);
+ std::uniform_int_distribution<uint64_t> y_dist(0, max);
+ auto xdice = bind(x_dist, rng);
+ auto ydice = bind(y_dist, rng);
+ for (size_t i=0; i<128; i++) {
+ size_t x_i = xdice();
+ size_t x_j = xdice();
+ if (x_i>x_j) std::swap(x_i,x_j);
+ size_t y_i = ydice();
+ size_t y_j = ydice();
+ if (y_i>y_j) std::swap(y_i,y_j);
+ auto uniq_values = restricted_unique_range_values(wt,x_i,x_j,y_i,y_j);
+
+ /* verify */
+ std::set<value_type> syms;
+ for (size_t j=x_i; j<=x_j; j++) {
+ if (iv[j] >= y_i && iv[j] <= y_j) syms.insert(iv[j]);
+ }
+ auto itr = syms.begin();
+ auto end = syms.end();
+ size_t r = 0;
+ while (itr != end) {
+ auto value = *itr;
+ ASSERT_EQ(value,uniq_values[r]);
+ r++;
+ itr++;
+ }
+ }
+
+ // check invalid queries don't do the wrong thing
+ // 0 1 2 3 4 5 6 7 8 9 10
+ int_vector<> S = {5,6,7,8,9,5,6,7,13,14,15};
+ t_wt wt_test;
+ construct_im(wt_test,S);
+ auto empty_uniq_values = restricted_unique_range_values(wt,8,3,7,9);
+ ASSERT_TRUE(empty_uniq_values.size() == 0);
+ empty_uniq_values = restricted_unique_range_values(wt,3,8,9,7);
+ ASSERT_TRUE(empty_uniq_values.size() == 0);
+ empty_uniq_values = restricted_unique_range_values(wt,3,8,3,4);
+ ASSERT_TRUE(empty_uniq_values.size() == 0);
+ empty_uniq_values = restricted_unique_range_values(wt,3,8,10,11);
+ ASSERT_TRUE(empty_uniq_values.size() == 0);
+}
+
+//! Test the load method and restricted_unique_range_values
+TYPED_TEST(WtIntTest, restricted_unique_range_values)
+{
+ TypeParam wt;
+ test_range_unique_values<TypeParam>(wt);
+}
+
+
+
+TYPED_TEST(WtIntTest, DeleteTest)
+{
+ sdsl::remove(temp_file);
+}
+
+} // namespace
+
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 3) {
+ // LCOV_EXCL_START
+ cout << "Usage: " << argv[0] << " test_file temp_file [in-memory]" << endl;
+ cout << " (1) Generates a WT out of test_file; stores it in temp_file." << endl;
+ cout << " If `in-memory` is specified, the in-memory construction is tested." << endl;
+ cout << " (2) Performs tests." << endl;
+ cout << " (3) Deletes temp_file." << endl;
+ return 1;
+ // LCOV_EXCL_STOP
+ }
+ test_file = argv[1];
+ temp_file = argv[2];
+ in_memory = argc > 3;
+ if (in_memory) {
+ int_vector<> data;
+ load_from_file(data, test_file);
+ test_file = ram_file_name(test_file);
+ store_to_file(data, test_file);
+ temp_file = ram_file_name(temp_file);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/test/coverage/.gitignore b/test/coverage/.gitignore
new file mode 100644
index 0000000..3b6badb
--- /dev/null
+++ b/test/coverage/.gitignore
@@ -0,0 +1,5 @@
+*
+!README.md
+!clean.sh
+!run.sh
+!.gitignore
diff --git a/test/coverage/README.md b/test/coverage/README.md
new file mode 100644
index 0000000..46e4403
--- /dev/null
+++ b/test/coverage/README.md
@@ -0,0 +1,18 @@
+# Code coverage of tests
+
+This directory contains a script which generates statistics
+about the code coverage of the tests.
+
+A call of `./run.sh` will compile all tests with code coverage
+parameters and execute all tests to gather the information.
+
+
+## Prerequisites
+
+ * The GCC utility [gcov][GCOV] has to be installed and
+ `g++` has to be used as compiler.
+ * The HTML output is generated by the [lcov][LCOV] tool.
+
+
+[GCOV]: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html "gcov"
+[LCOV]: http://ltp.sourceforge.net/coverage/lcov.php "lcov"
diff --git a/test/coverage/clean.sh b/test/coverage/clean.sh
new file mode 100755
index 0000000..8ad9c1c
--- /dev/null
+++ b/test/coverage/clean.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# activate globbing
+shopt -s extglob
+# removes all but the listed files in the directory
+# and subdirectories
+rm -rf !(run.sh|clean.sh|.gitignore|README.md)
+
diff --git a/test/coverage/run.sh b/test/coverage/run.sh
new file mode 100755
index 0000000..202fc97
--- /dev/null
+++ b/test/coverage/run.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+CUR_DIR=`pwd`
+cd "${CUR_DIR}"
+OLD_DIR="$( cd "$( dirname "$0" )" && pwd )" # gets the directory where the script is located in
+cd "${OLD_DIR}"
+OLD_DIR=`pwd`
+
+lcov --directory .. --zerocounters
+
+cd ..
+make clean
+make CODE_COVER="-g -fprofile-arcs -ftest-coverage -lgcov" $1
+MAKERET=$?
+cd ${OLD_DIR}
+
+if [ ${MAKERET} != 0 ]; then
+ echo "ERROR: tests failed."
+ exit 1
+fi
+
+INC_STR=`grep 'INC_DIR = ' ../../Make.helper`
+INC_DIR=${INC_STR#INC_DIR = }
+
+lcov -d .. -d ${INC_DIR}/sdsl --no-recursion --no-external --capture --output-file sdsl-lite.info
+genhtml -o output --legend sdsl-lite.info
diff --git a/test/download.config b/test/download.config
new file mode 100644
index 0000000..c1a5093
--- /dev/null
+++ b/test/download.config
@@ -0,0 +1,4 @@
+# [TC_PATH];[TC_DOWNLOAD_URL]
+test_cases/faust.txt;http://people.eng.unimelb.edu.au/sgog/data/faust.txt.gz
+test_cases/zarathustra.txt;http://people.eng.unimelb.edu.au/sgog/data/zarathustra.txt.gz
+test_cases/moby.int;http://people.eng.unimelb.edu.au/sgog/data/moby.int.gz
diff --git a/test/test_cases/.gitignore b/test/test_cases/.gitignore
new file mode 100644
index 0000000..e9641a0
--- /dev/null
+++ b/test/test_cases/.gitignore
@@ -0,0 +1,11 @@
+*
+!100a.txt
+!README.md
+!abc_abc_abc.txt
+!abc_abc_abc2.txt
+!empty.txt
+!example01.txt
+!keeper.int
+!one_byte.txt
+!all_symbols.txt
+!.gitignore
diff --git a/test/test_cases/100a.txt b/test/test_cases/100a.txt
new file mode 100644
index 0000000..d690765
--- /dev/null
+++ b/test/test_cases/100a.txt
@@ -0,0 +1 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
\ No newline at end of file
diff --git a/test/test_cases/README.md b/test/test_cases/README.md
new file mode 100644
index 0000000..790ea5b
--- /dev/null
+++ b/test/test_cases/README.md
@@ -0,0 +1,7 @@
+# Test inputs
+
+This directory contains some small inputs and will
+be populated by larger inputs when running the
+all tests.
+
+TODO: describe what the ending of the files mean.
diff --git a/test/test_cases/abc_abc_abc.txt b/test/test_cases/abc_abc_abc.txt
new file mode 100644
index 0000000..ec7761c
Binary files /dev/null and b/test/test_cases/abc_abc_abc.txt differ
diff --git a/test/test_cases/abc_abc_abc2.txt b/test/test_cases/abc_abc_abc2.txt
new file mode 100644
index 0000000..ec7761c
Binary files /dev/null and b/test/test_cases/abc_abc_abc2.txt differ
diff --git a/test/test_cases/all_symbols.txt b/test/test_cases/all_symbols.txt
new file mode 100644
index 0000000..c866266
Binary files /dev/null and b/test/test_cases/all_symbols.txt differ
diff --git a/test/test_cases/empty.txt b/test/test_cases/empty.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test/test_cases/example01.txt b/test/test_cases/example01.txt
new file mode 100644
index 0000000..1f4f5fe
--- /dev/null
+++ b/test/test_cases/example01.txt
@@ -0,0 +1 @@
+mississippi
diff --git a/test/test_cases/keeper.int b/test/test_cases/keeper.int
new file mode 100644
index 0000000..105d98d
Binary files /dev/null and b/test/test_cases/keeper.int differ
diff --git a/test/test_cases/one_byte.txt b/test/test_cases/one_byte.txt
new file mode 100644
index 0000000..2e65efe
--- /dev/null
+++ b/test/test_cases/one_byte.txt
@@ -0,0 +1 @@
+a
\ No newline at end of file
diff --git a/test/tmp/.gitignore b/test/tmp/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/test/tmp/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/tutorial/.gitignore b/tutorial/.gitignore
new file mode 100644
index 0000000..37a28a8
--- /dev/null
+++ b/tutorial/.gitignore
@@ -0,0 +1 @@
+*.x
diff --git a/tutorial/Makefile b/tutorial/Makefile
new file mode 100644
index 0000000..d09aea6
--- /dev/null
+++ b/tutorial/Makefile
@@ -0,0 +1,17 @@
+include ../Make.helper
+CXX_FLAGS=$(MY_CXX_FLAGS) $(MY_CXX_OPT_FLAGS) -I$(INC_DIR) -L$(LIB_DIR)
+CCLIB=-lsdsl -ldivsufsort -ldivsufsort64
+SOURCES=$(wildcard *.cpp)
+EXECS=$(SOURCES:.cpp=.x)
+
+all: $(EXECS)
+
+build-test: $(EXECS)
+
+%.x:%.cpp
+ $(MY_CXX) $(CXX_FLAGS) -o $@ $< $(CCLIB)
+
+clean:
+ rm -f $(EXECS)
+ rm -rf *.dSYM
+
diff --git a/tutorial/cst-search.cpp b/tutorial/cst-search.cpp
new file mode 100644
index 0000000..c6c64c4
--- /dev/null
+++ b/tutorial/cst-search.cpp
@@ -0,0 +1,90 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+
+template<class t_cst, class t_pat=typename t_cst::string_type>
+void execute(const char* input, uint8_t num_bytes, t_pat pat, const char* format)
+{
+ typedef typename t_cst::node_type node_t;
+ t_cst cst;
+ construct_im(cst, input, num_bytes);
+ csXprintf(cout, format, cst);
+
+ cout << "pattern \"" << pat << "\"" << endl;
+ cout << "---- backward search step by step ----" << endl;
+ {
+ uint64_t lb=0, rb=cst.size()-1;
+ for (auto it=pat.end(); it != pat.begin() and lb <= rb;) {
+ --it;
+ if (backward_search(cst.csa, lb, rb, (typename t_cst::char_type)*it, lb, rb) > 0) {
+ cout << "[" << lb << "," << rb << "]" << endl;
+ cout << "matched " << *it << endl;
+ }
+ }
+ }
+
+ cout << "---- backward search for the pattern ----" << endl;
+ {
+ uint64_t lb=0, rb=cst.size()-1;
+ backward_search(cst.csa, lb, rb, pat.begin(), pat.end(), lb, rb);
+ cout << "size = " << rb+1-lb << endl;
+ }
+ cout << "---- count pattern occurrences ----" << endl;
+ {
+ cout << "count(cst.csa, \"" << pat << "\")=" << count(cst.csa, pat) << endl;
+ }
+ cout << "---- locate the pattern ----" << endl;
+ {
+ auto occs = locate(cst.csa, pat);
+ cout << "locate(cst.csa, \"" << pat << "\")=" << occs.size() << endl;
+ cout << occs << endl;
+ cout << endl;
+ }
+ cout << "---- extract text ----" << endl;
+ {
+ cout << "extract(csa,0,csa.size())=\"" << extract(cst.csa, 0, cst.csa.size()-1) << "\"" << endl;
+ }
+
+ cout << "---- forward search step by step ----" << endl;
+ {
+ node_t v = cst.root();
+ auto it = pat.begin();
+ for (uint64_t char_pos=0; it != pat.end(); ++it) {
+ if (forward_search(cst, v, it-pat.begin(), *it, char_pos) > 0) {
+ cout << it-pat.begin() << "-[" << cst.lb(v) << "," << cst.rb(v) << "]" << endl;
+ cout << "matched " << *it << endl;
+ } else {
+ break;
+ }
+ }
+ }
+ cout << "---- count pattern occurrences ----" << endl;
+ {
+ cout << "count(cst, \"" << pat << "\")=" << count(cst, pat) << endl;
+ }
+ cout << "---- extract text ----" << endl;
+ {
+ cout << "extract(cst,cst.select_leaf(cst.csa.isa[0]+1))=\""
+ << extract(cst, cst.select_leaf(cst.csa.isa[0]+1)) << "\"" << endl;
+ }
+
+}
+
+
+int main()
+{
+ {
+ cout << "# Byte alphabet example\n" << endl;
+ execute<cst_sct3<> >("abracadabra#bracda", 1, string("brac"), "%2I %3S %T");
+ cout << "\n\n" << endl;
+ }
+
+ {
+ cout << "# Integer alphabet example\n" << endl;
+ execute<cst_sct3<csa_bitcompressed<int_alphabet<> > > >("2 801 543 293 597 801 444 444 293", 'd', {801, 444}, "%2I %3S %:4T");
+ }
+}
diff --git a/tutorial/cst-traversal.cpp b/tutorial/cst-traversal.cpp
new file mode 100644
index 0000000..cb04dc0
--- /dev/null
+++ b/tutorial/cst-traversal.cpp
@@ -0,0 +1,26 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+#include <string>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int, char* argv[])
+{
+ cst_sct3<> cst;
+ construct(cst, argv[1], 1);
+ uint64_t max_depth = stoull(argv[2]);
+
+ // use the DFS iterator to traverse `cst`
+ for (auto it=cst.begin(); it!=cst.end(); ++it) {
+ if (it.visit() == 1) { // node visited the first time
+ auto v = *it; // get the node by dereferencing the iterator
+ if (cst.depth(v) <= max_depth) { // if depth node is <= max_depth
+ // process node, e.g. output it in format d-[lb, rb]
+ cout<<cst.depth(v)<<"-["<<cst.lb(v)<< ","<<cst.rb(v)<<"]"<<endl;
+ } else { // skip the subtree otherwise
+ it.skip_subtree();
+ }
+ }
+ }
+}
diff --git a/tutorial/csx-printf.cpp b/tutorial/csx-printf.cpp
new file mode 100644
index 0000000..53a2ed2
--- /dev/null
+++ b/tutorial/csx-printf.cpp
@@ -0,0 +1,75 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+std::string format("%3I%3S %3s %3P %3p %3L %3B %T");
+std::string header(" i SA ISA PSI LF LCP BWT TEXT");
+static const std::streamsize BUF_SIZE=4096;
+char line[BUF_SIZE];
+
+
+typedef csa_bitcompressed<int_alphabet<> > csa_int_t;
+typedef cst_sct3<> cst_byte_t;
+typedef cst_sct3<csa_int_t> cst_int_t;
+
+void print_usage(const char* command)
+{
+ cout << "\
+A pretty printer for suffix array/tree members.\n\
+Transforms each input line into a CST and outputs\n\
+formatted suffix array/tree members.\n\
+Usage: " << command << " X \"[FORMAT]\" \"[HEADER]\" \"[SENTINEL]\"\n\
+X : Input is interpreted dependent on X.\n\
+ X=1: byte sequence.\n\
+ X=d: sequence of decimal numbers.\n\
+FORMAT : Format string. Default=`" << format << "`.\n\
+HEADER : Header string. Default=`" << header <<"`.\n\
+SENTINEL: Sentinel character. \n\
+\n\
+Each line of the output will be formatted according to the format string.\
+All content, except tokens which start with `%` will be copied. Tokens\
+which start with `%` will be replaced as follows (let w be a positive\
+number. setw(w) is used to format single numbers):\
+\n\
+Token | Replacement | Comment\n\
+-----------------------------------------------------------------------\n\
+ %[w]I | Row index i. | \n\
+ %[w]S | SA[i] | \n\
+ %[w]s | ISA[i] | \n\
+ %[w]P | PSI[i] | \n\
+ %[w]p | LF[i] | \n\
+ %[w]L | LCP[i] | only for CSTs \n\
+ %[w]B | BWT[i] | \n\
+ %[w[:W]]T | Print min(idx.size(),w) chars of each | \n\
+ | suffix, each char formatted by setw(W).| \n\
+ %% | % | \n";
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2 or !('1' == argv[1][0] or 'd'==argv[1][0])) {
+ print_usage(argv[0]);
+ return 1;
+ }
+ if (argc > 2) {
+ format = argv[2];
+ }
+ if (argc > 3) {
+ header = argv[3];
+ }
+ while (cin.getline(line, BUF_SIZE)) {
+ cout << header << endl;
+ if ('1' == argv[1][0]) {
+ cst_byte_t cst;
+ construct_im(cst, (const char*)line, 1);
+ csXprintf(cout, format, cst, ((argc > 4) ? argv[4][0] : '$'));
+ } else if ('d' == argv[1][0]) {
+ cst_int_t cst;
+ construct_im(cst, (const char*)line, 'd');
+ csXprintf(cout, format, cst, ((argc > 4) ? argv[4][0] : '0'));
+ }
+ cout << endl;
+ }
+}
diff --git a/tutorial/document_listing/Makefile b/tutorial/document_listing/Makefile
new file mode 100644
index 0000000..6f40521
--- /dev/null
+++ b/tutorial/document_listing/Makefile
@@ -0,0 +1,20 @@
+include ../../Make.helper
+CXX_FLAGS=$(MY_CXX_FLAGS) $(MY_CXX_OPT_FLAGS) -I$(INC_DIR) -L$(LIB_DIR)
+CCLIB=-lsdsl -ldivsufsort -ldivsufsort64
+EXECS=doc_list_index_sada.x
+
+all: $(EXECS)
+
+build-test: $(EXECS)
+
+doc_list_index_sada.x: doc_list_index.cpp doc_list_index_sada.hpp
+ $(MY_CXX) \
+ $(CXX_FLAGS)\
+ -DIDX_TYPE="doc_list_index_sada<>" \
+ -DIDX_SUF=".sada-idx" \
+ -o $@ $< $(CCLIB)
+
+clean:
+ rm -f $(EXECS)
+ rm -rf *.dSYM
+
diff --git a/tutorial/document_listing/doc_list_index.cpp b/tutorial/document_listing/doc_list_index.cpp
new file mode 100644
index 0000000..b52a916
--- /dev/null
+++ b/tutorial/document_listing/doc_list_index.cpp
@@ -0,0 +1,84 @@
+#include "doc_list_index.hpp"
+#include <iostream>
+#include <chrono>
+#include <algorithm>
+
+using namespace std;
+using namespace sdsl;
+
+using idx_type = IDX_TYPE;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[0] << " collection_file" << endl;
+ return 1;
+ }
+ string collection_file = string(argv[1]);
+ idx_type idx;
+ string idx_file = collection_file + SDSL_XSTR(IDX_SUF);
+ cout<<"idx_file="<<idx_file<<endl;
+
+
+ using timer = std::chrono::high_resolution_clock;
+
+ if (!load_from_file(idx, idx_file)) {
+ cout << "Generate index for " << collection_file << endl;
+ {
+ auto start = timer::now();
+ idx_type temp_idx(collection_file, 1);
+ auto stop = timer::now();
+ auto elapsed = stop-start;
+ std::cout << "construction time = " << std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << std::endl;
+ store_to_file(temp_idx, idx_file);
+ ofstream out(idx_file+".html");
+ write_structure<HTML_FORMAT>(temp_idx, out);
+ }
+ load_from_file(idx, idx_file);
+ } else {
+ cout << "Loaded index from " << collection_file << endl;
+ }
+
+ using timer = std::chrono::high_resolution_clock;
+ char buffer[64];
+ size_t q_len = 0;
+ size_t q_cnt = 0;
+ size_t sum = 0;
+ size_t sum_fdt = 0;
+ auto start = timer::now();
+ while (cin.getline(buffer, 64)) {
+ typename idx_type::result res;
+ string query(buffer);
+ if (q_len != query.size()) {
+ if (q_len == 0) {
+ start = timer::now();
+ } else {
+ auto stop = timer::now();
+ auto elapsed = stop-start;
+ cout<<q_len<<" "
+ <<std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()/q_cnt << endl;
+
+
+ start = timer::now();
+ q_cnt = 0;
+ }
+ q_len = query.size();
+ }
+ ++q_cnt;
+ size_t x = idx.search(query.begin(), query.end(), res, 10);
+ sum += x;
+ for (auto& r : res) {
+ sum_fdt += r.second;
+// cout << " " << r.first << " " << r.second << endl;
+ }
+// if (res.size()==0){
+// cout<<" empty"<<endl;
+// }
+// cout << " (" << x << ")"<< endl;
+ }
+ auto stop = timer::now();
+ auto elapsed = stop-start;
+ std::cout<<q_len<<" "<<std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()/q_cnt << std::endl;
+
+ cerr << "sum = " << sum << " sum f_dt = " << sum_fdt << endl;
+}
diff --git a/tutorial/document_listing/generate_collection.py b/tutorial/document_listing/generate_collection.py
new file mode 100644
index 0000000..27b0325
--- /dev/null
+++ b/tutorial/document_listing/generate_collection.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+
+import fnmatch
+import sys
+import os
+import re
+
+includes = ['*.cpp','*.hpp'] # sources only
+includes = r'|'.join([fnmatch.translate(x) for x in includes])
+
+collection_path = "collection.txt"
+
+def main():
+
+ if len(sys.argv) == 1:
+ print "Usage ./", sys.argv[0], "directory"
+ sys.exit(0)
+ cur_dir = sys.argv[1]
+ doc_paths = []
+ for root, dirs, files in os.walk(cur_dir):
+ files = [f for f in files if re.match(includes, f)]
+ for f in files:
+ doc_path = root+"/"+f
+ doc_paths.append(doc_path)
+
+ print "Found ", len(doc_paths), "source files in", cur_dir
+ collection_f = open(collection_path,'w')
+ for doc_path in doc_paths:
+ f = open(doc_path, 'r')
+ content = f.read()
+ collection_f.write(content)
+ collection_f.write('\1')
+
+if __name__ == '__main__':
+ main()
diff --git a/tutorial/expl-01.cpp b/tutorial/expl-01.cpp
new file mode 100644
index 0000000..a37da70
--- /dev/null
+++ b/tutorial/expl-01.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+#include <sdsl/vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ int_vector<> v = {3,2,1,0,2,1,3,4,1,1,1,3,2,3};
+ v[1] = 0;
+ util::bit_compress(v);
+ cout << v << endl;
+ cout << size_in_bytes(v) << endl;
+}
diff --git a/tutorial/expl-02.cpp b/tutorial/expl-02.cpp
new file mode 100644
index 0000000..cc00bbc
--- /dev/null
+++ b/tutorial/expl-02.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include <sdsl/vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ int_vector<> v(10*(1<<20));
+ for (size_t i=0; i<10; ++i)
+ for (size_t j=0; j < 1U<<20; ++j)
+ v[i*(1<<20)+j] = j;
+ cout << size_in_mega_bytes(v) << endl;
+ util::bit_compress(v);
+ cout << size_in_mega_bytes(v) << endl;
+ enc_vector<coder::comma<>> ev(v);
+ cout << size_in_mega_bytes(ev) << endl;
+}
diff --git a/tutorial/expl-03.cpp b/tutorial/expl-03.cpp
new file mode 100644
index 0000000..de34c89
--- /dev/null
+++ b/tutorial/expl-03.cpp
@@ -0,0 +1,19 @@
+#include <iostream>
+#include <sdsl/vectors.hpp>
+#include <sdsl/coder_elias_gamma.hpp>
+#include <sdsl/coder_comma.hpp>
+#include <sdsl/coder_fibonacci.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ int_vector<> v(10*(1<<20), 0);
+ v[0] = 1ULL<<63;
+ //util::bit_compress(v);
+ cout << size_in_mega_bytes(v) << endl;
+ vlc_vector<coder::fibonacci> vv(v);
+ cout << size_in_mega_bytes(vv) << endl;
+ cout << "Percentage: " << size_in_mega_bytes(vv) / size_in_mega_bytes(v) * 100 << endl;
+}
diff --git a/tutorial/expl-04.cpp b/tutorial/expl-04.cpp
new file mode 100644
index 0000000..e9a76b0
--- /dev/null
+++ b/tutorial/expl-04.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = {1,1,0,1,0,0,1};
+ cout << b << endl;
+ b = bit_vector(80*(1<<20), 0);
+ for (size_t i=0; i < b.size(); i+=100)
+ b[i] = 1;
+ cout << size_in_mega_bytes(b) << endl;
+}
diff --git a/tutorial/expl-05.cpp b/tutorial/expl-05.cpp
new file mode 100644
index 0000000..ae22ce8
--- /dev/null
+++ b/tutorial/expl-05.cpp
@@ -0,0 +1,17 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = bit_vector(80*(1<<20), 0);
+ for (size_t i=0; i < b.size(); i+=100)
+ b[i] = 1;
+ cout << size_in_mega_bytes(b) << endl;
+ rrr_vector<63> rrrb(b);
+ cout << size_in_mega_bytes(rrrb) << endl;
+ sd_vector<> sdb(b);
+ cout << size_in_mega_bytes(sdb) << endl;
+}
diff --git a/tutorial/expl-06.cpp b/tutorial/expl-06.cpp
new file mode 100644
index 0000000..8df2525
--- /dev/null
+++ b/tutorial/expl-06.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = bit_vector(80*(1<<20), 0);
+ for (size_t i=0; i < b.size(); i+=100)
+ b[i] = 1;
+ sd_vector<> sdb(b);
+ write_structure<JSON_FORMAT>(sdb, cout);
+}
diff --git a/tutorial/expl-07.cpp b/tutorial/expl-07.cpp
new file mode 100644
index 0000000..1742901
--- /dev/null
+++ b/tutorial/expl-07.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = bit_vector(8000, 0);
+ for (size_t i=0; i < b.size(); i+=100)
+ b[i] = 1;
+ rank_support_v<1> b_rank(&b);
+ for (size_t i=0; i<=b.size(); i+= b.size()/4)
+ cout << "(" << i << ", " << b_rank(i) << ") ";
+ cout << endl;
+}
diff --git a/tutorial/expl-08.cpp b/tutorial/expl-08.cpp
new file mode 100644
index 0000000..5428b14
--- /dev/null
+++ b/tutorial/expl-08.cpp
@@ -0,0 +1,22 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = bit_vector(8000, 0);
+ for (size_t i=0; i < b.size(); i+=100)
+ b[i] = 1;
+ sd_vector<> sdb(b);
+ sd_vector<>::rank_1_type sdb_rank(&sdb);
+ for (size_t i=0; i<=sdb.size(); i+= sdb.size()/4)
+ cout << "(" << i << ", " << sdb_rank(i) << ") ";
+ cout << endl;
+ rrr_vector<> rrrb(b);
+ rrr_vector<>::rank_1_type rrrb_rank(&rrrb);
+ for (size_t i=0; i<=rrrb.size(); i+= rrrb.size()/4)
+ cout << "(" << i << ", " << rrrb_rank(i) << ") ";
+ cout << endl;
+}
diff --git a/tutorial/expl-09.cpp b/tutorial/expl-09.cpp
new file mode 100644
index 0000000..ecc8f6f
--- /dev/null
+++ b/tutorial/expl-09.cpp
@@ -0,0 +1,17 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = {0,1,0,1};
+ rank_support_v<1> b_r1(&b);
+ rank_support_v<0> b_r0(&b);
+ rank_support_v<10,2> b_r10(&b);
+ rank_support_v<01,2> b_r01(&b);
+ for (size_t i=0; i<=b.size(); ++i)
+ cout << i << ": "<< b_r1(i) << " " << b_r0(i)
+ << " " << b_r10(i) << " " << b_r01(i) << endl;
+}
diff --git a/tutorial/expl-10.cpp b/tutorial/expl-10.cpp
new file mode 100644
index 0000000..4a760dc
--- /dev/null
+++ b/tutorial/expl-10.cpp
@@ -0,0 +1,17 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = {0,1,0,1,1,1,0,0,0,1,1};
+ size_t zeros = rank_support_v<0>(&b)(b.size());
+ bit_vector::select_0_type b_sel(&b);
+
+ for (size_t i=1; i <= zeros; ++i) {
+ cout << b_sel(i) << " ";
+ }
+ cout << endl;
+}
diff --git a/tutorial/expl-11.cpp b/tutorial/expl-11.cpp
new file mode 100644
index 0000000..3091a6c
--- /dev/null
+++ b/tutorial/expl-11.cpp
@@ -0,0 +1,16 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ bit_vector b = {0,1,0,1,1,1,0,0,0,1,1};
+ size_t cnt10 = rank_support_v<10,2>(&b)(b.size());
+ select_support_mcl<10,2> b_sel10(&b);
+
+ for (size_t i=1; i <= cnt10; ++i)
+ cout << b_sel10(i) << " ";
+ cout << endl;
+}
diff --git a/tutorial/expl-12.cpp b/tutorial/expl-12.cpp
new file mode 100644
index 0000000..5641416
--- /dev/null
+++ b/tutorial/expl-12.cpp
@@ -0,0 +1,21 @@
+#include <iostream>
+#include <sdsl/bit_vectors.hpp>
+#include <sdsl/vectors.hpp>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ sd_vector<> sd_b = bit_vector {1,0,1,1,1,0,1,1,0,0,1,0,0,1};
+ size_t ones = sd_vector<>::rank_1_type(&sd_b)(sd_b.size());
+ sd_vector<>::select_1_type sdb_sel(&sd_b);
+
+ cout << sd_b << endl;
+
+ for (size_t i=1; i <= ones; ++i)
+ cout << sdb_sel(i) << " ";
+ cout << endl;
+}
+
+
diff --git a/tutorial/expl-13.cpp b/tutorial/expl-13.cpp
new file mode 100644
index 0000000..3eee23a
--- /dev/null
+++ b/tutorial/expl-13.cpp
@@ -0,0 +1,16 @@
+#include <sdsl/wavelet_trees.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ wt_blcd<> wt;
+ construct(wt, "expl-13.cpp", 1);
+ for (size_t i=0; i < wt.size() and wt[i]!='\n'; ++i)
+ cout << wt[i];
+ cout << endl;
+ cout << "number of lines : " << wt.rank(wt.size(), '\n') << endl;
+ cout << "first '=' in line: " << wt.rank(wt.select(1, '='),'\n')+1 << endl;
+}
diff --git a/tutorial/expl-14.cpp b/tutorial/expl-14.cpp
new file mode 100644
index 0000000..595fded
--- /dev/null
+++ b/tutorial/expl-14.cpp
@@ -0,0 +1,18 @@
+#include <sdsl/wavelet_trees.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ wt_hutu<rrr_vector<63>> wt;
+ construct_im(wt, "こんにちは世界", 1);
+ for (size_t i=0; i < wt.size(); ++i)
+ cout << wt[i];
+ cout << endl;
+ auto t1 = wt.lex_count(0, wt.size(), 0x80);
+ auto t2 = wt.lex_count(0, wt.size(), 0xbf);
+ cout << "# of bytes : " << wt.size() << endl;
+ cout << "# of UTF-8 symbols: " << get<1>(t1) + get<2>(t2) << endl;
+}
diff --git a/tutorial/expl-15.cpp b/tutorial/expl-15.cpp
new file mode 100644
index 0000000..cc64d0e
--- /dev/null
+++ b/tutorial/expl-15.cpp
@@ -0,0 +1,22 @@
+#include <sdsl/wavelet_trees.hpp>
+#include <iostream>
+#include <utility>
+
+using namespace std;
+using namespace sdsl;
+
+template<class value_type, class size_type>
+ostream& operator<<(ostream& os, const std::pair<value_type, size_type>& p)
+{
+ return os << "(" << p.first << "," << p.second << ")";
+}
+
+int main()
+{
+ wt_int<rrr_vector<63>> wt;
+ construct_im(wt, "6 1000 1 4 7 3 18 6 3", 'd');
+ auto res = wt.range_search_2d(1, 5, 4, 18);
+ for (auto point : res.second)
+ cout << point << " ";
+ cout << endl;
+}
diff --git a/tutorial/expl-16.cpp b/tutorial/expl-16.cpp
new file mode 100644
index 0000000..7d6062d
--- /dev/null
+++ b/tutorial/expl-16.cpp
@@ -0,0 +1,17 @@
+#include <sdsl/wavelet_trees.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ wt_huff_int<rrr_vector<63>> wt;
+ construct_im(wt, int_vector<>({1981, 1974, 1990, 1974, 2014, 1974}));
+ cout << "wt.sigma : " << wt.sigma << endl;
+ cout << wt << endl;
+ size_t idx = 5;
+ auto r_c = wt.inverse_select(idx);
+ cout << get<0>(r_c)+1 << " occurrence(s) of "
+ << get<1>(r_c) << " in [0.." << idx << "]" << endl;
+}
diff --git a/tutorial/expl-17.cpp b/tutorial/expl-17.cpp
new file mode 100644
index 0000000..f959a82
--- /dev/null
+++ b/tutorial/expl-17.cpp
@@ -0,0 +1,15 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ csa_bitcompressed<> csa;
+ construct_im(csa, "abracadabra", 1);
+ cout << "csa.size(): " << csa.size() << endl;
+ cout << "csa.sigma : " << csa.sigma << endl;
+ cout << csa << endl;
+ cout << extract(csa, 0, csa.size()-1) << endl;
+}
diff --git a/tutorial/expl-18.cpp b/tutorial/expl-18.cpp
new file mode 100644
index 0000000..70ba87f
--- /dev/null
+++ b/tutorial/expl-18.cpp
@@ -0,0 +1,19 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <algorithm>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ csa_wt<wt_huff<rrr_vector<63>>,4,8> csa; // 接尾辞配列
+ construct(csa, "expl-18.cpp", 1);
+ cout << "count(\"配列\") : " << count(csa, "配列") << endl;
+ auto occs = locate(csa, "\n");
+ sort(occs.begin(), occs.end());
+ auto max_line_length = occs[0];
+ for (size_t i=1; i < occs.size(); ++i)
+ max_line_length = std::max(max_line_length, occs[i]-occs[i-1]+1);
+ cout << "max line length : " << max_line_length << endl;
+}
diff --git a/tutorial/expl-19.cpp b/tutorial/expl-19.cpp
new file mode 100644
index 0000000..97f0218
--- /dev/null
+++ b/tutorial/expl-19.cpp
@@ -0,0 +1,14 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+#include <algorithm>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ csa_wt<wt_int<rrr_vector<63>>> csa;
+ construct_im(csa, "1 8 15 23 1 8 23 11 8", 'd');
+ cout << " i SA ISA PSI LF BWT T[SA[i]..SA[i]-1]" << endl;
+ csXprintf(cout, "%2I %2S %3s %3P %2p %3B %:3T", csa);
+}
diff --git a/tutorial/expl-20.cpp b/tutorial/expl-20.cpp
new file mode 100644
index 0000000..cf67cf5
--- /dev/null
+++ b/tutorial/expl-20.cpp
@@ -0,0 +1,14 @@
+#include <sdsl/suffix_arrays.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ memory_monitor::start();
+ csa_wt<> csa;
+ construct(csa, "english.200MB", 1);
+ memory_monitor::stop();
+ memory_monitor::write_memory_log<HTML_FORMAT>(cout);
+}
diff --git a/tutorial/expl-21.cpp b/tutorial/expl-21.cpp
new file mode 100644
index 0000000..3e88edb
--- /dev/null
+++ b/tutorial/expl-21.cpp
@@ -0,0 +1,16 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ cst_sct3<> cst;
+ construct_im(cst, "umulmundumulmum", 1);
+ cout << "inner nodes : " << cst.nodes() - cst.csa.size() << endl;
+ auto v = cst.select_child(cst.child(cst.root(), 'u'),1);
+ auto d = cst.depth(v);
+ cout << "v : " << d << "-[" << cst.lb(v) << "," << cst.rb(v) << "]" << endl;
+ cout << "extract(cst, v) : " << extract(cst, v) << endl;
+}
diff --git a/tutorial/expl-22.cpp b/tutorial/expl-22.cpp
new file mode 100644
index 0000000..6f90469
--- /dev/null
+++ b/tutorial/expl-22.cpp
@@ -0,0 +1,17 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ cst_sct3<csa_wt<wt_int<rrr_vector<>>>> cst;
+ int_vector<> data(100000, 0, 10);
+ for (size_t i=0; i < data.size(); ++i)
+ data[i] = 1 + rand()%1023;
+ construct_im(cst, data);
+ cout << "cst.csa.sigma: " << cst.csa.sigma << endl;
+ for (size_t k=0; k<3; ++k)
+ cout << "H" << k << "(data) : " << get<0>(Hk(cst, k)) << endl;
+}
diff --git a/tutorial/expl-23.cpp b/tutorial/expl-23.cpp
new file mode 100644
index 0000000..2bde216
--- /dev/null
+++ b/tutorial/expl-23.cpp
@@ -0,0 +1,16 @@
+#include <sdsl/suffix_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ cst_sct3<csa_wt<wt_huff<rrr_vector<>>>, lcp_support_sada<>> cst1;
+ construct(cst1, "english.200MB", 1);
+ cout << "cst1.lcp in MiB : " << size_in_mega_bytes(cst1.lcp) << endl;
+ util::clear(cst1);
+ cst_sct3<csa_wt<wt_huff<rrr_vector<>>>, lcp_dac<>> cst2;
+ construct(cst2, "english.200MB", 1);
+ cout << "cst2.lcp in MiB : " << size_in_mega_bytes(cst2.lcp) << endl;
+}
diff --git a/tutorial/expl-24.cpp b/tutorial/expl-24.cpp
new file mode 100644
index 0000000..0d8b9b2
--- /dev/null
+++ b/tutorial/expl-24.cpp
@@ -0,0 +1,17 @@
+#include <sdsl/bp_support.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ // ( ( ( ) ( ) ) ( ) ( ( ( ) ( ) ) ( ) ) )
+ bit_vector b = {1,1,1,0,1,0,0,1,0,1,1,1,0,1,0,0,1,0,0,0};
+ bp_support_sada<> bps(&b); // <- pointer to b
+ cout << bps.find_close(0) << ", "
+ << bps.find_open(3) << ", "
+ << bps.enclose(4) << ", "
+ << bps.double_enclose(13, 16) << endl;
+}
diff --git a/tutorial/expl-25.cpp b/tutorial/expl-25.cpp
new file mode 100644
index 0000000..3e5a129
--- /dev/null
+++ b/tutorial/expl-25.cpp
@@ -0,0 +1,19 @@
+
+#include <sdsl/bp_support.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ // ( ( ( ) ( ) ) ( ) ( ( ( ) ( ) ) ( ) ) )
+ bit_vector b = {1,1,1,0,1,0,0,1,0,1,1,1,0,1,0,0,1,0,0,0};
+ bp_support_sada<> bps(&b); // <- pointer to b
+ for (size_t i=0; i < b.size(); ++i)
+ cout << bps.excess(i)<< " ";
+ cout << endl;
+ cout << bps.rank(0) << ", " // inclusive rank for BPS!!!
+ << bps.select(4) << endl;
+}
diff --git a/tutorial/expl-26.cpp b/tutorial/expl-26.cpp
new file mode 100644
index 0000000..ef216a6
--- /dev/null
+++ b/tutorial/expl-26.cpp
@@ -0,0 +1,15 @@
+#include <sdsl/rmq_support.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace sdsl;
+
+int main()
+{
+ // 0 1 2 3 4 5 6 7 8 9 0
+ int_vector<> v = {5,3,8,9,1,2,5,3,9,0,7};
+ rmq_succinct_sct<> rmq(&v); // <- pointer to b
+ util::clear(v);
+ cout << "v.size() = " << v.size() << endl;
+ cout << rmq(0, 10) << ", " << rmq(2, 7) << endl;
+}
diff --git a/tutorial/int-vector-buffer.cpp b/tutorial/int-vector-buffer.cpp
new file mode 100644
index 0000000..de2a411
--- /dev/null
+++ b/tutorial/int-vector-buffer.cpp
@@ -0,0 +1,34 @@
+#include <sdsl/vectors.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main()
+{
+ std::string tmp_file = "tmp_file.sdsl";
+ {
+ // generate int_vector and store to a file
+ int_vector<> v = {1,3,5,7,2,3,4,9,8,7,10,1};
+ store_to_file(v, tmp_file);
+ }
+ {
+ // use int_vector_buffer to open the file
+ int_vector_buffer<> ivb(tmp_file);
+ // output elements and assign 42 to each of them
+for (auto x : ivb) {
+ cout << x << endl;
+ x = 42;
+ }
+ // int_vector_buffer is destroy at the end of the
+ // scope and all value are written to disk
+ }
+ {
+ // read vector from file and output it
+ int_vector<> v;
+ load_from_file(v, tmp_file);
+ cout << v << endl;
+ }
+ // delete temporary file
+ sdsl::remove(tmp_file);
+}
diff --git a/tutorial/rmq-example.cpp b/tutorial/rmq-example.cpp
new file mode 100644
index 0000000..5e0d45a
--- /dev/null
+++ b/tutorial/rmq-example.cpp
@@ -0,0 +1,37 @@
+#include <iostream>
+#include <sdsl/rmq_support.hpp>
+
+using namespace sdsl;
+using namespace std;
+
+
+int main()
+{
+ rmq_succinct_sct<> rmq;
+ {
+ // initilaize int_vector object A
+ int_vector<> A = {6,7,3,2,4,2,1,5,8,2};
+ // output a
+ cout << "A = " << A << endl;
+
+ // generate range-minimum structure by passing
+ // pointer to ordered array
+ rmq = rmq_succinct_sct<>(&A);
+
+ // calculate index of minimal element in a[0..a.size()-1]
+ auto min_idx = rmq(0, A.size()-1);
+
+ cout << "A[" << min_idx << "]=" << A[min_idx];
+ cout << " is the samllest element in A[0.." << A.size()-1 << "]" << endl;
+
+ // calculate index of minimal element in a[2..5]
+ min_idx = rmq(2,5);
+
+ cout << "A[" << min_idx << "]=" << A[min_idx];
+ cout << " is the smallest element in A[2..5]" << endl;
+ }
+ // no A does not exist any more, queries can still be answered
+ auto min_idx = rmq(1,5);
+ cout << "A[" << min_idx << "] is the smallest in A[1..5]" << endl;
+ return 0;
+}
diff --git a/tutorial/use-a-wavelet-tree.cpp b/tutorial/use-a-wavelet-tree.cpp
new file mode 100644
index 0000000..b877b91
--- /dev/null
+++ b/tutorial/use-a-wavelet-tree.cpp
@@ -0,0 +1,27 @@
+#include <sdsl/wavelet_trees.hpp>
+#include <iostream>
+
+using namespace sdsl;
+using namespace std;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2) {
+ cout << "Usage: " << argv[1] << " file" << endl;
+ return 1;
+ }
+ wt_huff<rrr_vector<63>> wt;
+ construct(wt, argv[1], 1);
+
+ cout << "wt.size()="<< wt.size() << endl;
+ cout << "wt.sigma ="<< wt.sigma << endl;
+ if (wt.size() > 0) {
+ // access an element
+ cout << "wt[0]=" << wt[0] << endl;
+ // rank an element (exclude)
+ uint64_t r = wt.rank(wt.size(), wt[0]);
+ cout << "wt.rank(wt.size(), wt[0])=" << r << endl;
+ // select element ()
+ cout << "wt.select(r, wt[0]) = " << wt.select(r, wt[0]) << endl;
+ }
+}
diff --git a/uninstall.sh b/uninstall.sh
new file mode 100755
index 0000000..8dfa21b
--- /dev/null
+++ b/uninstall.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# This script removes all installed sdsl files
+# on a LINUX or Mac OS X system
+
+CUR_DIR=`pwd`
+SDSL_INSTALL_PREFIX=${HOME}
+if [ $# -ge 1 ]; then
+ SDSL_INSTALL_PREFIX=${1}
+fi
+
+echo "Library files will be removed from"
+echo "'${SDSL_INSTALL_PREFIX}/lib' and"
+echo "'${SDSL_INSTALL_PREFIX}/include'"
+
+
+cd "${CUR_DIR}"
+OLD_DIR="$( cd "$( dirname "$0" )" && pwd )" # gets the directory where the script is located in
+cd "${OLD_DIR}"
+OLD_DIR=`pwd`
+
+cd build # change into the build directory
+if [ $? != 0 ]; then
+ exit 1
+fi
+
+make uninstall
+
+if [ $? != 0 ]; then
+ exit 1
+fi
+
+./clean.sh # clean-up build directory
+if [ $? != 0 ]; then
+ exit 1
+fi
+
+echo "Installed sdsl files were removed."
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/libsdsl.git
More information about the debian-med-commit
mailing list