From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/boost/libs/container/CMakeLists.txt | 39 + src/boost/libs/container/Jamfile | 11 + src/boost/libs/container/bench/Jamfile.v2 | 34 + .../container/bench/bench_adaptive_node_pool.cpp | 339 ++ src/boost/libs/container/bench/bench_alloc.cpp | 188 + .../container/bench/bench_alloc_expand_bwd.cpp | 224 + .../container/bench/bench_alloc_expand_fwd.cpp | 202 + .../container/bench/bench_alloc_shrink_to_fit.cpp | 181 + .../bench/bench_alloc_stable_vector_burst.cpp | 294 + .../libs/container/bench/bench_flat_multiset.cpp | 29 + src/boost/libs/container/bench/bench_flat_set.cpp | 29 + src/boost/libs/container/bench/bench_set.cpp | 35 + src/boost/libs/container/bench/bench_set.hpp | 485 ++ .../container/bench/bench_set_adaptive_pool.cpp | 34 + .../libs/container/bench/bench_set_alloc_v2.cpp | 29 + src/boost/libs/container/bench/bench_set_avl.cpp | 38 + src/boost/libs/container/bench/bench_set_multi.cpp | 30 + src/boost/libs/container/bench/bench_set_sg.cpp | 28 + src/boost/libs/container/bench/bench_set_sp.cpp | 28 + .../libs/container/bench/bench_static_vector.cpp | 144 + src/boost/libs/container/bench/detail/varray.hpp | 2242 +++++++ .../libs/container/bench/detail/varray_concept.hpp | 60 + .../libs/container/bench/detail/varray_util.hpp | 646 ++ src/boost/libs/container/bench/varray.hpp | 1000 ++++ src/boost/libs/container/build/Jamfile.v2 | 22 + src/boost/libs/container/example/Jamfile.v2 | 34 + .../libs/container/example/doc_custom_deque.cpp | 41 + .../container/example/doc_custom_small_vector.cpp | 47 + .../container/example/doc_custom_static_vector.cpp | 39 + .../libs/container/example/doc_custom_tree.cpp | 69 + .../libs/container/example/doc_custom_vector.cpp | 54 + src/boost/libs/container/example/doc_emplace.cpp | 44 + .../container/example/doc_extended_allocators.cpp | 54 + .../libs/container/example/doc_move_containers.cpp | 54 + src/boost/libs/container/example/doc_pmr.cpp | 98 + .../container/example/doc_recursive_containers.cpp | 73 + .../libs/container/example/doc_type_erasure.cpp | 91 + src/boost/libs/container/index.html | 14 + src/boost/libs/container/meta/libraries.json | 15 + src/boost/libs/container/proj/to-do.txt | 62 + .../container/proj/vc7ide/alloc_basic_test.vcproj | 140 + .../container/proj/vc7ide/alloc_full_test.vcproj | 135 + .../libs/container/proj/vc7ide/alloc_lib.vcproj | 246 + .../proj/vc7ide/allocator_traits_test.vcproj | 135 + .../proj/vc7ide/bench_adaptive_node_pool.vcproj | 135 + .../libs/container/proj/vc7ide/bench_alloc.vcproj | 135 + .../proj/vc7ide/bench_alloc_expand_bwd.vcproj | 135 + .../proj/vc7ide/bench_alloc_expand_fwd.vcproj | 135 + .../proj/vc7ide/bench_alloc_shrink_to_fit.vcproj | 135 + .../vc7ide/bench_alloc_stable_vector_burst.vcproj | 135 + .../proj/vc7ide/bench_flat_multiset.vcproj | 136 + .../container/proj/vc7ide/bench_flat_set.vcproj | 136 + .../libs/container/proj/vc7ide/bench_set.vcproj | 135 + .../proj/vc7ide/bench_set_adaptive_pool.vcproj | 136 + .../proj/vc7ide/bench_set_alloc_v2.vcproj | 136 + .../container/proj/vc7ide/bench_set_avl.vcproj | 136 + .../container/proj/vc7ide/bench_set_multi.vcproj | 136 + .../libs/container/proj/vc7ide/bench_set_sg.vcproj | 136 + .../libs/container/proj/vc7ide/bench_set_sp.vcproj | 136 + .../proj/vc7ide/bench_static_vector.vcproj | 136 + src/boost/libs/container/proj/vc7ide/container.sln | 685 +++ .../libs/container/proj/vc7ide/container.vcproj | 568 ++ .../libs/container/proj/vc7ide/deque_test.vcproj | 135 + .../container/proj/vc7ide/doc_custom_tree.vcproj | 136 + .../container/proj/vc7ide/doc_custom_vector.vcproj | 136 + .../libs/container/proj/vc7ide/doc_emplace.vcproj | 136 + .../proj/vc7ide/doc_extended_allocators.vcproj | 136 + .../proj/vc7ide/doc_move_containers.vcproj | 136 + .../libs/container/proj/vc7ide/doc_pmr.vcproj | 136 + .../proj/vc7ide/doc_recursive_containers.vcproj | 136 + .../container/proj/vc7ide/doc_type_erasure.vcproj | 136 + .../proj/vc7ide/explicit_inst_deque_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_flat_map_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_flat_set_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_list_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_map_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_set_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_slist_test.vcproj | 136 + .../vc7ide/explicit_inst_small_vector_test.vcproj | 136 + .../vc7ide/explicit_inst_stable_vector_test.vcproj | 136 + .../vc7ide/explicit_inst_static_vector_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_string_test.vcproj | 136 + .../proj/vc7ide/explicit_inst_vector_test.vcproj | 136 + .../container/proj/vc7ide/flat_map_test.vcproj | 137 + .../container/proj/vc7ide/flat_set_test.vcproj | 137 + .../container/proj/vc7ide/flat_tree_test.vcproj | 135 + .../container/proj/vc7ide/global_resource.vcproj | 135 + .../container/proj/vc7ide/hash_table_test.vcproj | 135 + .../proj/vc7ide/insert_vs_emplace_test.vcproj | 135 + .../libs/container/proj/vc7ide/list_test.vcproj | 135 + .../libs/container/proj/vc7ide/map_test.vcproj | 135 + .../proj/vc7ide/memory_resource_test.vcproj | 135 + .../vc7ide/monotonic_buffer_resource_test.vcproj | 137 + .../container/proj/vc7ide/node_handle_test.vcproj | 135 + .../proj/vc7ide/null_iterators_test.vcproj | 128 + .../libs/container/proj/vc7ide/pair_test.vcproj | 135 + .../container/proj/vc7ide/pmr_deque_test.vcproj | 136 + .../container/proj/vc7ide/pmr_flat_map_test.vcproj | 136 + .../container/proj/vc7ide/pmr_flat_set_test.vcproj | 136 + .../container/proj/vc7ide/pmr_list_test.vcproj | 136 + .../libs/container/proj/vc7ide/pmr_map_test.vcproj | 136 + .../libs/container/proj/vc7ide/pmr_set_test.vcproj | 136 + .../container/proj/vc7ide/pmr_slist_test.vcproj | 136 + .../proj/vc7ide/pmr_small_vector_test.vcproj | 136 + .../proj/vc7ide/pmr_stable_vector_test.vcproj | 136 + .../container/proj/vc7ide/pmr_string_test.vcproj | 136 + .../container/proj/vc7ide/pmr_vector_test.vcproj | 136 + .../proj/vc7ide/polymorphic_allocator_test.vcproj | 135 + .../container/proj/vc7ide/resource_adaptor.vcproj | 136 + .../vc7ide/scoped_allocator_adaptor_test.vcproj | 134 + .../proj/vc7ide/scoped_allocator_usage_test.vcproj | 136 + .../libs/container/proj/vc7ide/set_test.vcproj | 134 + .../libs/container/proj/vc7ide/slist_test.vcproj | 135 + .../container/proj/vc7ide/small_vector_test.vcproj | 135 + .../proj/vc7ide/stable_vector_test.vcproj | 134 + .../proj/vc7ide/static_vector_test.vcproj | 135 + .../libs/container/proj/vc7ide/string_test.vcproj | 136 + .../proj/vc7ide/string_view_compat_test.vcproj | 136 + .../vc7ide/synchronized_pool_resource_test.vcproj | 136 + .../proj/vc7ide/throw_exception_test.vcproj | 136 + .../libs/container/proj/vc7ide/tree_test.vcproj | 135 + .../unsynchronized_pool_resource_test.vcproj | 136 + .../proj/vc7ide/uses_allocator_test.vcproj | 134 + .../proj/vc7ide/vector_options_test.vcproj | 135 + .../libs/container/proj/vc7ide/vector_test.vcproj | 135 + src/boost/libs/container/src/alloc_lib.c | 27 + src/boost/libs/container/src/dlmalloc.cpp | 108 + src/boost/libs/container/src/dlmalloc_2_8_6.c | 6280 ++++++++++++++++++++ src/boost/libs/container/src/dlmalloc_ext_2_8_6.c | 1484 +++++ src/boost/libs/container/src/global_resource.cpp | 106 + .../container/src/monotonic_buffer_resource.cpp | 165 + src/boost/libs/container/src/pool_resource.cpp | 291 + .../container/src/synchronized_pool_resource.cpp | 111 + .../container/src/unsynchronized_pool_resource.cpp | 79 + src/boost/libs/container/test/Jamfile.v2 | 40 + src/boost/libs/container/test/alloc_basic_test.cpp | 119 + src/boost/libs/container/test/alloc_full_test.cpp | 849 +++ .../container/test/allocator_argument_tester.hpp | 233 + .../libs/container/test/allocator_traits_test.cpp | 447 ++ .../libs/container/test/check_equal_containers.hpp | 159 + src/boost/libs/container/test/comparison_test.hpp | 58 + .../libs/container/test/container_common_tests.hpp | 86 + .../libs/container/test/default_init_test.hpp | 155 + .../libs/container/test/deque_options_test.cpp | 43 + src/boost/libs/container/test/deque_test.cpp | 446 ++ .../test/derived_from_memory_resource.hpp | 87 + .../libs/container/test/dummy_test_allocator.hpp | 232 + src/boost/libs/container/test/emplace_test.hpp | 686 +++ .../container/test/expand_bwd_test_allocator.hpp | 200 + .../container/test/expand_bwd_test_template.hpp | 218 + .../container/test/explicit_inst_deque_test.cpp | 46 + .../container/test/explicit_inst_flat_map_test.cpp | 94 + .../container/test/explicit_inst_flat_set_test.cpp | 88 + .../container/test/explicit_inst_list_test.cpp | 25 + .../libs/container/test/explicit_inst_map_test.cpp | 56 + .../libs/container/test/explicit_inst_set_test.cpp | 54 + .../container/test/explicit_inst_slist_test.cpp | 44 + .../test/explicit_inst_small_vector_test.cpp | 56 + .../test/explicit_inst_stable_vector_test.cpp | 45 + .../test/explicit_inst_static_vector_test.cpp | 33 + .../container/test/explicit_inst_string_test.cpp | 44 + .../container/test/explicit_inst_vector_test.cpp | 47 + .../libs/container/test/flat_map_adaptor_test.cpp | 104 + src/boost/libs/container/test/flat_map_test.cpp | 838 +++ .../libs/container/test/flat_set_adaptor_test.cpp | 101 + src/boost/libs/container/test/flat_set_test.cpp | 933 +++ src/boost/libs/container/test/flat_tree_test.cpp | 156 + .../libs/container/test/global_resource_test.cpp | 127 + src/boost/libs/container/test/hash_table_test.cppx | 0 .../container/test/input_from_forward_iterator.hpp | 80 + src/boost/libs/container/test/insert_test.hpp | 75 + .../libs/container/test/insert_vs_emplace_test.cpp | 498 ++ src/boost/libs/container/test/list_test.cpp | 286 + src/boost/libs/container/test/list_test.hpp | 469 ++ src/boost/libs/container/test/map_test.cpp | 693 +++ src/boost/libs/container/test/map_test.hpp | 1264 ++++ .../libs/container/test/memory_resource_logger.hpp | 86 + .../libs/container/test/memory_resource_test.cpp | 135 + .../test/monotonic_buffer_resource_test.cpp | 483 ++ src/boost/libs/container/test/movable_int.hpp | 437 ++ src/boost/libs/container/test/node_handle_test.cpp | 633 ++ .../libs/container/test/null_iterators_test.cpp | 96 + src/boost/libs/container/test/pair_test.cpp | 156 + src/boost/libs/container/test/pmr_deque_test.cpp | 26 + .../libs/container/test/pmr_flat_map_test.cpp | 26 + .../libs/container/test/pmr_flat_set_test.cpp | 26 + src/boost/libs/container/test/pmr_list_test.cpp | 26 + src/boost/libs/container/test/pmr_map_test.cpp | 26 + src/boost/libs/container/test/pmr_set_test.cpp | 26 + src/boost/libs/container/test/pmr_slist_test.cpp | 26 + .../libs/container/test/pmr_small_vector_test.cpp | 26 + .../libs/container/test/pmr_stable_vector_test.cpp | 26 + .../libs/container/test/pmr_static_vector_test.cpp | 26 + src/boost/libs/container/test/pmr_string_test.cpp | 31 + src/boost/libs/container/test/pmr_vector_test.cpp | 26 + .../container/test/polymorphic_allocator_test.cpp | 198 + .../libs/container/test/pool_resource_test.hpp | 493 ++ src/boost/libs/container/test/print_container.hpp | 46 + .../container/test/propagate_allocator_test.hpp | 368 ++ .../container/test/propagation_test_allocator.hpp | 268 + .../libs/container/test/resource_adaptor_test.cpp | 234 + .../test/scoped_allocator_adaptor_test.cpp | 1377 +++++ .../container/test/scoped_allocator_usage_test.cpp | 428 ++ src/boost/libs/container/test/set_test.cpp | 655 ++ src/boost/libs/container/test/set_test.hpp | 942 +++ src/boost/libs/container/test/slist_test.cpp | 290 + .../container/test/small_vector_options_test.cpp | 110 + .../libs/container/test/small_vector_test.cpp | 236 + .../libs/container/test/stable_vector_test.cpp | 227 + .../container/test/static_vector_options_test.cpp | 124 + .../libs/container/test/static_vector_test.cpp | 827 +++ .../libs/container/test/static_vector_test.hpp | 103 + src/boost/libs/container/test/string_test.cpp | 596 ++ .../container/test/string_view_compat_test.cpp | 275 + .../test/synchronized_pool_resource_test.cpp | 19 + .../libs/container/test/throw_exception_test.cpp | 62 + src/boost/libs/container/test/tree_test.cpp | 119 + .../test/unsynchronized_pool_resource_test.cpp | 19 + .../libs/container/test/uses_allocator_test.cpp | 84 + .../libs/container/test/vector_options_test.cpp | 121 + src/boost/libs/container/test/vector_test.cpp | 364 ++ src/boost/libs/container/test/vector_test.hpp | 563 ++ 222 files changed, 50252 insertions(+) create mode 100644 src/boost/libs/container/CMakeLists.txt create mode 100644 src/boost/libs/container/Jamfile create mode 100644 src/boost/libs/container/bench/Jamfile.v2 create mode 100644 src/boost/libs/container/bench/bench_adaptive_node_pool.cpp create mode 100644 src/boost/libs/container/bench/bench_alloc.cpp create mode 100644 src/boost/libs/container/bench/bench_alloc_expand_bwd.cpp create mode 100644 src/boost/libs/container/bench/bench_alloc_expand_fwd.cpp create mode 100644 src/boost/libs/container/bench/bench_alloc_shrink_to_fit.cpp create mode 100644 src/boost/libs/container/bench/bench_alloc_stable_vector_burst.cpp create mode 100644 src/boost/libs/container/bench/bench_flat_multiset.cpp create mode 100644 src/boost/libs/container/bench/bench_flat_set.cpp create mode 100644 src/boost/libs/container/bench/bench_set.cpp create mode 100644 src/boost/libs/container/bench/bench_set.hpp create mode 100644 src/boost/libs/container/bench/bench_set_adaptive_pool.cpp create mode 100644 src/boost/libs/container/bench/bench_set_alloc_v2.cpp create mode 100644 src/boost/libs/container/bench/bench_set_avl.cpp create mode 100644 src/boost/libs/container/bench/bench_set_multi.cpp create mode 100644 src/boost/libs/container/bench/bench_set_sg.cpp create mode 100644 src/boost/libs/container/bench/bench_set_sp.cpp create mode 100644 src/boost/libs/container/bench/bench_static_vector.cpp create mode 100644 src/boost/libs/container/bench/detail/varray.hpp create mode 100644 src/boost/libs/container/bench/detail/varray_concept.hpp create mode 100644 src/boost/libs/container/bench/detail/varray_util.hpp create mode 100644 src/boost/libs/container/bench/varray.hpp create mode 100644 src/boost/libs/container/build/Jamfile.v2 create mode 100644 src/boost/libs/container/example/Jamfile.v2 create mode 100644 src/boost/libs/container/example/doc_custom_deque.cpp create mode 100644 src/boost/libs/container/example/doc_custom_small_vector.cpp create mode 100644 src/boost/libs/container/example/doc_custom_static_vector.cpp create mode 100644 src/boost/libs/container/example/doc_custom_tree.cpp create mode 100644 src/boost/libs/container/example/doc_custom_vector.cpp create mode 100644 src/boost/libs/container/example/doc_emplace.cpp create mode 100644 src/boost/libs/container/example/doc_extended_allocators.cpp create mode 100644 src/boost/libs/container/example/doc_move_containers.cpp create mode 100644 src/boost/libs/container/example/doc_pmr.cpp create mode 100644 src/boost/libs/container/example/doc_recursive_containers.cpp create mode 100644 src/boost/libs/container/example/doc_type_erasure.cpp create mode 100644 src/boost/libs/container/index.html create mode 100644 src/boost/libs/container/meta/libraries.json create mode 100644 src/boost/libs/container/proj/to-do.txt create mode 100644 src/boost/libs/container/proj/vc7ide/alloc_basic_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/alloc_full_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/alloc_lib.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/allocator_traits_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_adaptive_node_pool.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_alloc.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_alloc_expand_bwd.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_alloc_expand_fwd.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_alloc_shrink_to_fit.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_alloc_stable_vector_burst.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_flat_multiset.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_flat_set.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set_adaptive_pool.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set_alloc_v2.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set_avl.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set_multi.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set_sg.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_set_sp.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/bench_static_vector.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/container.sln create mode 100644 src/boost/libs/container/proj/vc7ide/container.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/deque_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_custom_tree.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_custom_vector.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_emplace.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_extended_allocators.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_move_containers.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_pmr.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_recursive_containers.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/doc_type_erasure.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_deque_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_flat_map_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_flat_set_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_list_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_map_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_set_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_slist_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_small_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_stable_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_static_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_string_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/explicit_inst_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/flat_map_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/flat_set_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/flat_tree_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/global_resource.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/hash_table_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/insert_vs_emplace_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/list_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/map_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/memory_resource_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/monotonic_buffer_resource_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/node_handle_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/null_iterators_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pair_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_deque_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_flat_map_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_flat_set_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_list_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_map_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_set_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_slist_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_small_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_stable_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_string_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/pmr_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/polymorphic_allocator_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/resource_adaptor.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/scoped_allocator_adaptor_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/scoped_allocator_usage_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/set_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/slist_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/small_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/stable_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/static_vector_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/string_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/string_view_compat_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/synchronized_pool_resource_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/throw_exception_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/tree_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/unsynchronized_pool_resource_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/uses_allocator_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/vector_options_test.vcproj create mode 100644 src/boost/libs/container/proj/vc7ide/vector_test.vcproj create mode 100644 src/boost/libs/container/src/alloc_lib.c create mode 100644 src/boost/libs/container/src/dlmalloc.cpp create mode 100644 src/boost/libs/container/src/dlmalloc_2_8_6.c create mode 100644 src/boost/libs/container/src/dlmalloc_ext_2_8_6.c create mode 100644 src/boost/libs/container/src/global_resource.cpp create mode 100644 src/boost/libs/container/src/monotonic_buffer_resource.cpp create mode 100644 src/boost/libs/container/src/pool_resource.cpp create mode 100644 src/boost/libs/container/src/synchronized_pool_resource.cpp create mode 100644 src/boost/libs/container/src/unsynchronized_pool_resource.cpp create mode 100644 src/boost/libs/container/test/Jamfile.v2 create mode 100644 src/boost/libs/container/test/alloc_basic_test.cpp create mode 100644 src/boost/libs/container/test/alloc_full_test.cpp create mode 100644 src/boost/libs/container/test/allocator_argument_tester.hpp create mode 100644 src/boost/libs/container/test/allocator_traits_test.cpp create mode 100644 src/boost/libs/container/test/check_equal_containers.hpp create mode 100644 src/boost/libs/container/test/comparison_test.hpp create mode 100644 src/boost/libs/container/test/container_common_tests.hpp create mode 100644 src/boost/libs/container/test/default_init_test.hpp create mode 100644 src/boost/libs/container/test/deque_options_test.cpp create mode 100644 src/boost/libs/container/test/deque_test.cpp create mode 100644 src/boost/libs/container/test/derived_from_memory_resource.hpp create mode 100644 src/boost/libs/container/test/dummy_test_allocator.hpp create mode 100644 src/boost/libs/container/test/emplace_test.hpp create mode 100644 src/boost/libs/container/test/expand_bwd_test_allocator.hpp create mode 100644 src/boost/libs/container/test/expand_bwd_test_template.hpp create mode 100644 src/boost/libs/container/test/explicit_inst_deque_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_flat_map_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_flat_set_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_list_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_map_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_set_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_slist_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_small_vector_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_stable_vector_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_static_vector_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_string_test.cpp create mode 100644 src/boost/libs/container/test/explicit_inst_vector_test.cpp create mode 100644 src/boost/libs/container/test/flat_map_adaptor_test.cpp create mode 100644 src/boost/libs/container/test/flat_map_test.cpp create mode 100644 src/boost/libs/container/test/flat_set_adaptor_test.cpp create mode 100644 src/boost/libs/container/test/flat_set_test.cpp create mode 100644 src/boost/libs/container/test/flat_tree_test.cpp create mode 100644 src/boost/libs/container/test/global_resource_test.cpp create mode 100644 src/boost/libs/container/test/hash_table_test.cppx create mode 100644 src/boost/libs/container/test/input_from_forward_iterator.hpp create mode 100644 src/boost/libs/container/test/insert_test.hpp create mode 100644 src/boost/libs/container/test/insert_vs_emplace_test.cpp create mode 100644 src/boost/libs/container/test/list_test.cpp create mode 100644 src/boost/libs/container/test/list_test.hpp create mode 100644 src/boost/libs/container/test/map_test.cpp create mode 100644 src/boost/libs/container/test/map_test.hpp create mode 100644 src/boost/libs/container/test/memory_resource_logger.hpp create mode 100644 src/boost/libs/container/test/memory_resource_test.cpp create mode 100644 src/boost/libs/container/test/monotonic_buffer_resource_test.cpp create mode 100644 src/boost/libs/container/test/movable_int.hpp create mode 100644 src/boost/libs/container/test/node_handle_test.cpp create mode 100644 src/boost/libs/container/test/null_iterators_test.cpp create mode 100644 src/boost/libs/container/test/pair_test.cpp create mode 100644 src/boost/libs/container/test/pmr_deque_test.cpp create mode 100644 src/boost/libs/container/test/pmr_flat_map_test.cpp create mode 100644 src/boost/libs/container/test/pmr_flat_set_test.cpp create mode 100644 src/boost/libs/container/test/pmr_list_test.cpp create mode 100644 src/boost/libs/container/test/pmr_map_test.cpp create mode 100644 src/boost/libs/container/test/pmr_set_test.cpp create mode 100644 src/boost/libs/container/test/pmr_slist_test.cpp create mode 100644 src/boost/libs/container/test/pmr_small_vector_test.cpp create mode 100644 src/boost/libs/container/test/pmr_stable_vector_test.cpp create mode 100644 src/boost/libs/container/test/pmr_static_vector_test.cpp create mode 100644 src/boost/libs/container/test/pmr_string_test.cpp create mode 100644 src/boost/libs/container/test/pmr_vector_test.cpp create mode 100644 src/boost/libs/container/test/polymorphic_allocator_test.cpp create mode 100644 src/boost/libs/container/test/pool_resource_test.hpp create mode 100644 src/boost/libs/container/test/print_container.hpp create mode 100644 src/boost/libs/container/test/propagate_allocator_test.hpp create mode 100644 src/boost/libs/container/test/propagation_test_allocator.hpp create mode 100644 src/boost/libs/container/test/resource_adaptor_test.cpp create mode 100644 src/boost/libs/container/test/scoped_allocator_adaptor_test.cpp create mode 100644 src/boost/libs/container/test/scoped_allocator_usage_test.cpp create mode 100644 src/boost/libs/container/test/set_test.cpp create mode 100644 src/boost/libs/container/test/set_test.hpp create mode 100644 src/boost/libs/container/test/slist_test.cpp create mode 100644 src/boost/libs/container/test/small_vector_options_test.cpp create mode 100644 src/boost/libs/container/test/small_vector_test.cpp create mode 100644 src/boost/libs/container/test/stable_vector_test.cpp create mode 100644 src/boost/libs/container/test/static_vector_options_test.cpp create mode 100644 src/boost/libs/container/test/static_vector_test.cpp create mode 100644 src/boost/libs/container/test/static_vector_test.hpp create mode 100644 src/boost/libs/container/test/string_test.cpp create mode 100644 src/boost/libs/container/test/string_view_compat_test.cpp create mode 100644 src/boost/libs/container/test/synchronized_pool_resource_test.cpp create mode 100644 src/boost/libs/container/test/throw_exception_test.cpp create mode 100644 src/boost/libs/container/test/tree_test.cpp create mode 100644 src/boost/libs/container/test/unsynchronized_pool_resource_test.cpp create mode 100644 src/boost/libs/container/test/uses_allocator_test.cpp create mode 100644 src/boost/libs/container/test/vector_options_test.cpp create mode 100644 src/boost/libs/container/test/vector_test.cpp create mode 100644 src/boost/libs/container/test/vector_test.hpp (limited to 'src/boost/libs/container') diff --git a/src/boost/libs/container/CMakeLists.txt b/src/boost/libs/container/CMakeLists.txt new file mode 100644 index 00000000..8a6428e0 --- /dev/null +++ b/src/boost/libs/container/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright 2019 Mike Dev +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +# +# NOTE: CMake support for Boost.Container is currently experimental at best +# and the interface is likely to change in the future + +cmake_minimum_required( VERSION 3.5 ) +project( BoostContainer LANGUAGES C CXX ) + +file( GLOB boost_container_cpp_files src/*.cpp ) + +add_library(boost_container + ${boost_container_cpp_files} + src/alloc_lib.c +) + +# This is the public target name, other libraries should link to +add_library( Boost::container ALIAS boost_container ) + +target_include_directories( boost_container PUBLIC include ) + +# NOTE: +# We deactivate autolinking, because cmake based builds don't need it and +# we don't implement name mangling for the library file anyway. +# Ususally the parent CMakeLists.txt file should already have globally defined BOOST_ALL_NO_LIB +target_compile_definitions( boost_container PUBLIC BOOST_CONTAINER_NO_LIB ) + +target_link_libraries( boost_container + PUBLIC + Boost::assert + Boost::config + Boost::container_hash + Boost::core + Boost::intrusive + Boost::move + Boost::static_assert + Boost::type_traits +) diff --git a/src/boost/libs/container/Jamfile b/src/boost/libs/container/Jamfile new file mode 100644 index 00000000..c55393e3 --- /dev/null +++ b/src/boost/libs/container/Jamfile @@ -0,0 +1,11 @@ +# Boost.Container Library Jamfile +# +# Copyright (c) 2018 Ion Gaztanaga +# +# Use, modification, and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# please order by name to ease maintenance +build-project example ; +build-project test ; diff --git a/src/boost/libs/container/bench/Jamfile.v2 b/src/boost/libs/container/bench/Jamfile.v2 new file mode 100644 index 00000000..9cf993dc --- /dev/null +++ b/src/boost/libs/container/bench/Jamfile.v2 @@ -0,0 +1,34 @@ +# Boost Container Library Test Jamfile + +# (C) Copyright Ion Gaztanaga 2009. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Adapted from John Maddock's TR1 Jamfile.v2 +# Copyright John Maddock 2005. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# this rule enumerates through all the sources and invokes +# the run rule for each source, the result is a list of all +# the run rules, which we can pass on to the test_suite rule: + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) /boost/container//boost_container /boost/timer//boost_timer + : # additional args + : # test-files + : # requirements + ] ; + } + + return $(all_rules) ; +} + +test-suite container_bench : [ test_all r ] ; diff --git a/src/boost/libs/container/bench/bench_adaptive_node_pool.cpp b/src/boost/libs/container/bench/bench_adaptive_node_pool.cpp new file mode 100644 index 00000000..acb0750e --- /dev/null +++ b/src/boost/libs/container/bench/bench_adaptive_node_pool.cpp @@ -0,0 +1,339 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//Enable checks in debug mode +#ifndef NDEBUG +#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS +#endif + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#pragma warning (disable : 4127) +#pragma warning (disable : 4244) +#pragma warning (disable : 4267) +#endif + +#include +#include +#include +#include +#include //std::allocator +#include //std::cout, std::endl +#include //std::vector +#include //std::size_t +#include //assert + +#include +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +typedef std::allocator StdAllocator; +typedef bc::allocator AllocatorPlusV2; +typedef bc::allocator AllocatorPlusV1; +typedef bc::adaptive_pool + < int + , bc::ADP_nodes_per_block + , bc::ADP_max_free_blocks + , bc::ADP_only_alignment + , 1> AdPoolAlignOnlyV1; +typedef bc::adaptive_pool + < int + , bc::ADP_nodes_per_block + , bc::ADP_max_free_blocks + , bc::ADP_only_alignment + , 2> AdPoolAlignOnlyV2; +typedef bc::adaptive_pool + < int + , bc::ADP_nodes_per_block + , bc::ADP_max_free_blocks + , 2 + , 1> AdPool2PercentV1; +typedef bc::adaptive_pool + < int + , bc::ADP_nodes_per_block + , bc::ADP_max_free_blocks + , 2 + , 2> AdPool2PercentV2; +typedef bc::node_allocator + < int + , bc::NodeAlloc_nodes_per_block + , 1> SimpleSegregatedStorageV1; +typedef bc::node_allocator + < int + , bc::NodeAlloc_nodes_per_block + , 2> SimpleSegregatedStorageV2; + +//Explicit instantiation +template class bc::adaptive_pool + < int + , bc::ADP_nodes_per_block + , bc::ADP_max_free_blocks + , bc::ADP_only_alignment + , 2>; + +template class bc::node_allocator + < int + , bc::NodeAlloc_nodes_per_block + , 2>; + +template struct get_allocator_name; + +template<> struct get_allocator_name +{ static const char *get() { return "StdAllocator"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV2"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV1"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AdPoolAlignOnlyV1"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AdPoolAlignOnlyV2"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AdPool2PercentV1"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AdPool2PercentV2"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "SimpleSegregatedStorageV1"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "SimpleSegregatedStorageV2"; } }; + +class MyInt +{ + std::size_t int_; + + public: + explicit MyInt(std::size_t i = 0) : int_(i){} + MyInt(const MyInt &other) + : int_(other.int_) + {} + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } +}; + +template +void list_test_template(std::size_t num_iterations, std::size_t num_elements, bool csv_output) +{ + typedef typename Allocator::template rebind::other IntAllocator; + nanosecond_type tinsert, terase; + bc::dlmalloc_malloc_stats_t insert_stats, erase_stats; + std::size_t insert_inuse, erase_inuse; + const size_t sizeof_node = 2*sizeof(void*)+sizeof(int); + + typedef bc::list list_t; + typedef typename list_t::iterator iterator_t; + { + cpu_timer timer; + timer.resume(); + list_t l; + for(std::size_t r = 0; r != num_iterations; ++r){ + l.insert(l.end(), num_elements, MyInt(r)); + } + timer.stop(); + tinsert = timer.elapsed().wall; + + insert_inuse = bc::dlmalloc_in_use_memory(); + insert_stats = bc::dlmalloc_malloc_stats(); +/* + iterator_t it(l.begin()); + iterator_t last(--l.end()); + for(std::size_t n_elem = 0, n_max = l.size()/2-1; n_elem != n_max; ++n_elem) + { + l.splice(it++, l, last--); + } +*/ + //l.reverse(); + + //Now preprocess erase ranges + std::vector ranges_to_erase; + ranges_to_erase.push_back(l.begin()); + for(std::size_t r = 0; r != num_iterations; ++r){ + iterator_t next_pos(ranges_to_erase[r]); + std::size_t n = num_elements; + while(n--){ ++next_pos; } + ranges_to_erase.push_back(next_pos); + } + + //Measure range erasure function + timer.start(); + for(std::size_t r = 0; r != num_iterations; ++r){ + assert((r+1) < ranges_to_erase.size()); + l.erase(ranges_to_erase[r], ranges_to_erase[r+1]); + } + timer.stop(); + terase = timer.elapsed().wall; + erase_inuse = bc::dlmalloc_in_use_memory(); + erase_stats = bc::dlmalloc_malloc_stats(); + } + + + if(csv_output){ + std::cout << get_allocator_name::get() + << ";" + << num_iterations + << ";" + << num_elements + << ";" + << float(tinsert)/(num_iterations*num_elements) + << ";" + << (unsigned int)insert_stats.system_bytes + << ";" + << float(insert_stats.system_bytes)/(num_iterations*num_elements*sizeof_node)*100.0-100.0 + << ";" + << (unsigned int)insert_inuse + << ";" + << (float(insert_inuse)/(num_iterations*num_elements*sizeof_node)*100.0)-100.0 + << ";"; + std::cout << float(terase)/(num_iterations*num_elements) + << ";" + << (unsigned int)erase_stats.system_bytes + << ";" + << (unsigned int)erase_inuse + << std::endl; + } + else{ + std::cout << std::endl + << "Allocator: " << get_allocator_name::get() + << std::endl + << " allocation/deallocation(ns): " << float(tinsert)/(num_iterations*num_elements) << '\t' << float(terase)/(num_iterations*num_elements) + << std::endl + << " Sys MB(overh.)/Inuse MB(overh.): " << (float)insert_stats.system_bytes/(1024*1024) << "(" << float(insert_stats.system_bytes)/(num_iterations*num_elements*sizeof_node)*100.0-100.0 << "%)" + << " / " + << (float)insert_inuse/(1024*1024) << "(" << (float(insert_inuse)/(num_iterations*num_elements*sizeof_node)*100.0)-100.0 << "%)" + << std::endl + << " system MB/inuse bytes after: " << (float)erase_stats.system_bytes/(1024*1024) << '\t' << bc::dlmalloc_in_use_memory() + << std::endl << std::endl; + } + + //Release node_allocator cache + typedef boost::container::dtl::shared_node_pool + < (2*sizeof(void*)+sizeof(int)) + , AdPoolAlignOnlyV2::nodes_per_block> shared_node_pool_t; + boost::container::dtl::singleton_default + ::instance().purge_blocks(); + + //Release adaptive_pool cache + typedef boost::container::dtl::shared_adaptive_node_pool + < (2*sizeof(void*)+sizeof(int)) + , AdPool2PercentV2::nodes_per_block + , AdPool2PercentV2::max_free_blocks + , AdPool2PercentV2::overhead_percent> shared_adaptive_pool_plus_t; + boost::container::dtl::singleton_default + ::instance().deallocate_free_blocks(); + + //Release adaptive_pool cache + typedef boost::container::dtl::shared_adaptive_node_pool + < (2*sizeof(void*)+sizeof(int)) + , AdPool2PercentV2::nodes_per_block + , AdPool2PercentV2::max_free_blocks + , 0u> shared_adaptive_pool_plus_align_only_t; + boost::container::dtl::singleton_default + ::instance().deallocate_free_blocks(); + //Release dlmalloc memory + bc::dlmalloc_trim(0); +} + +void print_header() +{ + std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";" + << "Insertion time(ns)" << ";" + << "System bytes" << ";" + << "System overhead(%)" << ";" + << "In use bytes" << ";" + << "In use overhead(%)" << ";" + << "Erasure time (ns)" << ";" + << "System bytes after" << ";" + << "In use bytes after" + << std::endl; +} + +int main(int argc, const char *argv[]) +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS + std::size_t numrep[] = { 1000 }; + #elif defined(NDEBUG) + std::size_t numrep [] = { 15000 }; + #else + std::size_t numrep [] = { 1000 }; + #endif + std::size_t numele [] = { 100 }; + #elif defined(SIMPLE_IT) + std::size_t numrep [] = { 3 }; + std::size_t numele [] = { 100 }; + #else + #ifdef NDEBUG + std::size_t numrep [] = { 300, 3000, 30000, 300000, 600000, 1500000, 3000000 }; + #else + std::size_t numrep [] = { 20, 200, 2000, 20000, 40000, 100000, 200000 }; + #endif + std::size_t numele [] = { 10000, 1000, 100, 10, 5, 2, 1 }; + #endif + + bool csv_output = argc == 2 && (strcmp(argv[1], "--csv-output") == 0); + + if(csv_output){/* + print_header(); + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + } + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + list_test_template(numrep[i], numele[i], csv_output); + }*/ + } + else{ + for(std::size_t i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + std::cout << "\n ----------------------------------- \n" + << " Iterations/Elements: " << numrep[i] << "/" << numele[i] + << "\n ----------------------------------- \n"; + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + list_test_template(numrep[i], numele[i], csv_output); + } + } + return 0; +} diff --git a/src/boost/libs/container/bench/bench_alloc.cpp b/src/boost/libs/container/bench/bench_alloc.cpp new file mode 100644 index 00000000..e17be111 --- /dev/null +++ b/src/boost/libs/container/bench/bench_alloc.cpp @@ -0,0 +1,188 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#endif + +#include + +#define BOOST_INTERPROCESS_VECTOR_ALLOC_STATS + +#include //std::cout, std::endl +#include //typeid +#include //assert + +#include +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +using namespace boost::container; + +template +void allocation_timing_test(unsigned int num_iterations, unsigned int num_elements) +{ + size_t capacity = 0; + unsigned int numalloc = 0, numexpand = 0; + + std::cout + << " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n" + << " Iterations/Elements: " << num_iterations << "/" << num_elements << '\n' + << " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n" + << std::endl; + + + allocation_type malloc_types[] = { BOOST_CONTAINER_EXPAND_BWD, BOOST_CONTAINER_EXPAND_FWD, BOOST_CONTAINER_ALLOCATE_NEW }; + const char * malloc_names[] = { "Backwards expansion", "Forward expansion", "New allocation" }; + for(size_t i = 0; i < sizeof(malloc_types)/sizeof(allocation_type); ++i){ + numalloc = 0; numexpand = 0; + const allocation_type m_mode = malloc_types[i]; + const char *malloc_name = malloc_names[i]; + + cpu_timer timer; + timer.resume(); + + for(unsigned int r = 0; r != num_iterations; ++r){ + void *first_mem = 0; + if(m_mode != BOOST_CONTAINER_EXPAND_FWD) + first_mem = dlmalloc_malloc(sizeof(POD)*num_elements*3/2); + void *addr = dlmalloc_malloc(1*sizeof(POD)); + if(m_mode == BOOST_CONTAINER_EXPAND_FWD) + first_mem = dlmalloc_malloc(sizeof(POD)*num_elements*3/2); + capacity = dlmalloc_size(addr)/sizeof(POD); + dlmalloc_free(first_mem); + ++numalloc; + + try{ + dlmalloc_command_ret_t ret; + for(size_t e = capacity + 1; e < num_elements; ++e){ + size_t received_size; + size_t min = (capacity+1)*sizeof(POD); + size_t max = (capacity*3/2)*sizeof(POD); + if(min > max) + max = min; + ret = dlmalloc_allocation_command + ( m_mode, sizeof(POD) + , min, max, &received_size, addr); + if(!ret.first){ + std::cout << "(!ret.first)!" << std::endl; + throw int(0); + } + if(!ret.second){ + assert(m_mode == BOOST_CONTAINER_ALLOCATE_NEW); + if(m_mode != BOOST_CONTAINER_ALLOCATE_NEW){ + std::cout << "m_mode != BOOST_CONTAINER_ALLOCATE_NEW!" << std::endl; + return; + } + dlmalloc_free(addr); + addr = ret.first; + ++numalloc; + } + else{ + assert(m_mode != BOOST_CONTAINER_ALLOCATE_NEW); + if(m_mode == BOOST_CONTAINER_ALLOCATE_NEW){ + std::cout << "m_mode == BOOST_CONTAINER_ALLOCATE_NEW!" << std::endl; + return; + } + ++numexpand; + } + capacity = received_size/sizeof(POD); + addr = ret.first; + e = capacity + 1; + } + dlmalloc_free(addr); + } + catch(...){ + dlmalloc_free(addr); + throw; + } + } + + assert( dlmalloc_allocated_memory() == 0); + if(dlmalloc_allocated_memory()!= 0){ + std::cout << "Memory leak!" << std::endl; + return; + } + + timer.stop(); + nanosecond_type nseconds = timer.elapsed().wall; + + std::cout << " Malloc type: " << malloc_name + << std::endl + << " allocation ns: " + << float(nseconds)/(num_iterations*num_elements) + << std::endl + << " capacity - alloc calls (new/expand): " + << (unsigned int)capacity << " - " + << (float(numalloc) + float(numexpand))/num_iterations + << "(" << float(numalloc)/num_iterations << "/" << float(numexpand)/num_iterations << ")" + << std::endl << std::endl; + dlmalloc_trim(0); + } +} + +template +struct char_holder +{ + char ints_[N]; +}; + +template +int allocation_loop() +{ + std::cout << std::endl + << "-------------------------------------------\n" + << "-------------------------------------------\n" + << " Type(sizeof): " << typeid(POD).name() << " (" << sizeof(POD) << ")\n" + << "-------------------------------------------\n" + << "-------------------------------------------\n" + << std::endl; + + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + unsigned int numrep [] = { 50000 }; + #else + unsigned int numrep [] = { 5000 }; + #endif + unsigned int numele [] = { 100 }; + #elif defined(SIMPLE_IT) + unsigned int numrep [] = { 3 }; + unsigned int numele [] = { 100 }; + #else + #ifdef NDEBUG + unsigned int numrep [] = { /*10000, */10000, 100000, 1000000 }; + #else + unsigned int numrep [] = { /*10000, */1000, 10000, 100000 }; + #endif + unsigned int numele [] = { /*10000, */1000, 100, 10 }; + #endif + + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + allocation_timing_test(numrep[i], numele[i]); + } + + return 0; +} + +int main() +{ + dlmalloc_mallopt( (-3)//M_MMAP_THRESHOLD + , 100*10000000); + //allocation_loop >(); + //allocation_loop >(); + allocation_loop >(); + allocation_loop >(); + //allocation_loop >(); + allocation_loop >(); + return 0; +} diff --git a/src/boost/libs/container/bench/bench_alloc_expand_bwd.cpp b/src/boost/libs/container/bench/bench_alloc_expand_bwd.cpp new file mode 100644 index 00000000..d60cf564 --- /dev/null +++ b/src/boost/libs/container/bench/bench_alloc_expand_bwd.cpp @@ -0,0 +1,224 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#endif + +#include + +#define BOOST_CONTAINER_VECTOR_ALLOC_STATS + +#include +#include //std::allocator +#include //std::cout, std::endl +#include //assert + +#include +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +typedef std::allocator StdAllocator; +typedef bc::allocator AllocatorPlusV2Mask; +typedef bc::allocator AllocatorPlusV2; +typedef bc::allocator AllocatorPlusV1; + +template struct get_allocator_name; + +template<> struct get_allocator_name +{ static const char *get() { return "StdAllocator"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV2Mask"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV2"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV1"; } }; + +//typedef int MyInt; + +class MyInt +{ + int int_; + + public: + MyInt(int i = 0) + : int_(i) + {} + + MyInt(const MyInt &other) + : int_(other.int_) + {} + + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } + + ~MyInt() + { + int_ = 0; + } +}; +namespace boost{ + +template +struct has_trivial_destructor_after_move; + +template<> +struct has_trivial_destructor_after_move +{ + static const bool value = true; + //static const bool value = false; +}; + +} //namespace boost{ + + +void print_header() +{ + std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";" + << "Capacity" << ";" << "push_back(ns)" << ";" << "Allocator calls" << ";" + << "New allocations" << ";" << "Bwd expansions" << std::endl; +} + +template +void vector_test_template(unsigned int num_iterations, unsigned int num_elements, bool csv_output) +{ + typedef typename Allocator::template rebind::other IntAllocator; + unsigned int numalloc = 0, numexpand = 0; + + cpu_timer timer; + timer.resume(); + + unsigned int capacity = 0; + for(unsigned int r = 0; r != num_iterations; ++r){ + bc::vector v; + v.reset_alloc_stats(); + void *first_mem = 0; + try{ + first_mem = bc::dlmalloc_malloc(sizeof(MyInt)*num_elements*3/2); + v.push_back(MyInt(0)); + bc::dlmalloc_free(first_mem); + + for(unsigned int e = 0; e != num_elements; ++e){ + v.push_back(MyInt(e)); + } + numalloc += v.num_alloc; + numexpand += v.num_expand_bwd; + capacity = static_cast(v.capacity()); + } + catch(...){ + bc::dlmalloc_free(first_mem); + throw; + } + } + + assert(bc::dlmalloc_allocated_memory() == 0); + + timer.stop(); + nanosecond_type nseconds = timer.elapsed().wall; + + if(csv_output){ + std::cout << get_allocator_name::get() + << ";" + << num_iterations + << ";" + << num_elements + << ";" + << capacity + << ";" + << float(nseconds)/(num_iterations*num_elements) + << ";" + << (float(numalloc) + float(numexpand))/num_iterations + << ";" + << float(numalloc)/num_iterations + << ";" + << float(numexpand)/num_iterations + << std::endl; + } + else{ + std::cout << std::endl + << "Allocator: " << get_allocator_name::get() + << std::endl + << " push_back ns: " + << float(nseconds)/(num_iterations*num_elements) + << std::endl + << " capacity - alloc calls (new/expand): " + << (unsigned int)capacity << " - " + << (float(numalloc) + float(numexpand))/num_iterations + << "(" << float(numalloc)/num_iterations << "/" << float(numexpand)/num_iterations << ")" + << std::endl; + std::cout << '\n' + << " ----------------------------------- " + << std::endl; + } + bc::dlmalloc_trim(0); +} + +int main(int argc, const char *argv[]) +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + unsigned int numit [] = { 10 }; + #else + unsigned int numit [] = { 10 }; + #endif + unsigned int numele [] = { 10000 }; + #elif defined(SIMPLE_IT) + unsigned int numit [] = { 3 }; + unsigned int numele[] = { 10000 }; + #else + #ifdef NDEBUG + unsigned int numit [] = { 2000, 20000, 200000, 2000000 }; + #else + unsigned int numit [] = { 100, 1000, 10000, 100000 }; + #endif + unsigned int numele [] = { 10000, 1000, 100, 10 }; + #endif + + bool csv_output = argc == 2 && (strcmp(argv[1], "--csv-output") == 0); + + if(csv_output){ + print_header(); + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + } + else{ + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + std::cout << "\n ----------------------------------- \n" + << " Iterations/Elements: " << numit[i] << "/" << numele[i] + << "\n ----------------------------------- \n"; + vector_test_template(numit[i], numele[i], csv_output); + vector_test_template(numit[i], numele[i], csv_output); + vector_test_template(numit[i], numele[i], csv_output); + vector_test_template(numit[i], numele[i], csv_output); + } + } + return 0; +} diff --git a/src/boost/libs/container/bench/bench_alloc_expand_fwd.cpp b/src/boost/libs/container/bench/bench_alloc_expand_fwd.cpp new file mode 100644 index 00000000..d03a75e7 --- /dev/null +++ b/src/boost/libs/container/bench/bench_alloc_expand_fwd.cpp @@ -0,0 +1,202 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#pragma warning (disable : 4267) +#pragma warning (disable : 4244) +#endif + +#define BOOST_CONTAINER_VECTOR_ALLOC_STATS + +#include +#include +#include + +#include //std::allocator +#include //std::cout, std::endl +#include //std::strcmp +#include +#include +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +#if defined(BOOST_CONTAINER_VECTOR_ALLOC_STATS) + +template +static void reset_alloc_stats(std::vector &) + {} + +template +static std::size_t get_num_alloc(std::vector &) + { return 0; } + +template +static std::size_t get_num_expand(std::vector &) + { return 0; } + +template +static void reset_alloc_stats(bc::vector &v) + { v.reset_alloc_stats(); } + +template +static std::size_t get_num_alloc(bc::vector &v) + { return v.num_alloc; } + +template +static std::size_t get_num_expand(bc::vector &v) + { return v.num_expand_fwd; } + +#endif //BOOST_CONTAINER_VECTOR_ALLOC_STATS + +class MyInt +{ + int int_; + + public: + explicit MyInt(int i = 0) + : int_(i) + {} + + MyInt(const MyInt &other) + : int_(other.int_) + {} + + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } + + ~MyInt() + { + int_ = 0; + } +}; + +template +void vector_test_template(unsigned int num_iterations, unsigned int num_elements) +{ + unsigned int numalloc = 0, numexpand = 0; + + cpu_timer timer; + timer.resume(); + + unsigned int capacity = 0; + for(unsigned int r = 0; r != num_iterations; ++r){ + Container v; + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + reset_alloc_stats(v); + #endif + //v.reserve(num_elements); + //MyInt a[3]; +/* + for(unsigned int e = 0; e != num_elements/3; ++e){ + v.insert(v.end(), &a[0], &a[0]+3); + }*/ +/* + for(unsigned int e = 0; e != num_elements/3; ++e){ + v.insert(v.end(), 3, MyInt(e)); + }*/ +/* + for(unsigned int e = 0; e != num_elements/3; ++e){ + v.insert(v.empty() ? v.end() : --v.end(), &a[0], &a[0]+3); + }*/ +/* + for(unsigned int e = 0; e != num_elements/3; ++e){ + v.insert(v.empty() ? v.end() : --v.end(), 3, MyInt(e)); + }*/ +/* + for(unsigned int e = 0; e != num_elements/3; ++e){ + v.insert(v.size() >= 3 ? v.end()-3 : v.begin(), &a[0], &a[0]+3); + }*/ +/* + for(unsigned int e = 0; e != num_elements/3; ++e){ + v.insert(v.size() >= 3 ? v.end()-3 : v.begin(), 3, MyInt(e)); + }*/ +/* + for(unsigned int e = 0; e != num_elements; ++e){ + v.insert(v.end(), MyInt(e)); + }*/ +/* + for(unsigned int e = 0; e != num_elements; ++e){ + v.insert(v.empty() ? v.end() : --v.end(), MyInt(e)); + }*/ + + for(unsigned int e = 0; e != num_elements; ++e){ + v.push_back(MyInt(e)); + } + + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + numalloc += get_num_alloc(v); + numexpand += get_num_expand(v); + #endif + capacity = static_cast(v.capacity()); + } + + timer.stop(); + nanosecond_type nseconds = timer.elapsed().wall; + + std::cout << std::endl + << "Allocator: " << typeid(typename Container::allocator_type).name() + << std::endl + << " push_back ns: " + << float(nseconds)/(num_iterations*num_elements) + << std::endl + << " capacity - alloc calls (new/expand): " + << (unsigned int)capacity << " - " + << (float(numalloc) + float(numexpand))/num_iterations + << "(" << float(numalloc)/num_iterations << "/" << float(numexpand)/num_iterations << ")" + << std::endl << std::endl; + bc::dlmalloc_trim(0); +} + +void print_header() +{ + std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";" + << "Capacity" << ";" << "push_back(ns)" << ";" << "Allocator calls" << ";" + << "New allocations" << ";" << "Fwd expansions" << std::endl; +} + +int main() +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + std::size_t numit [] = { 1000 }; + #else + std::size_t numit [] = { 100 }; + #endif + std::size_t numele [] = { 10000 }; + #elif defined SIMPLE_IT + std::size_t numit [] = { 3 }; + std::size_t numele [] = { 10000 }; + #else + #ifdef NDEBUG + unsigned int numit [] = { 1000, 10000, 100000, 1000000 }; + #else + unsigned int numit [] = { 100, 1000, 10000, 100000 }; + #endif + unsigned int numele [] = { 10000, 1000, 100, 10 }; + #endif + + print_header(); + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template< bc::vector > >(numit[i], numele[i]); + vector_test_template< bc::vector > >(numit[i], numele[i]); + vector_test_template > >(numit[i], numele[i]); + vector_test_template > >(numit[i], numele[i]); + } + return 0; +} diff --git a/src/boost/libs/container/bench/bench_alloc_shrink_to_fit.cpp b/src/boost/libs/container/bench/bench_alloc_shrink_to_fit.cpp new file mode 100644 index 00000000..0edb2fea --- /dev/null +++ b/src/boost/libs/container/bench/bench_alloc_shrink_to_fit.cpp @@ -0,0 +1,181 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#endif + +#include + +#define BOOST_CONTAINER_VECTOR_ALLOC_STATS + +#include + +#undef BOOST_CONTAINER_VECTOR_ALLOC_STATS + +#include //std::allocator +#include //std::cout, std::endl +#include //assert + +#include +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +typedef std::allocator StdAllocator; +typedef bc::allocator AllocatorPlusV2; +typedef bc::allocator AllocatorPlusV1; + +template struct get_allocator_name; + +template<> struct get_allocator_name +{ static const char *get() { return "StdAllocator"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV2"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV1"; } }; + +class MyInt +{ + std::size_t int_; //Use a type that will grow on 64 bit machines + + public: + MyInt(int i = 0) : int_(i){} + + MyInt(const MyInt &other) + : int_(other.int_) + {} + + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } +}; + +void print_header() +{ + std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";" + << "num_shrink" << ";" << "shrink_to_fit(ns)" << std::endl; +} + +template +void vector_test_template(unsigned int num_iterations, unsigned int num_elements, bool csv_output) +{ + typedef typename Allocator::template rebind::other IntAllocator; + + unsigned int capacity = 0; + const std::size_t Step = 5; + unsigned int num_shrink = 0; + (void)capacity; + + cpu_timer timer; + timer.resume(); + + #ifndef NDEBUG + typedef bc::dtl::integral_constant + ::value> alloc_version; + #endif + + for(unsigned int r = 0; r != num_iterations; ++r){ + bc::vector v(num_elements); + v.reset_alloc_stats(); + num_shrink = 0; + for(unsigned int e = num_elements; e != 0; e -= Step){ + v.erase(v.end() - Step, v.end()); + v.shrink_to_fit(); + assert( (alloc_version::value != 2) || (e == Step) || (v.num_shrink > num_shrink) ); + num_shrink = v.num_shrink; + } + assert(v.empty()); + assert(0 == v.capacity()); + } + + timer.stop(); + nanosecond_type nseconds = timer.elapsed().wall; + + if(csv_output){ + std::cout << get_allocator_name::get() + << ";" + << num_iterations + << ";" + << num_elements + << ";" + << num_shrink + << ";" + << float(nseconds)/(num_iterations*num_elements) + << std::endl; + } + else{ + std::cout << std::endl + << "Allocator: " << get_allocator_name::get() + << std::endl + << " num_shrink: " << num_shrink + << std::endl + << " shrink_to_fit ns: " + << float(nseconds)/(num_iterations*num_elements) + << std::endl << std::endl; + } + bc::dlmalloc_trim(0); +} + +int main(int argc, const char *argv[]) +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + unsigned int numit [] = { 10 }; + #else + unsigned int numit [] = { 50 }; + unsigned int numele[] = { 2000 }; + #endif + #elif defined SIMPLE_IT + unsigned int numit [] = { 3 }; + unsigned int numele[] = { 2000 }; + #else + #ifdef NDEBUG + unsigned int numit [] = { 100, 1000, 10000 }; + #else + unsigned int numit [] = { 10, 100, 1000 }; + #endif + unsigned int numele [] = { 10000, 2000, 500 }; + #endif + + bool csv_output = argc == 2 && (strcmp(argv[1], "--csv-output") == 0); + + if(csv_output){ + print_header(); + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template(numit[i], numele[i], csv_output); + } + } + else{ + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + std::cout << "\n ----------------------------------- \n" + << " Iterations/Elements: " << numit[i] << "/" << numele[i] + << "\n ----------------------------------- \n"; + vector_test_template(numit[i], numele[i], csv_output); + vector_test_template(numit[i], numele[i], csv_output); + vector_test_template(numit[i], numele[i], csv_output); + } + } + return 0; +} diff --git a/src/boost/libs/container/bench/bench_alloc_stable_vector_burst.cpp b/src/boost/libs/container/bench/bench_alloc_stable_vector_burst.cpp new file mode 100644 index 00000000..1e299b31 --- /dev/null +++ b/src/boost/libs/container/bench/bench_alloc_stable_vector_burst.cpp @@ -0,0 +1,294 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#pragma warning (disable : 4541) +#pragma warning (disable : 4673) +#pragma warning (disable : 4671) +#pragma warning (disable : 4244) +#endif + +#include //std::allocator +#include //std::cout, std::endl +#include //std::vector +#include //std::size_t +#include //assert + +#include +#include +#include +#include +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +typedef std::allocator StdAllocator; +typedef bc::allocator AllocatorPlusV1; +typedef bc::allocator AllocatorPlusV2; +typedef bc::adaptive_pool + < int + , bc::ADP_nodes_per_block + , 0//bc::ADP_max_free_blocks + , 2 + , 2> AdPool2PercentV2; + +template struct get_allocator_name; + +template<> struct get_allocator_name +{ static const char *get() { return "StdAllocator"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV1"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AllocatorPlusV2"; } }; + +template<> struct get_allocator_name +{ static const char *get() { return "AdPool2PercentV2"; } }; + +class MyInt +{ + int int_; + + public: + MyInt(int i = 0) : int_(i){} + MyInt(const MyInt &other) + : int_(other.int_) + {} + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } +}; + +template +struct get_vector +{ + typedef bc::vector + ::other> type; + static const char *vector_name() + { + return "vector"; + } +}; + +template +struct get_stable_vector +{ + typedef bc::stable_vector + ::other> type; + static const char *vector_name() + { + return "stable_vector"; + } +}; + +template class GetContainer, class Allocator> +void stable_vector_test_template(unsigned int num_iterations, unsigned int num_elements, bool csv_output) +{ + typedef typename GetContainer::type vector_type; + //std::size_t top_capacity = 0; + nanosecond_type nseconds; + { + { + vector_type l; + cpu_timer timer; + timer.resume(); + + for(unsigned int r = 0; r != num_iterations; ++r){ + l.insert(l.end(), num_elements, MyInt(r)); + } + + timer.stop(); + nseconds = timer.elapsed().wall; + + if(csv_output){ + std::cout << get_allocator_name::get() + << ";" + << GetContainer::vector_name() + << ";" + << num_iterations + << ";" + << num_elements + << ";" + << float(nseconds)/(num_iterations*num_elements) + << ";"; + } + else{ + std::cout << "Allocator: " << get_allocator_name::get() + << '\t' + << GetContainer::vector_name() + << std::endl + << " allocation ns: " + << float(nseconds)/(num_iterations*num_elements); + } +// top_capacity = l.capacity(); + //Now preprocess ranges to erase + std::vector ranges_to_erase; + ranges_to_erase.push_back(l.begin()); + for(unsigned int r = 0; r != num_iterations; ++r){ + typename vector_type::iterator next_pos(ranges_to_erase[r]); + std::size_t n = num_elements; + while(n--){ ++next_pos; } + ranges_to_erase.push_back(next_pos); + } + + //Measure range erasure function + timer.stop(); + timer.start(); + + for(unsigned int r = 0; r != num_iterations; ++r){ + std::size_t init_pos = (num_iterations-1)-r; + l.erase(ranges_to_erase[init_pos], l.end()); + } + timer.stop(); + nseconds = timer.elapsed().wall; + assert(l.empty()); + } + } + + if(csv_output){ + std::cout << float(nseconds)/(num_iterations*num_elements) + << std::endl; + } + else{ + std::cout << '\t' + << " deallocation ns: " + << float(nseconds)/(num_iterations*num_elements)/* + << std::endl + << " max capacity: " + << static_cast(top_capacity) + << std::endl + << " remaining cap. " + << static_cast(top_capacity - num_iterations*num_elements) + << " (" << (float(top_capacity)/float(num_iterations*num_elements) - 1)*100 << " %)"*/ + << std::endl << std::endl; + } + assert(bc::dlmalloc_all_deallocated()); + bc::dlmalloc_trim(0); +} + +void print_header() +{ + std::cout << "Allocator" << ";" << "Iterations" << ";" << "Size" << ";" + << "Insertion time(ns)" << ";" << "Erasure time(ns)" << ";" + << std::endl; +} + +void stable_vector_operations() +{ + { + bc::stable_vector a(bc::stable_vector::size_type(5), 4); + bc::stable_vector b(a); + bc::stable_vector c(a.cbegin(), a.cend()); + b.insert(b.cend(), 0); + c.pop_back(); + a.assign(b.cbegin(), b.cend()); + a.assign(c.cbegin(), c.cend()); + a.assign(1, 2); + } + { + typedef bc::stable_vector > stable_vector_t; + stable_vector_t a(bc::stable_vector::size_type(5), 4); + stable_vector_t b(a); + stable_vector_t c(a.cbegin(), a.cend()); + b.insert(b.cend(), 0); + c.pop_back(); + assert(static_cast(a.end() - a.begin()) == a.size()); + a.assign(b.cbegin(), b.cend()); + assert(static_cast(a.end() - a.begin()) == a.size()); + a.assign(c.cbegin(), c.cend()); + assert(static_cast(a.end() - a.begin()) == a.size()); + a.assign(1, 2); + assert(static_cast(a.end() - a.begin()) == a.size()); + a.reserve(100); + assert(static_cast(a.end() - a.begin()) == a.size()); + } +} + +int main(int argc, const char *argv[]) +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + unsigned int numit [] = { 40 }; + #else + unsigned int numit [] = { 4 }; + #endif + unsigned int numele [] = { 10000 }; + #elif defined(SIMPLE_IT) + unsigned int numit [] = { 3 }; + unsigned int numele [] = { 10000 }; + #else + #ifdef NDEBUG + unsigned int numit [] = { 40, 400, 4000, 40000 }; + #else + unsigned int numit [] = { 4, 40, 400, 4000 }; + #endif + unsigned int numele [] = { 10000, 1000, 100, 10 }; + #endif + + //Warning: range erasure is buggy. Vector iterators are not stable, so it is not + //possible to cache iterators, but indexes!!! + + bool csv_output = argc == 2 && (strcmp(argv[1], "--csv-output") == 0); + + if(csv_output){ + print_header(); + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + stable_vector_test_template(numit[i], numele[i], csv_output); + } + } + else{ + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + std::cout << "\n ----------------------------------- \n" + << " Iterations/Elements: " << numit[i] << "/" << numele[i] + << "\n ----------------------------------- \n"; + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + stable_vector_test_template(numit[i], numele[i], csv_output); + } + } + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_flat_multiset.cpp b/src/boost/libs/container/bench/bench_flat_multiset.cpp new file mode 100644 index 00000000..6ee7cca1 --- /dev/null +++ b/src/boost/libs/container/bench/bench_flat_multiset.cpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include "boost/container/flat_set.hpp" +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //flat_set vs set + launch_tests< flat_multiset , multiset > + ("flat_multiset", "multiset"); + launch_tests< flat_multiset , multiset > + ("flat_multiset", "multiset"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_flat_set.cpp b/src/boost/libs/container/bench/bench_flat_set.cpp new file mode 100644 index 00000000..8f86ba46 --- /dev/null +++ b/src/boost/libs/container/bench/bench_flat_set.cpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include "boost/container/flat_set.hpp" +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //flat_set vs set + launch_tests< flat_set , set > + ("flat_set", "set"); + launch_tests< flat_set , set > + ("flat_set", "set"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set.cpp b/src/boost/libs/container/bench/bench_set.cpp new file mode 100644 index 00000000..890fd350 --- /dev/null +++ b/src/boost/libs/container/bench/bench_set.cpp @@ -0,0 +1,35 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //set vs std::set + launch_tests< set , std::set > + ("set", "std::set"); + launch_tests< set , std::set > + ("set", "std::set"); + + //set(sizeopt) vs set(!sizeopt) + launch_tests< set, set, std::allocator, tree_assoc_options< optimize_size >::type > > + ("set(sizeopt=true)", "set(sizeopt=false)"); + launch_tests< set, set, std::allocator, tree_assoc_options< optimize_size >::type > > + ("set(sizeopt=true)", "set(sizeopt=false)"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set.hpp b/src/boost/libs/container/bench/bench_set.hpp new file mode 100644 index 00000000..300aba47 --- /dev/null +++ b/src/boost/libs/container/bench/bench_set.hpp @@ -0,0 +1,485 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_BENCH_BENCH_SET_HPP +#define BOOST_CONTAINER_BENCH_BENCH_SET_HPP + +#include +#include +#include //sort +#include +#include +#include +#include +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +#define SIMPLE_IT +#ifdef SIMPLE_IT +static const std::size_t NIter = 3; +#else + #ifdef NDEBUG + static const std::size_t NIter = 250; + #else + static const std::size_t NIter = 25; + #endif +#endif + +static const std::size_t NElements = 1000; + + +void compare_times(cpu_times time_numerator, cpu_times time_denominator){ + std::cout << ((double)time_numerator.wall/(double)time_denominator.wall) << std::endl; + std::cout << "----------------------------------------------" << '\n' << std::endl; +} + +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +boost::container::vector sorted_unique_range_int; +boost::container::vector sorted_range_int; +boost::container::vector random_unique_range_int; +boost::container::vector random_range_int; + +void fill_range_ints() +{ + //sorted_unique_range_int + sorted_unique_range_int.resize(NElements); + for(std::size_t i = 0, max = sorted_unique_range_int.size(); i != max; ++i){ + sorted_unique_range_int[i] = static_cast(i); + } + //sorted_range_int + sorted_range_int = sorted_unique_range_int; + sorted_range_int.insert(sorted_range_int.end(), sorted_unique_range_int.begin(), sorted_unique_range_int.end()); + std::sort(sorted_range_int.begin(), sorted_range_int.end()); + + //random_range_int + std::srand(0); + random_range_int.assign(sorted_range_int.begin(), sorted_range_int.end()); + ::random_shuffle(random_range_int.begin(), random_range_int.end()); + //random_unique_range_int + std::srand(0); + random_unique_range_int.assign(sorted_unique_range_int.begin(), sorted_unique_range_int.end()); + ::random_shuffle(random_unique_range_int.begin(), random_unique_range_int.end()); +} + +boost::container::vector sorted_unique_range_string; +boost::container::vector sorted_range_string; +boost::container::vector random_unique_range_string; +boost::container::vector random_range_string; + +void fill_range_strings() +{ + boost::container::string model_s; + model_s.append(sizeof(boost::container::string), '*'); + + //sorted_unique_range_int + sorted_unique_range_string.resize(NElements); + std::stringstream sstr; + + for(std::size_t i = 0, max = sorted_unique_range_string.size(); i != max; ++i){ + sstr.str(std::string()); + sstr << std::setfill('0') << std::setw(10) << i; + sorted_unique_range_string[i] = model_s; + const std::string &s = sstr.str(); + sorted_unique_range_string[i].append(s.begin(), s.end()); + } + //sorted_range_string + sorted_range_string = sorted_unique_range_string; + sorted_range_string.insert(sorted_range_string.end(), sorted_unique_range_string.begin(), sorted_unique_range_string.end()); + std::sort(sorted_range_string.begin(), sorted_range_string.end()); + + //random_range_string + std::srand(0); + random_range_string.assign(sorted_range_string.begin(), sorted_range_string.end()); + ::random_shuffle(random_range_string.begin(), random_range_string.end()); + //random_unique_range_string + std::srand(0); + random_unique_range_string.assign(sorted_unique_range_string.begin(), sorted_unique_range_string.end()); + ::random_shuffle(random_unique_range_string.begin(), random_unique_range_string.end()); +} + +template +struct range_provider; + +template<> +struct range_provider +{ + typedef boost::container::vector type; + + static type &sorted_unique() + { return sorted_unique_range_int; } + + static type &sorted() + { return sorted_range_int; } + + static type &random_unique() + { return random_unique_range_int; } + + static type &random() + { return random_range_int; } +}; + +template<> +struct range_provider +{ + typedef boost::container::vector type; + + static type &sorted_unique() + { return sorted_unique_range_string; } + + static type &sorted() + { return sorted_range_string; } + + static type &random_unique() + { return random_unique_range_string; } + + static type &random() + { return random_range_string; } +}; + +template +cpu_times copy_destroy_time(boost::container::vector &unique_range) +{ + cpu_timer copy_timer, assign_timer, destroy_timer; + + cpu_timer total_time; + + for(std::size_t i = 0; i != NIter; ++i){ + { + C c(unique_range.begin(), unique_range.end()); + total_time.resume(); + copy_timer.resume(); + C caux(c); + copy_timer.stop(); + assign_timer.resume(); + c = caux; + assign_timer.stop(); + destroy_timer.resume(); + } + destroy_timer.stop(); + total_time.stop(); + } + total_time.stop(); + + std::cout << " Copy sorted range " << boost::timer::format(copy_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Assign sorted range " << boost::timer::format(assign_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Destroy " << boost::timer::format(destroy_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl; + return total_time.elapsed(); +} + +template +cpu_times construct_time( boost::container::vector &unique_range + , boost::container::vector &range + , const char *RangeType) +{ + cpu_timer sur_timer, sr_timer; + + cpu_timer total_time; + + for(std::size_t i = 0; i != NIter; ++i){ + { + sur_timer.resume(); + total_time.resume(); + C c(unique_range.begin(), unique_range.end()); + sur_timer.stop(); + total_time.stop(); + } + { + total_time.resume(); + sr_timer.resume(); + C c(range.begin(), range.end()); + sr_timer.stop(); + total_time.stop(); + } + } + + std::cout << " Construct " << RangeType << " unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Construct " << RangeType << " range " << boost::timer::format(sr_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl; + return total_time.elapsed(); +} + +template +cpu_times insert_time( boost::container::vector &unique_range + , boost::container::vector &range + , const char *RangeType) +{ + cpu_timer ur_timer,r_timer; + ur_timer.stop();r_timer.stop(); + + cpu_timer total_time; + total_time.resume(); + + for(std::size_t i = 0; i != NIter; ++i){ + { + total_time.resume(); + ur_timer.resume(); + C c; + c.insert(unique_range.begin(), unique_range.end()); + ur_timer.stop(); + total_time.stop(); + } + { + total_time.resume(); + r_timer.resume(); + C c; + c.insert(range.begin(), range.end()); + r_timer.stop(); + total_time.stop(); + } + } + + std::cout << " Insert " << RangeType << " unique_range " << boost::timer::format(ur_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Insert " << RangeType << " range " << boost::timer::format(r_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl; + return total_time.elapsed(); +} + +template +bool check_not_end(boost::container::vector &iterators, Iterator itend, std::size_t number_of_ends = 0) +{ + std::size_t end_count = 0; + for(std::size_t i = 0, max = iterators.size(); i != max; ++i){ + if(iterators[i] == itend && (++end_count > number_of_ends) ) + return false; + } + return true; +} + +template +bool check_all_not_empty(boost::container::vector< std::pair > &iterator_pairs) +{ + for(std::size_t i = 0, max = iterator_pairs.size(); i != max; ++i){ + if(iterator_pairs[i].first == iterator_pairs[i].second) + return false; + } + return true; +} + +template +cpu_times search_time(boost::container::vector &unique_range, const char *RangeType) +{ + cpu_timer find_timer, lower_timer, upper_timer, equal_range_timer, count_timer; + + C c(unique_range.begin(), unique_range.end()); + + cpu_timer total_time; + total_time.resume(); + + boost::container::vector v_it(NElements); + boost::container::vector< std::pair > v_itp(NElements); + + for(std::size_t i = 0; i != NIter; ++i){ + //Find + { + find_timer.resume(); + for(std::size_t rep = 0; rep != 2; ++rep) + for(std::size_t j = 0, max = unique_range.size(); j != max; ++j){ + v_it[j] = c.find(unique_range[j]); + } + find_timer.stop(); + if(!check_not_end(v_it, c.end())){ + std::cout << "ERROR! find all elements not found" << std::endl; + } + } + //Lower + { + lower_timer.resume(); + for(std::size_t rep = 0; rep != 2; ++rep) + for(std::size_t j = 0, max = unique_range.size(); j != max; ++j){ + v_it[j] = c.lower_bound(unique_range[j]); + } + lower_timer.stop(); + if(!check_not_end(v_it, c.end())){ + std::cout << "ERROR! lower_bound all elements not found" << std::endl; + } + } + //Upper + { + upper_timer.resume(); + for(std::size_t rep = 0; rep != 2; ++rep) + for(std::size_t j = 0, max = unique_range.size(); j != max; ++j){ + v_it[j] = c.upper_bound(unique_range[j]); + } + upper_timer.stop(); + if(!check_not_end(v_it, c.end(), 1u)){ + std::cout << "ERROR! upper_bound all elements not found" << std::endl; + } + } + //Equal + { + equal_range_timer.resume(); + for(std::size_t rep = 0; rep != 2; ++rep) + for(std::size_t j = 0, max = unique_range.size(); j != max; ++j){ + v_itp[j] = c.equal_range(unique_range[j]); + } + equal_range_timer.stop(); + if(!check_all_not_empty(v_itp)){ + std::cout << "ERROR! equal_range all elements not found" << std::endl; + } + } + //Count + { + std::size_t count = 0; + count_timer.resume(); + for(std::size_t rep = 0; rep != 2; ++rep) + for(std::size_t j = 0, max = unique_range.size(); j != max; ++j){ + count += c.count(unique_range[j]); + } + count_timer.stop(); + if(count/2 != c.size()){ + std::cout << "ERROR! count all elements not found" << std::endl; + } + } + } + total_time.stop(); + + std::cout << " Find " << RangeType << " " << boost::timer::format(find_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Lower Bound " << RangeType << " " << boost::timer::format(lower_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Upper Bound " << RangeType << " " << boost::timer::format(upper_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Equal Range " << RangeType << " " << boost::timer::format(equal_range_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Count " << RangeType << " " << boost::timer::format(count_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Total time = " << boost::timer::format(total_time.elapsed(), boost::timer::default_places, "%ws\n") << std::endl; + return total_time.elapsed(); +} + +template +void extensions_time(boost::container::vector &sorted_unique_range) +{ + cpu_timer sur_timer,sur_opt_timer; + sur_timer.stop();sur_opt_timer.stop(); + + for(std::size_t i = 0; i != NIter; ++i){ + { + sur_timer.resume(); + C c(sorted_unique_range.begin(), sorted_unique_range.end()); + sur_timer.stop(); + } + { + sur_opt_timer.resume(); + C c(boost::container::ordered_unique_range, sorted_unique_range.begin(), sorted_unique_range.end()); + sur_opt_timer.stop(); + } + + } + std::cout << " Construct sorted_unique_range " << boost::timer::format(sur_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << " Construct sorted_unique_range (extension) " << boost::timer::format(sur_opt_timer.elapsed(), boost::timer::default_places, "%ws\n"); + std::cout << "Extension/Standard: "; + compare_times(sur_opt_timer.elapsed(), sur_timer.elapsed()); +} + +template +void launch_tests(const char *BoostContName, const char *StdContName) +{ + typedef range_provider get_range_t; + try { + std::cout << "**********************************************" << '\n'; + std::cout << "**********************************************" << '\n'; + std::cout << '\n'; + std::cout << BoostContName << " .VS " << StdContName << '\n'; + std::cout << '\n'; + std::cout << "**********************************************" << '\n'; + std::cout << "**********************************************" << '\n' << std::endl; + { + std::cout << "Copy/Assign/Destroy benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = copy_destroy_time< BoostClass >(get_range_t::sorted_unique()); + + std::cout << "Copy/Assign/Destroy benchmark:" << StdContName << std::endl; + cpu_times std_set_time = copy_destroy_time< StdClass >(get_range_t::sorted_unique()); + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Ordered construct benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = construct_time< BoostClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)"); + + std::cout << "Ordered construct benchmark:" << StdContName << std::endl; + cpu_times std_set_time = construct_time< StdClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)");; + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Random construct benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = construct_time< BoostClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)"); + + std::cout << "Random construct benchmark:" << StdContName << std::endl; + cpu_times std_set_time = construct_time< StdClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)");; + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Ordered Insert benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = insert_time< BoostClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)"); + + std::cout << "Ordered Insert benchmark:" << StdContName << std::endl; + cpu_times std_set_time = insert_time< StdClass >(get_range_t::sorted_unique(), get_range_t::sorted(), "(ord)"); + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Random Insert benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = insert_time< BoostClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)"); + + std::cout << "Random Insert benchmark:" << StdContName << std::endl; + cpu_times std_set_time = insert_time< StdClass >(get_range_t::random_unique(), get_range_t::random(), "(rnd)"); + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Ordered Search benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = search_time< BoostClass >(get_range_t::sorted_unique(), "(ord)"); + + std::cout << "Ordered Search benchmark:" << StdContName << std::endl; + cpu_times std_set_time = search_time< StdClass >(get_range_t::sorted_unique(), "(ord)"); + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Random Search benchmark:" << BoostContName << std::endl; + cpu_times boost_set_time = search_time< BoostClass >(get_range_t::random_unique(), "(rnd)"); + + std::cout << "Random Search benchmark:" << StdContName << std::endl; + cpu_times std_set_time = search_time< StdClass >(get_range_t::random_unique(), "(rnd)"); + + std::cout << BoostContName << "/" << StdContName << ": "; + compare_times(boost_set_time, std_set_time); + } + { + std::cout << "Extensions benchmark:" << BoostContName << std::endl; + extensions_time< BoostClass >(get_range_t::sorted_unique()); + } + + }catch(std::exception &e){ + std::cout << e.what(); + } +} + +#endif //#ifndef BOOST_CONTAINER_BENCH_BENCH_SET_HPP diff --git a/src/boost/libs/container/bench/bench_set_adaptive_pool.cpp b/src/boost/libs/container/bench/bench_set_adaptive_pool.cpp new file mode 100644 index 00000000..dc5f4762 --- /dev/null +++ b/src/boost/libs/container/bench/bench_set_adaptive_pool.cpp @@ -0,0 +1,34 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//Enable checks in debug mode +#ifndef NDEBUG +#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS +#endif + +#include "bench_set.hpp" +#include +#include +#include + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //set<..., adaptive_pool> vs. set + launch_tests< set, private_adaptive_pool >, set > + ("set", "set"); + launch_tests< set, private_adaptive_pool >, set > + ("set", "set"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set_alloc_v2.cpp b/src/boost/libs/container/bench/bench_set_alloc_v2.cpp new file mode 100644 index 00000000..9c2fb9be --- /dev/null +++ b/src/boost/libs/container/bench/bench_set_alloc_v2.cpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "bench_set.hpp" +#include +#include + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //set<..., version_2> vs. set + launch_tests< set, allocator >, set > + ("set", "set"); + launch_tests< set, allocator >, set > + ("set", "set"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set_avl.cpp b/src/boost/libs/container/bench/bench_set_avl.cpp new file mode 100644 index 00000000..6d0d77d7 --- /dev/null +++ b/src/boost/libs/container/bench/bench_set_avl.cpp @@ -0,0 +1,38 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include + +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //set(AVL) vs set(RB) + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type >, set > + ("set(AVL)", "set(RB)"); + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type >, set > + ("set(AVL)", "set(RB)"); + + //set(AVL,sizeopt) vs set(AVL,!sizeopt) + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type > + , set, std::allocator, tree_assoc_options< tree_type, optimize_size >::type > > + ("set(AVL,sizeopt=true)", "set(AVL,sizeopt=false)"); + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type > + , set, std::allocator, tree_assoc_options< tree_type, optimize_size >::type > > + ("set(AVL,sizeopt=true)", "set(AVL,sizeopt=false)"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set_multi.cpp b/src/boost/libs/container/bench/bench_set_multi.cpp new file mode 100644 index 00000000..a01dbc9f --- /dev/null +++ b/src/boost/libs/container/bench/bench_set_multi.cpp @@ -0,0 +1,30 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include + +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //multiset vs std::multiset + launch_tests< multiset , std::multiset > + ("multiset", "std::multiset"); + launch_tests< multiset , std::multiset > + ("multiset", "std::multiset"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set_sg.cpp b/src/boost/libs/container/bench/bench_set_sg.cpp new file mode 100644 index 00000000..c9884388 --- /dev/null +++ b/src/boost/libs/container/bench/bench_set_sg.cpp @@ -0,0 +1,28 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //set(RB) vs set(SG) + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type >, set > + ("set(SG)", "set(RB)"); + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type >, set > + ("set(SG)", "set(RB)"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_set_sp.cpp b/src/boost/libs/container/bench/bench_set_sp.cpp new file mode 100644 index 00000000..0f86ed48 --- /dev/null +++ b/src/boost/libs/container/bench/bench_set_sp.cpp @@ -0,0 +1,28 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include "boost/container/set.hpp" +#include "bench_set.hpp" + +int main() +{ + using namespace boost::container; + + fill_range_ints(); + fill_range_strings(); + + //set(RB) vs set(SP) + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type >, set > + ("set(SP)", "set(RB)"); + launch_tests< set, std::allocator, tree_assoc_options< tree_type >::type >, set > + ("set(SP)", "set(RB)"); + + return 0; +} diff --git a/src/boost/libs/container/bench/bench_static_vector.cpp b/src/boost/libs/container/bench/bench_static_vector.cpp new file mode 100644 index 00000000..d9dd8a78 --- /dev/null +++ b/src/boost/libs/container/bench/bench_static_vector.cpp @@ -0,0 +1,144 @@ +// benchmark based on: http://cpp-next.com/archive/2010/10/howards-stl-move-semantics-benchmark/ +// +// @file bench_static_vector.cpp +// @date Aug 14, 2011 +// @author Andrew Hundt +// +// (C) Copyright 2011-2013 Andrew Hundt +// (C) Copyright 2013-2013 Ion Gaztanaga +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// @brief varray_benchmark.cpp compares the performance of boost::container::varray to boost::container::vector + +#include "varray.hpp" +#include "boost/container/vector.hpp" +#include "boost/container/static_vector.hpp" +#include "../test/movable_int.hpp" +#include +#include +#include +#include +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +static const std::size_t N = 500; + +#ifdef NDEBUG +static const std::size_t Iter = 50; +#else +static const std::size_t Iter = 5; +#endif + +//#define BENCH_SIMPLE_CONSTRUCTION +//#define BENCH_TRIVIAL_TYPE + +#ifdef BENCH_TRIVIAL_TYPE +typedef std::size_t basic_type_t; +#else +typedef boost::container::test::copyable_int basic_type_t; +#endif + +template +T &get_set(std::size_t) +{ + #ifdef BENCH_SIMPLE_CONSTRUCTION + T &t = *new T(N); + for (std::size_t i = 0; i < N; ++i) + t[i] = basic_type_t(std::rand()); + #else + T &t = *new T; + t.reserve(N); + for (std::size_t i = 0; i < N; ++i) + t.push_back(basic_type_t(std::rand())); + #endif + return t; +} + +template +T &generate() +{ + T &v = *new T; + v.reserve(N); + + for (std::size_t i = 0; i < N; ++i){ + typename T::reference r = get_set(i); + v.push_back(boost::move(r)); + delete &r; + } + return v; +} + +template +cpu_times time_it() +{ + cpu_timer sortTime,rotateTime,destructionTime; + sortTime.stop();rotateTime.stop();destructionTime.stop(); + cpu_timer totalTime, constructTime; + std::srand (0); + for(std::size_t i = 0; i< Iter; ++i){ + constructTime.resume(); + { + T &v = generate(); + constructTime.stop(); + sortTime.resume(); + std::sort(v.begin(), v.end()); + sortTime.stop(); + rotateTime.resume(); + std::rotate(v.begin(), v.begin() + v.size()/2, v.end()); + rotateTime.stop(); + destructionTime.resume(); + delete &v; + } + destructionTime.stop(); + } + totalTime.stop(); + std::cout << " construction took " << boost::timer::format(constructTime.elapsed(), 6, "%ws wall, %ts CPU (%p%)\n"); + std::cout << " sort took " << boost::timer::format(sortTime.elapsed(), 6, "%ws wall, %ts CPU (%p%)\n"); + std::cout << " rotate took " << boost::timer::format(rotateTime.elapsed(), 6, "%ws wall, %ts CPU (%p%)\n"); + std::cout << " destruction took " << boost::timer::format(destructionTime.elapsed(), 6, "%ws wall, %ts CPU (%p%)\n"); + std::cout << " Total time = " << boost::timer::format(totalTime.elapsed(), 6, "%ws wall, %ts CPU (%p%)\n") << std::endl; + return totalTime.elapsed(); +} + +void compare_times(cpu_times time_numerator, cpu_times time_denominator){ + std::cout + << "\n wall = " << ((double)time_numerator.wall/(double)time_denominator.wall) + << "\n (user+sys) = " << ((double)(time_numerator.system+time_numerator.user)/(double)(time_denominator.system+time_denominator.user)) << "\n\n"; +} + +int main() +{ + try { + std::cout << "N = " << N << " Iter = " << Iter << "\n\n"; + + std::cout << "varray benchmark:" << std::endl; + cpu_times time_varray = time_it,N > >(); + + std::cout << "boost::container::static_vector benchmark" << std::endl; + cpu_times time_boost_static_vector = time_it,N > >(); + + std::cout << "boost::container::vector benchmark" << std::endl; + cpu_times time_boost_vector = time_it > >(); + + std::cout << "std::vector benchmark" << std::endl; + cpu_times time_standard_vector = time_it > >(); + + std::cout << "varray/boost::container::vector total time comparison:"; + compare_times(time_varray, time_boost_vector); + + std::cout << "varray/boost::container::static_vector total time comparison:"; + compare_times(time_varray, time_boost_static_vector); + + std::cout << "varray/std::vector total time comparison:"; + compare_times(time_varray,time_standard_vector); + }catch(std::exception &e){ + std::cout << e.what(); + } + return 0; +} diff --git a/src/boost/libs/container/bench/detail/varray.hpp b/src/boost/libs/container/bench/detail/varray.hpp new file mode 100644 index 00000000..6db4f1e5 --- /dev/null +++ b/src/boost/libs/container/bench/detail/varray.hpp @@ -0,0 +1,2242 @@ +// Boost.Container varray +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// Copyright (c) 2014-2014 Ion Gaztanaga +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_DETAIL_VARRAY_HPP +#define BOOST_CONTAINER_DETAIL_VARRAY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include //algo_equal(), algo_lexicographical_compare +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include +#include +#include +#include +#include //adl_move_swap + + +#include "varray_util.hpp" + +#include +#include + +#include + +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif // BOOST_NO_EXCEPTIONS + + +/** + * @defgroup varray_non_member varray non-member functions + */ + +namespace boost { namespace container { namespace dtl { + +// Forward declaration +template +class varray; + +namespace strategy { + +// TODO: Improve error messages +// possibly include N in the strategy, and provide size as an optoinal allocate_failed parameter? +// Example of current error with reserve(4) when capacity is 3: +// "boost/container/varray.hpp(66): size can't exceed the capacity" +// Could say +// "cannot reserve(4) due to fixed capacity of 3 elements" + +//! @brief The default strategy. +//! +//! @tparam Value Type of element stored in the container. +template +struct def +{ + typedef Value value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef Value* pointer; + typedef const Value* const_pointer; + typedef Value& reference; + typedef const Value& const_reference; + + static void allocate_failed() + { + BOOST_ASSERT_MSG(false, "size can't exceed the capacity"); + } +}; + +//! @brief The strategy adapting info from passed Allocator. +//! +//! This strategy defines the same types that are defined in the Allocator. +//! +//! @tparam Allocator The Allocator which will be adapted. +template +struct allocator_adaptor +{ + typedef typename Allocator::value_type value_type; + typedef typename Allocator::size_type size_type; + typedef typename Allocator::difference_type difference_type; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + + static void allocate_failed() + { + BOOST_ASSERT_MSG(false, "size can't exceed the capacity"); + } +}; + +} // namespace strategy + +struct varray_error_handler +{ + template + static void check_capacity(varray const&, std::size_t s) + { + if ( Capacity < s ) + S::allocate_failed(); + } + + template + static void check_at(varray const& v, + typename varray::size_type i) + { + (void)v; + (void)i; +// TODO - use BOOST_THROW_EXCEPTION here? +#ifndef BOOST_NO_EXCEPTIONS + if ( v.size() <= i ) + throw std::out_of_range("index out of bounds"); +#else // BOOST_NO_EXCEPTIONS + BOOST_ASSERT_MSG(i < v.size(), "index out of bounds"); +#endif // BOOST_NO_EXCEPTIONS + } + + template + static void check_operator_brackets(varray const& v, + typename varray::size_type i) + { + (void)v; + (void)i; + BOOST_ASSERT_MSG(i < v.size(), "index out of bounds"); + } + + template + static void check_empty(varray const& v) + { + (void)v; + BOOST_ASSERT_MSG(0 < v.size(), "the container is empty"); + } + + template + static void check_iterator_end_neq(varray const& v, + typename varray::const_iterator position) + { + (void)v; + (void)position; + BOOST_ASSERT_MSG(v.begin() <= position && position < v.end(), "iterator out of bounds"); + } + + template + static void check_iterator_end_eq(varray const& v, + typename varray::const_iterator position) + { + (void)v; + (void)position; + BOOST_ASSERT_MSG(v.begin() <= position && position <= v.end(), "iterator out of bounds"); + } +}; + +template +struct varray_traits +{ + typedef typename Strategy::value_type value_type; + typedef typename Strategy::size_type size_type; + typedef typename Strategy::difference_type difference_type; + typedef typename Strategy::pointer pointer; + typedef typename Strategy::const_pointer const_pointer; + typedef typename Strategy::reference reference; + typedef typename Strategy::const_reference const_reference; + + typedef varray_error_handler error_handler; + + typedef false_type use_memop_in_swap_and_move; + typedef false_type use_optimized_swap; + typedef false_type disable_trivial_init; +}; + +/** + * @brief A variable-size array container with fixed capacity. + * + * varray is a sequence container like boost::container::vector with contiguous storage that can + * change in size, along with the static allocation, low overhead, and fixed capacity of boost::array. + * + * A varray is a sequence that supports random access to elements, constant time insertion and + * removal of elements at the end, and linear time insertion and removal of elements at the beginning or + * in the middle. The number of elements in a varray may vary dynamically up to a fixed capacity + * because elements are stored within the object itself similarly to an array. However, objects are + * initialized as they are inserted into varray unlike C arrays or std::array which must construct + * all elements on instantiation. The behavior of varray enables the use of statically allocated + * elements in cases with complex object lifetime requirements that would otherwise not be trivially + * possible. + * + * @par Error Handling + * Insertion beyond the capacity and out of bounds errors result in undefined behavior unless + * otherwise specified. In this respect if size() == capacity(), then varray::push_back() + * behaves like std::vector pop_front() if size() == empty(). The reason for this difference + * is because unlike vectors, varray does not perform allocation. + * + * @par Advanced Usage + * Error handling behavior can be modified to more closely match std::vector exception behavior + * when exceeding bounds by providing an alternate Strategy and varray_traits instantiation. + * + * @tparam Value The type of element that will be stored. + * @tparam Capacity The maximum number of elements varray can store, fixed at compile time. + * @tparam Strategy Defines the public typedefs and error handlers, + * implements StaticVectorStrategy and has some similarities + * to an Allocator. + */ +template > +class varray +{ + typedef dtl::varray_traits< + Value, Capacity, Strategy + > vt; + + typedef typename vt::error_handler errh; + typedef typename aligned_storage< + sizeof(Value[Capacity]), + boost::container::dtl::alignment_of::value + >::type aligned_storage_type; + + template + friend class varray; + + BOOST_COPYABLE_AND_MOVABLE(varray) + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES +public: + template + varray & operator=(varray & sv) + { + typedef varray other; + this->operator=(static_cast &>(const_cast(sv))); + return *this; + } +#endif + +public: + //! @brief The type of elements stored in the container. + typedef typename vt::value_type value_type; + //! @brief The unsigned integral type used by the container. + typedef typename vt::size_type size_type; + //! @brief The pointers difference type. + typedef typename vt::difference_type difference_type; + //! @brief The pointer type. + typedef typename vt::pointer pointer; + //! @brief The const pointer type. + typedef typename vt::const_pointer const_pointer; + //! @brief The value reference type. + typedef typename vt::reference reference; + //! @brief The value const reference type. + typedef typename vt::const_reference const_reference; + + //! @brief The iterator type. + typedef pointer iterator; + //! @brief The const iterator type. + typedef const_pointer const_iterator; + //! @brief The reverse iterator type. + typedef boost::container::reverse_iterator reverse_iterator; + //! @brief The const reverse iterator. + typedef boost::container::reverse_iterator const_reverse_iterator; + + //! @brief The type of a strategy used by the varray. + typedef Strategy strategy_type; + + //! @brief Constructs an empty varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + varray() + : m_size(0) + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a varray containing count value initialized Values. + //! + //! @param count The number of values which will be contained in the container. + //! + //! @par Throws + //! If Value's value initialization throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + explicit varray(size_type count) + : m_size(0) + { + this->resize(count); // may throw + } + + //! @pre count <= capacity() + //! + //! @brief Constructs a varray containing count copies of value. + //! + //! @param count The number of copies of a values that will be contained in the container. + //! @param value The value which will be used to copy construct values. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + varray(size_type count, value_type const& value) + : m_size(0) + { + this->resize(count, value); // may throw + } + + //! @pre + //! @li distance(first, last) <= capacity() + //! @li Iterator must meet the \c ForwardIterator. + //! + //! @brief Constructs a varray containing copy of a range [first, last). + //! + //! @param first The iterator to the first element in range. + //! @param last The iterator to the one after the last element in range. + //! + //! @par Throws + //! If Value's constructor taking a dereferenced Iterator throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template + varray(Iterator first, Iterator last) + : m_size(0) + { + this->assign(first, last); // may throw + } + + //! @brief Constructs a copy of other varray. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + varray(varray const& other) + : m_size(other.size()) + { + namespace sv = varray_detail; + sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw + } + + //! @pre other.size() <= capacity(). + //! + //! @brief Constructs a copy of other varray. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template + varray(varray const& other) + : m_size(other.size()) + { + errh::check_capacity(*this, other.size()); // may throw + + namespace sv = varray_detail; + sv::uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw + } + + //! @brief Copy assigns Values stored in the other varray to this one. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_COPY_ASSIGN_REF(varray) other) + { + this->assign(other.begin(), other.end()); // may throw + + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Copy assigns Values stored in the other varray to this one. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template +// TEMPORARY WORKAROUND +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + varray & operator=(::boost::rv< varray > const& other) +#else + varray & operator=(varray const& other) +#endif + { + this->assign(other.begin(), other.end()); // may throw + + return *this; + } + + //! @brief Move constructor. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + varray(BOOST_RV_REF(varray) other) + { + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_ctor_dispatch(other, use_memop_in_swap_and_move()); + } + + //! @pre other.size() <= capacity() + //! + //! @brief Move constructor. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is false_type - default. + //! @endinternal + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template + varray(BOOST_RV_REF_3_TEMPL_ARGS(varray, value_type, C, S) other) + : m_size(other.m_size) + { + errh::check_capacity(*this, other.size()); // may throw + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_ctor_dispatch(other, use_memop_in_swap_and_move()); + } + + //! @brief Move assignment. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_RV_REF(varray) other) + { + if ( &other == this ) + return *this; + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_assign_dispatch(other, use_memop_in_swap_and_move()); + + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Move assignment. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move is \c false_type - default. + //! @endinternal + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template + varray & operator=(BOOST_RV_REF_3_TEMPL_ARGS(varray, value_type, C, S) other) + { + errh::check_capacity(*this, other.size()); // may throw + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + this->move_assign_dispatch(other, use_memop_in_swap_and_move()); + + return *this; + } + + //! @brief Destructor. Destroys Values stored in this container. + //! + //! @par Throws + //! Nothing + //! + //! @par Complexity + //! Linear O(N). + ~varray() + { + namespace sv = varray_detail; + sv::destroy(this->begin(), this->end()); + } + + //! @brief Swaps contents of the other varray and this one. + //! + //! @param other The varray which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default. + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void swap(varray & other) + { + typedef typename + vt::use_optimized_swap use_optimized_swap; + + this->swap_dispatch(other, use_optimized_swap()); + } + + //! @pre other.size() <= capacity() && size() <= other.capacity() + //! + //! @brief Swaps contents of the other varray and this one. + //! + //! @param other The varray which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! @internal + //! @li It throws only if \c use_memop_in_swap_and_move and \c use_optimized_swap are \c false_type - default. + //! @endinternal + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template + void swap(varray & other) + { + errh::check_capacity(*this, other.size()); + errh::check_capacity(other, this->size()); + + typedef typename + vt::use_optimized_swap use_optimized_swap; + + this->swap_dispatch(other, use_optimized_swap()); + } + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are value initialized. + //! + //! @param count The number of elements which will be stored in the container. + //! + //! @par Throws + //! If Value's value initialization throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count) + { + namespace sv = varray_detail; + typedef typename vt::disable_trivial_init dti; + + if ( count < m_size ) + { + sv::destroy(this->begin() + count, this->end()); + } + else + { + errh::check_capacity(*this, count); // may throw + + sv::uninitialized_fill(this->end(), this->begin() + count, dti()); // may throw + } + m_size = count; // update end + } + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are copy constructed from value. + //! + //! @param count The number of elements which will be stored in the container. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count, value_type const& value) + { + if ( count < m_size ) + { + namespace sv = varray_detail; + sv::destroy(this->begin() + count, this->end()); + } + else + { + errh::check_capacity(*this, count); // may throw + + std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw + } + m_size = count; // update end + } + + //! @pre count <= capacity() + //! + //! @brief This call has no effect because the Capacity of this container is constant. + //! + //! @param count The number of elements which the container should be able to contain. + //! + //! @par Throws + //! Nothing. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + void reserve(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + //! @pre size() < capacity() + //! + //! @brief Adds a copy of value at the end. + //! + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant O(1). + void push_back(value_type const& value) + { + typedef typename vt::disable_trivial_init dti; + + errh::check_capacity(*this, m_size + 1); // may throw + + namespace sv = varray_detail; + sv::construct(dti(), this->end(), value); // may throw + ++m_size; // update end + } + + //! @pre size() < capacity() + //! + //! @brief Moves value to the end. + //! + //! @param value The value to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant O(1). + void push_back(BOOST_RV_REF(value_type) value) + { + typedef typename vt::disable_trivial_init dti; + + errh::check_capacity(*this, m_size + 1); // may throw + + namespace sv = varray_detail; + sv::construct(dti(), this->end(), ::boost::move(value)); // may throw + ++m_size; // update end + } + + //! @pre !empty() + //! + //! @brief Destroys last value and decreases the size. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + void pop_back() + { + errh::check_empty(*this); + + namespace sv = varray_detail; + sv::destroy(this->end() - 1); + --m_size; // update end + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a copy of element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws + //! @li If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, value_type const& value) + { + return this->priv_insert(position, value); + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a move-constructed element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, BOOST_RV_REF(value_type) value) + { + return this->priv_insert(position, boost::move(value)); + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() + count <= capacity() + //! + //! @brief Inserts a count copies of value at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param count The number of new elements which will be inserted. + //! @param value The value used to copy construct new elements. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws. + //! @li If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + iterator insert(iterator position, size_type count, value_type const& value) + { + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + count); // may throw + + if ( position == this->end() ) + { + std::uninitialized_fill(position, position + count, value); // may throw + m_size += count; // update end + } + else + { + namespace sv = varray_detail; + + difference_type to_move = boost::container::iterator_distance(position, this->end()); + + // TODO - should following lines check for exception and revert to the old size? + + if ( count < static_cast(to_move) ) + { + sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw + m_size += count; // update end + sv::move_backward(position, position + to_move - count, this->end() - count); // may throw + std::fill_n(position, count, value); // may throw + } + else + { + std::uninitialized_fill(this->end(), position + count, value); // may throw + m_size += count - to_move; // update end + sv::uninitialized_move(position, position + to_move, position + count); // may throw + m_size += to_move; // update end + std::fill_n(position, to_move, value); // may throw + } + } + + return position; + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li distance(first, last) <= capacity() + //! @li \c Iterator must meet the \c ForwardIterator. + //! + //! @brief Inserts a copy of a range [first, last) at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param first The iterator to the first element of a range used to construct new elements. + //! @param last The iterator to the one after the last element of a range used to construct new elements. + //! + //! @par Throws + //! @li If Value's constructor and assignment taking a dereferenced \c Iterator. + //! @li If Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Linear O(N). + template + iterator insert(iterator position, Iterator first, Iterator last) + { + this->insert_dispatch(position, first, last); + return position; + } + + //! @pre \c position must be a valid iterator of \c *this in range [begin(), end()) + //! + //! @brief Erases Value from position. + //! + //! @param position The position of the element which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator position) + { + namespace sv = varray_detail; + + errh::check_iterator_end_neq(*this, position); + + //TODO - add empty check? + //errh::check_empty(*this); + + sv::move(position + 1, this->end(), position); // may throw + sv::destroy(this->end() - 1); + --m_size; + + return position; + } + + //! @pre + //! @li \c first and \c last must define a valid range + //! @li iterators must be in range [begin(), end()] + //! + //! @brief Erases Values from a range [first, last). + //! + //! @param first The position of the first element of a range which will be erased from the container. + //! @param last The position of the one after the last element of a range which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator first, iterator last) + { + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, first); + errh::check_iterator_end_eq(*this, last); + + difference_type n = boost::container::iterator_distance(first, last); + + //TODO - add invalid range check? + //BOOST_ASSERT_MSG(0 <= n, "invalid range"); + //TODO - add this->size() check? + //BOOST_ASSERT_MSG(n <= this->size(), "invalid range"); + + sv::move(last, this->end(), first); // may throw + sv::destroy(this->end() - n, this->end()); + m_size -= n; + + return first; + } + + //! @pre distance(first, last) <= capacity() + //! + //! @brief Assigns a range [first, last) of Values to this container. + //! + //! @param first The iterator to the first element of a range used to construct new content of this container. + //! @param last The iterator to the one after the last element of a range used to construct new content of this container. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void assign(Iterator first, Iterator last) + { + this->assign_dispatch(first, last); // may throw + } + + //! @pre count <= capacity() + //! + //! @brief Assigns a count copies of value to this container. + //! + //! @param count The new number of elements which will be container in the container. + //! @param value The value which will be used to copy construct the new content. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + void assign(size_type count, value_type const& value) + { + if ( count < m_size ) + { + namespace sv = varray_detail; + + std::fill_n(this->begin(), count, value); // may throw + sv::destroy(this->begin() + count, this->end()); + } + else + { + errh::check_capacity(*this, count); // may throw + + std::fill_n(this->begin(), m_size, value); // may throw + std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw + } + m_size = count; // update end + } + +#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! @pre size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... in the end of the container. + //! + //! @param args The arguments of the constructor of the new element which will be created at the end of the container. + //! + //! @par Throws + //! If in-place constructor throws or Value's move constructor throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant O(1). + template + void emplace_back(BOOST_FWD_REF(Args) ...args) + { + typedef typename vt::disable_trivial_init dti; + + errh::check_capacity(*this, m_size + 1); // may throw + + namespace sv = varray_detail; + sv::construct(dti(), this->end(), ::boost::forward(args)...); // may throw + ++m_size; // update end + } + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()] + //! @li size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... before position + //! + //! @param position The position at which new elements will be inserted. + //! @param args The arguments of the constructor of the new element. + //! + //! @par Throws + //! If in-place constructor throws or if Value's move constructor or move assignment throws. + //! @internal + //! @li If a throwing error handler is specified, throws when the capacity is exceeded. (not by default). + //! @endinternal + //! + //! @par Complexity + //! Constant or linear. + template + iterator emplace(iterator position, BOOST_FWD_REF(Args) ...args) + { + typedef typename vt::disable_trivial_init dti; + + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + 1); // may throw + + if ( position == this->end() ) + { + sv::construct(dti(), position, ::boost::forward(args)...); // may throw + ++m_size; // update end + } + else + { + // TODO - should following lines check for exception and revert to the old size? + + // TODO - should move be used only if it's nonthrowing? + value_type & r = *(this->end() - 1); + sv::construct(dti(), this->end(), boost::move(r)); // may throw + ++m_size; // update end + sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw + + typename aligned_storage + ::value>::type temp_storage; + value_type * val_p = static_cast(static_cast(&temp_storage)); + sv::construct(dti(), val_p, ::boost::forward(args)...); // may throw + sv::scoped_destructor d(val_p); + sv::assign(position, ::boost::move(*val_p)); // may throw + } + + return position; + } + +#else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || BOOST_CONTAINER_DOXYGEN_INVOKED + + #define BOOST_CONTAINER_VARRAY_EMPLACE_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void emplace_back(BOOST_MOVE_UREF##N)\ + {\ + typedef typename vt::disable_trivial_init dti;\ + errh::check_capacity(*this, m_size + 1);/*may throw*/\ + \ + namespace sv = varray_detail;\ + sv::construct(dti(), this->end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ + ++m_size; /*update end*/\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace(iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + typedef typename vt::disable_trivial_init dti;\ + namespace sv = varray_detail;\ + errh::check_iterator_end_eq(*this, position);\ + errh::check_capacity(*this, m_size + 1); /*may throw*/\ + if ( position == this->end() ){\ + sv::construct(dti(), position BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ + ++m_size; /*update end*/\ + }\ + else{\ + /* TODO - should following lines check for exception and revert to the old size? */\ + /* TODO - should move be used only if it's nonthrowing? */\ + value_type & r = *(this->end() - 1);\ + sv::construct(dti(), this->end(), boost::move(r));/*may throw*/\ + ++m_size; /*update end*/\ + sv::move_backward(position, this->end() - 2, this->end() - 1);/*may throw*/\ + typename aligned_storage\ + ::value>::type temp_storage;\ + value_type * val_p = static_cast(static_cast(&temp_storage));\ + sv::construct(dti(), val_p BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); /*may throw*/\ + sv::scoped_destructor d(val_p);\ + sv::assign(position, ::boost::move(*val_p));/*may throw*/\ + }\ + return position;\ + }\ + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_VARRAY_EMPLACE_CODE) + #undef BOOST_CONTAINER_VARRAY_EMPLACE_CODE + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || BOOST_CONTAINER_DOXYGEN_INVOKED +#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE + + //! @brief Removes all elements from the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + void clear() + { + namespace sv = varray_detail; + sv::destroy(this->begin(), this->end()); + m_size = 0; // update end + } + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + reference at(size_type i) + { + errh::check_at(*this, i); // may throw + return *(this->begin() + i); + } + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference at(size_type i) const + { + errh::check_at(*this, i); // may throw + return *(this->begin() + i); + } + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference operator[](size_type i) + { + // TODO: Remove bounds check? std::vector and std::array operator[] don't check. + errh::check_operator_brackets(*this, i); + return *(this->begin() + i); + } + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference operator[](size_type i) const + { + errh::check_operator_brackets(*this, i); + return *(this->begin() + i); + } + + //! @pre \c !empty() + //! + //! @brief Returns reference to the first element. + //! + //! @return reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference front() + { + errh::check_empty(*this); + return *(this->begin()); + } + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference front() const + { + errh::check_empty(*this); + return *(this->begin()); + } + + //! @pre \c !empty() + //! + //! @brief Returns reference to the last element. + //! + //! @return reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference back() + { + errh::check_empty(*this); + return *(this->end() - 1); + } + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference back() const + { + errh::check_empty(*this); + return *(this->end() - 1); + } + + //! @brief Pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + Value * data() + { + return (addressof)(*(this->ptr())); + } + + //! @brief Const pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const Value * data() const + { + return (addressof)(*(this->ptr())); + } + + + //! @brief Returns iterator to the first element. + //! + //! @return iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator begin() { return this->ptr(); } + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator begin() const { return this->ptr(); } + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cbegin() const { return this->ptr(); } + + //! @brief Returns iterator to the one after the last element. + //! + //! @return iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator end() { return this->begin() + m_size; } + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator end() const { return this->begin() + m_size; } + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cend() const { return this->cbegin() + m_size; } + + //! @brief Returns reverse iterator to the first element of the reversed container. + //! + //! @return reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rbegin() { return reverse_iterator(this->end()); } + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } + + //! @brief Returns reverse iterator to the one after the last element of the reversed container. + //! + //! @return reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rend() { return reverse_iterator(this->begin()); } + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type capacity() { return Capacity; } + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type max_size() { return Capacity; } + + //! @brief Returns the number of stored elements. + //! + //! @return Number of elements contained in the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + size_type size() const { return m_size; } + + //! @brief Queries if the container contains elements. + //! + //! @return true if the number of elements contained in the + //! container is equal to 0. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + bool empty() const { return 0 == m_size; } + +private: + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + template + void move_ctor_dispatch(varray & other, true_type /*use_memop*/) + { + ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); + m_size = other.m_size; + } + + // @par Throws + // @li If boost::has_nothrow_move::value is true and Value's move constructor throws + // @li If boost::has_nothrow_move::value is false and Value's copy constructor throws. + // @par Complexity + // Linear O(N). + template + void move_ctor_dispatch(varray & other, false_type /*use_memop*/) + { + namespace sv = varray_detail; + sv::uninitialized_move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw + m_size = other.m_size; + } + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + template + void move_assign_dispatch(varray & other, true_type /*use_memop*/) + { + this->clear(); + + ::memcpy(this->data(), other.data(), sizeof(Value) * other.m_size); + boost::adl_move_swap(m_size, other.m_size); + } + + // @par Throws + // @li If boost::has_nothrow_move::value is true and Value's move constructor or move assignment throws + // @li If boost::has_nothrow_move::value is false and Value's copy constructor or move assignment throws. + // @par Complexity + // Linear O(N). + template + void move_assign_dispatch(varray & other, false_type /*use_memop*/) + { + namespace sv = varray_detail; + if ( m_size <= static_cast(other.size()) ) + { + sv::move_if_noexcept(other.begin(), other.begin() + m_size, this->begin()); // may throw + // TODO - perform uninitialized_copy first? + sv::uninitialized_move_if_noexcept(other.begin() + m_size, other.end(), this->end()); // may throw + } + else + { + sv::move_if_noexcept(other.begin(), other.end(), this->begin()); // may throw + sv::destroy(this->begin() + other.size(), this->end()); + } + m_size = other.size(); // update end + } + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + template + void swap_dispatch(varray & other, true_type const& /*use_optimized_swap*/) + { + typedef typename + if_c< + Capacity < C, + aligned_storage_type, + typename varray::aligned_storage_type + >::type + storage_type; + + storage_type temp_storage; + value_type * temp_ptr = static_cast(static_cast(&temp_storage)); + + ::memcpy(temp_ptr, this->data(), sizeof(Value) * this->size()); + ::memcpy(this->data(), other.data(), sizeof(Value) * other.size()); + ::memcpy(other.data(), temp_ptr, sizeof(Value) * this->size()); + + boost::adl_move_swap(m_size, other.m_size); + } + + // @par Throws + // If Value's move constructor or move assignment throws + // but only if use_memop_in_swap_and_move is false_type - default. + // @par Complexity + // Linear O(N). + template + void swap_dispatch(varray & other, false_type const& /*use_optimized_swap*/) + { + namespace sv = varray_detail; + + typedef typename + vt::use_memop_in_swap_and_move use_memop_in_swap_and_move; + + if ( this->size() < other.size() ) + swap_dispatch_impl(this->begin(), this->end(), other.begin(), other.end(), use_memop_in_swap_and_move()); // may throw + else + swap_dispatch_impl(other.begin(), other.end(), this->begin(), this->end(), use_memop_in_swap_and_move()); // may throw + boost::adl_move_swap(m_size, other.m_size); + } + + // @par Throws + // Nothing. + // @par Complexity + // Linear O(N). + void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, true_type const& /*use_memop*/) + { + //BOOST_ASSERT_MSG(boost::container::iterator_distance(first_sm, last_sm) <= boost::container::iterator_distance(first_la, last_la)); + + namespace sv = varray_detail; + for (; first_sm != last_sm ; ++first_sm, ++first_la) + { + typename aligned_storage< + sizeof(value_type), + alignment_of::value + >::type temp_storage; + value_type * temp_ptr = static_cast(static_cast(&temp_storage)); + ::memcpy(temp_ptr, (addressof)(*first_sm), sizeof(value_type)); + ::memcpy((addressof)(*first_sm), (addressof)(*first_la), sizeof(value_type)); + ::memcpy((addressof)(*first_la), temp_ptr, sizeof(value_type)); + } + + ::memcpy(first_sm, first_la, sizeof(value_type) * boost::container::iterator_distance(first_la, last_la)); + } + + // @par Throws + // If Value's move constructor or move assignment throws. + // @par Complexity + // Linear O(N). + void swap_dispatch_impl(iterator first_sm, iterator last_sm, iterator first_la, iterator last_la, false_type const& /*use_memop*/) + { + //BOOST_ASSERT_MSG(boost::container::iterator_distance(first_sm, last_sm) <= boost::container::iterator_distance(first_la, last_la)); + + namespace sv = varray_detail; + for (; first_sm != last_sm ; ++first_sm, ++first_la) + { + //boost::adl_move_swap(*first_sm, *first_la); // may throw + value_type temp(boost::move(*first_sm)); // may throw + *first_sm = boost::move(*first_la); // may throw + *first_la = boost::move(temp); // may throw + } + sv::uninitialized_move(first_la, last_la, first_sm); // may throw + sv::destroy(first_la, last_la); + } + + // insert + + // @par Throws + // If Value's move constructor or move assignment throws + // or if Value's copy assignment throws. + // @par Complexity + // Linear O(N). + template + iterator priv_insert(iterator position, V & value) + { + typedef typename vt::disable_trivial_init dti; + namespace sv = varray_detail; + + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, m_size + 1); // may throw + + if ( position == this->end() ) + { + sv::construct(dti(), position, value); // may throw + ++m_size; // update end + } + else + { + // TODO - should following lines check for exception and revert to the old size? + + // TODO - should move be used only if it's nonthrowing? + value_type & r = *(this->end() - 1); + sv::construct(dti(), this->end(), boost::move(r)); // may throw + ++m_size; // update end + sv::move_backward(position, this->end() - 2, this->end() - 1); // may throw + sv::assign(position, value); // may throw + } + + return position; + } + + // insert + + // @par Throws + // If Value's move constructor, move assignment throws + // or if Value's copy constructor or copy assignment throws. + // @par Complexity + // Linear O(N). + template + typename iterator_enable_if_tag::type + insert_dispatch(iterator position, Iterator first, Iterator last) + { + errh::check_iterator_end_eq(*this, position); + + size_type count = boost::container::iterator_distance(first, last); + + errh::check_capacity(*this, m_size + count); // may throw + + if ( position == this->end() ) + { + namespace sv = varray_detail; + + sv::uninitialized_copy(first, last, position); // may throw + m_size += count; // update end + } + else + { + this->insert_in_the_middle(position, first, last, count); // may throw + } + } + + // @par Throws + // If Value's move constructor, move assignment throws + // or if Value's copy constructor or copy assignment throws. + // @par Complexity + // Linear O(N). + template + typename iterator_disable_if_tag::type + insert_dispatch(iterator position, Iterator first, Iterator last) + { + errh::check_iterator_end_eq(*this, position); + + if ( position == this->end() ) + { + namespace sv = varray_detail; + + std::ptrdiff_t d = boost::container::iterator_distance(position, this->begin() + Capacity); + std::size_t count = sv::uninitialized_copy_s(first, last, position, d); // may throw + + errh::check_capacity(*this, count <= static_cast(d) ? m_size + count : Capacity + 1); // may throw + + m_size += count; + } + else + { + size_type count = boost::container::iterator_distance(first, last); + + errh::check_capacity(*this, m_size + count); // may throw + + this->insert_in_the_middle(position, first, last, count); // may throw + } + } + + // @par Throws + // If Value's move constructor, move assignment throws + // or if Value's copy constructor or copy assignment throws. + // @par Complexity + // Linear O(N). + template + void insert_in_the_middle(iterator position, Iterator first, Iterator last, difference_type count) + { + namespace sv = varray_detail; + + difference_type to_move = boost::container::iterator_distance(position, this->end()); + + // TODO - should following lines check for exception and revert to the old size? + + if ( count < to_move ) + { + sv::uninitialized_move(this->end() - count, this->end(), this->end()); // may throw + m_size += count; // update end + sv::move_backward(position, position + to_move - count, this->end() - count); // may throw + sv::copy(first, last, position); // may throw + } + else + { + Iterator middle_iter = first; + boost::container::iterator_advance(middle_iter, to_move); + + sv::uninitialized_copy(middle_iter, last, this->end()); // may throw + m_size += count - to_move; // update end + sv::uninitialized_move(position, position + to_move, position + count); // may throw + m_size += to_move; // update end + sv::copy(first, middle_iter, position); // may throw + } + } + + // assign + + // @par Throws + // If Value's constructor or assignment taking dereferenced Iterator throws. + // @par Complexity + // Linear O(N). + template + typename iterator_enable_if_tag::type + assign_dispatch(Iterator first, Iterator last) + { + namespace sv = varray_detail; + + size_type s = boost::container::iterator_distance(first, last); + + errh::check_capacity(*this, s); // may throw + + if ( m_size <= static_cast(s) ) + { + sv::copy(first, first + m_size, this->begin()); // may throw + // TODO - perform uninitialized_copy first? + sv::uninitialized_copy(first + m_size, last, this->end()); // may throw + } + else + { + sv::copy(first, last, this->begin()); // may throw + sv::destroy(this->begin() + s, this->end()); + } + m_size = s; // update end + } + + // @par Throws + // If Value's constructor or assignment taking dereferenced Iterator throws. + // @par Complexity + // Linear O(N). + template + typename iterator_disable_if_tag::type + assign_dispatch(Iterator first, Iterator last) + { + namespace sv = varray_detail; + + size_type s = 0; + iterator it = this->begin(); + + for ( ; it != this->end() && first != last ; ++it, ++first, ++s ) + *it = *first; // may throw + + sv::destroy(it, this->end()); + + std::ptrdiff_t d = boost::container::iterator_distance(it, this->begin() + Capacity); + std::size_t count = sv::uninitialized_copy_s(first, last, it, d); // may throw + s += count; + + errh::check_capacity(*this, count <= static_cast(d) ? s : Capacity + 1); // may throw + + m_size = s; // update end + } + + pointer ptr() + { + return pointer(static_cast(static_cast(&m_storage))); + } + + const_pointer ptr() const + { + return pointer(static_cast(static_cast(&m_storage))); + } + + size_type m_size; + aligned_storage_type m_storage; +}; + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +class varray +{ + typedef varray_traits< + Value, 0, Strategy + > vt; + + typedef typename vt::size_type stored_size_type; + typedef typename vt::error_handler errh; + +public: + typedef typename vt::value_type value_type; + typedef stored_size_type size_type; + typedef typename vt::difference_type difference_type; + typedef typename vt::pointer pointer; + typedef typename vt::const_pointer const_pointer; + typedef typename vt::reference reference; + typedef typename vt::const_reference const_reference; + + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef boost::container::reverse_iterator reverse_iterator; + typedef boost::container::reverse_iterator const_reverse_iterator; + + // nothrow + varray() {} + + // strong + explicit varray(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + varray(size_type count, value_type const&) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + varray(varray const& other) + { + errh::check_capacity(*this, other.size()); + } + + // strong + template + varray(varray const& other) + { + errh::check_capacity(*this, other.size()); // may throw + } + + // strong + template + varray(Iterator first, Iterator last) + { + errh::check_capacity(*this, boost::container::iterator_distance(first, last)); // may throw + } + + // basic + varray & operator=(varray const& other) + { + errh::check_capacity(*this, other.size()); + return *this; + } + + // basic + template + varray & operator=(varray const& other) + { + errh::check_capacity(*this, other.size()); // may throw + return *this; + } + + // nothrow + ~varray() {} + + // strong + void resize(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + void resize(size_type count, value_type const&) + { + errh::check_capacity(*this, count); // may throw + } + + + // nothrow + void reserve(size_type count) + { + errh::check_capacity(*this, count); // may throw + } + + // strong + void push_back(value_type const&) + { + errh::check_capacity(*this, 1); // may throw + } + + // nothrow + void pop_back() + { + errh::check_empty(*this); + } + + // basic + void insert(iterator position, value_type const&) + { + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, 1); // may throw + } + + // basic + void insert(iterator position, size_type count, value_type const&) + { + errh::check_iterator_end_eq(*this, position); + errh::check_capacity(*this, count); // may throw + } + + // basic + template + void insert(iterator, Iterator first, Iterator last) + { + errh::check_capacity(*this, boost::container::iterator_distance(first, last)); // may throw + } + + // basic + void erase(iterator position) + { + errh::check_iterator_end_neq(*this, position); + } + + // basic + void erase(iterator first, iterator last) + { + errh::check_iterator_end_eq(*this, first); + errh::check_iterator_end_eq(*this, last); + + //BOOST_ASSERT_MSG(0 <= n, "invalid range"); + } + + // basic + template + void assign(Iterator first, Iterator last) + { + errh::check_capacity(*this, boost::container::iterator_distance(first, last)); // may throw + } + + // basic + void assign(size_type count, value_type const&) + { + errh::check_capacity(*this, count); // may throw + } + + // nothrow + void clear() {} + + // strong + reference at(size_type i) + { + errh::check_at(*this, i); // may throw + return *(this->begin() + i); + } + + // strong + const_reference at(size_type i) const + { + errh::check_at(*this, i); // may throw + return *(this->begin() + i); + } + + // nothrow + reference operator[](size_type i) + { + errh::check_operator_brackets(*this, i); + return *(this->begin() + i); + } + + // nothrow + const_reference operator[](size_type i) const + { + errh::check_operator_brackets(*this, i); + return *(this->begin() + i); + } + + // nothrow + reference front() + { + errh::check_empty(*this); + return *(this->begin()); + } + + // nothrow + const_reference front() const + { + errh::check_empty(*this); + return *(this->begin()); + } + + // nothrow + reference back() + { + errh::check_empty(*this); + return *(this->end() - 1); + } + + // nothrow + const_reference back() const + { + errh::check_empty(*this); + return *(this->end() - 1); + } + + // nothrow + Value * data() { return (addressof)(*(this->ptr())); } + const Value * data() const { return (addressof)(*(this->ptr())); } + + // nothrow + iterator begin() { return this->ptr(); } + const_iterator begin() const { return this->ptr(); } + const_iterator cbegin() const { return this->ptr(); } + iterator end() { return this->begin(); } + const_iterator end() const { return this->begin(); } + const_iterator cend() const { return this->cbegin(); } + // nothrow + reverse_iterator rbegin() { return reverse_iterator(this->end()); } + const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } + const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } + reverse_iterator rend() { return reverse_iterator(this->begin()); } + const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } + const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } + + // nothrow + size_type capacity() const { return 0; } + size_type max_size() const { return 0; } + size_type size() const { return 0; } + bool empty() const { return true; } + +private: + + pointer ptr() + { + return pointer(reinterpret_cast(this)); + } + + const_pointer ptr() const + { + return const_pointer(reinterpret_cast(this)); + } +}; + +#endif // !BOOST_CONTAINER_DOXYGEN_INVOKED + +//! @brief Checks if contents of two varrays are equal. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if containers have the same size and elements in both containers are equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator== (varray const& x, varray const& y) +{ + return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); +} + +//! @brief Checks if contents of two varrays are not equal. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if containers have different size or elements in both containers are not equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator!= (varray const& x, varray const& y) +{ + return !(x==y); +} + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if x compares lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator< (varray const& x, varray const& y) +{ + return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if y compares lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator> (varray const& x, varray const& y) +{ + return y +bool operator<= (varray const& x, varray const& y) +{ + return !(y +bool operator>= (varray const& x, varray const& y) +{ + return !(x +inline void swap(varray & x, varray & y) +{ + x.swap(y); +} + +}}} // namespace boost::container::dtl + +#include + +#endif // BOOST_CONTAINER_DETAIL_VARRAY_HPP diff --git a/src/boost/libs/container/bench/detail/varray_concept.hpp b/src/boost/libs/container/bench/detail/varray_concept.hpp new file mode 100644 index 00000000..94d19bd7 --- /dev/null +++ b/src/boost/libs/container/bench/detail/varray_concept.hpp @@ -0,0 +1,60 @@ +// Boost.Container varray +// +// Copyright (c) 2012-2013 Andrew Hundt. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_VARRAY_CONCEPT_HPP +#define BOOST_CONTAINER_VARRAY_CONCEPT_HPP + +#include + +namespace boost { namespace container { namespace dtl { namespace concept { + +/** + * VArrayStrategyConcept + * + * \brief Checks strategy for varray, which has similarities to std::allocator + * \ingroup varray + */ +template +struct VArrayStrategy { +#ifndef DOXYGEN_NO_CONCEPT_MEMBERS + + // typedefs are the same as in std::allocator + typedef typename Strategy::value_type value_type; + typedef typename Strategy::size_type size_type; + typedef typename Strategy::difference_type difference_type; + typedef typename Strategy::pointer pointer; + typedef typename Strategy::const_pointer const_pointer; + typedef typename Strategy::reference reference; + typedef typename Strategy::const_reference const_reference; + + struct check_methods + { + static void apply() + { + Strategy const* str = 0; + + // must implement allocate_failed + str->allocate_failed(); + + boost::ignore_unused_variable_warning(str); + } + }; + +public : + BOOST_CONCEPT_USAGE(VArrayStrategy) + { + check_methods::apply(); + } + +#endif +}; + +}}}} // namespace boost::container::dtl::concept + +#endif //BOOST_CONTAINER_VARRAY_CONCEPT_HPP diff --git a/src/boost/libs/container/bench/detail/varray_util.hpp b/src/boost/libs/container/bench/detail/varray_util.hpp new file mode 100644 index 00000000..cf8c3379 --- /dev/null +++ b/src/boost/libs/container/bench/detail/varray_util.hpp @@ -0,0 +1,646 @@ +// Boost.Container +// +// varray details +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_DETAIL_VARRAY_UTIL_HPP +#define BOOST_CONTAINER_DETAIL_VARRAY_UTIL_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include +#include +#include + +#include +#include +#include + +// TODO - move vectors iterators optimization to the other, optional file instead of checking defines? + +#if defined(BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS) +#include +#include +#endif // BOOST_CONTAINER_VARRAY_ENABLE_ITERATORS_OPTIMIZATION && !BOOST_NO_EXCEPTIONS + +namespace boost { namespace container { namespace varray_detail { + +namespace bcd = ::boost::container::dtl; + +template +struct are_elements_contiguous : boost::container::dtl::is_pointer +{}; + +#if defined(BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS) + +template +struct are_elements_contiguous< + bcd::vector_const_iterator +> : bcd::true_type +{}; + +template +struct are_elements_contiguous< + bcd::vector_iterator +> : bcd::true_type +{}; + +#if defined(BOOST_DINKUMWARE_STDLIB) + +template +struct are_elements_contiguous< + std::_Vector_const_iterator +> : bcd::true_type +{}; + +template +struct are_elements_contiguous< + std::_Vector_iterator +> : bcd::true_type +{}; + +#elif defined(BOOST_GNU_STDLIB) + +template +struct are_elements_contiguous< + __gnu_cxx::__normal_iterator > +> : bcd::true_type +{}; + +#elif defined(_LIBCPP_VERSION) + +// TODO - test it first +//template +//struct are_elements_contiguous< +// __wrap_iter

+//> : bcd::true_type +//{}; + +#else // OTHER_STDLIB + +// TODO - add other iterators implementations + +#endif // STDLIB + +#endif // BOOST_CONTAINER_VARRAY_ENABLE_VECTORS_OPTIMIZATION && !BOOST_NO_EXCEPTIONS + +template +struct are_corresponding : + bcd::bool_< + bcd::is_same< + bcd::remove_const< + typename ::boost::container::iterator_traits::value_type + >, + bcd::remove_const< + typename ::boost::container::iterator_traits::value_type + > + >::value && + are_elements_contiguous::value && + are_elements_contiguous::value + > +{}; + +template +struct is_corresponding_value : + bcd::bool_< + bcd::is_same< + bcd::remove_const::value_type>, + bcd::remove_const + >::value + > +{}; + +// destroy(I, I) + +template +void destroy_dispatch(I /*first*/, I /*last*/, bcd::true_type const& /*is_trivially_destructible*/) +{} + +template +void destroy_dispatch(I first, I last, bcd::false_type const& /*is_trivially_destructible*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + for ( ; first != last ; ++first ) + first->~value_type(); +} + +template +void destroy(I first, I last) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + destroy_dispatch(first, last, bcd::bool_::value>()); +} + +// destroy(I) + +template +void destroy_dispatch(I /*pos*/, + bcd::true_type const& /*is_trivially_destructible*/) +{} + +template +void destroy_dispatch(I pos, + bcd::false_type const& /*is_trivially_destructible*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + pos->~value_type(); +} + +template +void destroy(I pos) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + destroy_dispatch(pos, bcd::bool_::value>()); +} + +// copy(I, I, O) + +template +inline O copy_dispatch(I first, I last, O dst, bcd::true_type const& /*use_memmove*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + const std::size_t d = boost::container::iterator_distance(first, last); + ::memmove(boost::container::dtl::addressof(*dst), boost::container::dtl::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline O copy_dispatch(I first, I last, O dst, bcd::false_type const& /*use_memmove*/) +{ + return std::copy(first, last, dst); // may throw +} + +template +inline O copy(I first, I last, O dst) +{ + typedef bcd::bool_ + < are_corresponding::value && + bcd::is_trivially_copy_assignable::value_type>::value + > use_memmove; + + return copy_dispatch(first, last, dst, use_memmove()); // may throw +} + +// uninitialized_copy(I, I, O) + +template +inline +O uninitialized_copy_dispatch(I first, I last, O dst, + bcd::true_type const& /*use_memcpy*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + const std::size_t d = boost::container::iterator_distance(first, last); + ::memcpy(boost::container::dtl::addressof(*dst), boost::container::dtl::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline +F uninitialized_copy_dispatch(I first, I last, F dst, + bcd::false_type const& /*use_memcpy*/) +{ + return std::uninitialized_copy(first, last, dst); // may throw +} + +template +inline +F uninitialized_copy(I first, I last, F dst) +{ + typedef bcd::bool_ + < are_corresponding::value && + bcd::is_trivially_copy_constructible::value_type>::value + > use_memcpy; + return uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw +} + +// uninitialized_move(I, I, O) + +template +inline +O uninitialized_move_dispatch(I first, I last, O dst, + bcd::true_type const& /*use_memcpy*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + const std::size_t d = boost::container::iterator_distance(first, last); + ::memcpy(boost::container::dtl::addressof(*dst), boost::container::dtl::addressof(*first), sizeof(value_type) * d); + return dst + d; +} + +template +inline +O uninitialized_move_dispatch(I first, I last, O dst, + bcd::false_type const& /*use_memcpy*/) +{ + //return boost::uninitialized_move(first, last, dst); // may throw + + O o = dst; + + BOOST_TRY + { + typedef typename boost::container::iterator_traits::value_type value_type; + for (; first != last; ++first, ++o ) + new (boost::container::dtl::addressof(*o)) value_type(boost::move(*first)); + } + BOOST_CATCH(...) + { + destroy(dst, o); + BOOST_RETHROW; + } + BOOST_CATCH_END + + return dst; +} + +template +inline +O uninitialized_move(I first, I last, O dst) +{ + typedef bcd::bool_ + < are_corresponding::value && + bcd::is_trivially_copy_constructible::value_type>::value + > use_memcpy; + return uninitialized_move_dispatch(first, last, dst, use_memcpy()); // may throw +} + +// TODO - move uses memmove - implement 2nd version using memcpy? + +// move(I, I, O) + +template +inline +O move_dispatch(I first, I last, O dst, + bcd::true_type const& /*use_memmove*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + const std::size_t d = boost::container::iterator_distance(first, last); + ::memmove(boost::container::dtl::addressof(*dst), boost::container::dtl::addressof(*first), sizeof(value_type)*d ); + return dst + d; +} + +template +inline +O move_dispatch(I first, I last, O dst, + bcd::false_type const& /*use_memmove*/) +{ + return boost::move(first, last, dst); // may throw +} + +template +inline +O move(I first, I last, O dst) +{ + typedef bcd::bool_ + < are_corresponding::value && + bcd::is_trivially_copy_constructible::value_type>::value + > use_memmove; + return move_dispatch(first, last, dst, use_memmove()); // may throw +} + +// move_backward(BDI, BDI, BDO) + +template +inline +BDO move_backward_dispatch(BDI first, BDI last, BDO dst, + bcd::true_type const& /*use_memmove*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + const std::size_t d = boost::container::iterator_distance(first, last); + BDO foo(dst - d); + ::memmove(boost::container::dtl::addressof(*foo), boost::container::dtl::addressof(*first), sizeof(value_type) * d); + return foo; +} + +template +inline +BDO move_backward_dispatch(BDI first, BDI last, BDO dst, + bcd::false_type const& /*use_memmove*/) +{ + return boost::move_backward(first, last, dst); // may throw +} + +template +inline +BDO move_backward(BDI first, BDI last, BDO dst) +{ + typedef bcd::bool_ + < are_corresponding::value && + bcd::is_trivially_copy_constructible::value_type>::value + > use_memmove; + return move_backward_dispatch(first, last, dst, use_memmove()); // may throw +} + +template +struct has_nothrow_move : public + bcd::bool_< + ::boost::has_nothrow_move< + typename bcd::remove_const::type + >::value + || + ::boost::has_nothrow_move::value + > +{}; + +// uninitialized_move_if_noexcept(I, I, O) + +template +inline +O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, bcd::true_type const& /*use_move*/) +{ return uninitialized_move(first, last, dst); } + +template +inline +O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, bcd::false_type const& /*use_move*/) +{ return uninitialized_copy(first, last, dst); } + +template +inline +O uninitialized_move_if_noexcept(I first, I last, O dst) +{ + typedef has_nothrow_move< + typename ::boost::container::iterator_traits::value_type + > use_move; + + return uninitialized_move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw +} + +// move_if_noexcept(I, I, O) + +template +inline +O move_if_noexcept_dispatch(I first, I last, O dst, bcd::true_type const& /*use_move*/) +{ return move(first, last, dst); } + +template +inline +O move_if_noexcept_dispatch(I first, I last, O dst, bcd::false_type const& /*use_move*/) +{ return copy(first, last, dst); } + +template +inline +O move_if_noexcept(I first, I last, O dst) +{ + typedef has_nothrow_move< + typename ::boost::container::iterator_traits::value_type + > use_move; + + return move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw +} + +// uninitialized_fill(I, I) + +template +inline +void uninitialized_fill_dispatch(I , I , + bcd::true_type const& /*is_trivially_default_constructible*/, + bcd::true_type const& /*disable_trivial_init*/) +{} + +template +inline +void uninitialized_fill_dispatch(I first, I last, + bcd::true_type const& /*is_trivially_default_constructible*/, + bcd::false_type const& /*disable_trivial_init*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + for ( ; first != last ; ++first ) + new (boost::container::dtl::addressof(*first)) value_type(); +} + +template +inline +void uninitialized_fill_dispatch(I first, I last, + bcd::false_type const& /*is_trivially_default_constructible*/, + DisableTrivialInit const& /*not_used*/) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + I it = first; + + BOOST_TRY + { + for ( ; it != last ; ++it ) + new (boost::container::dtl::addressof(*it)) value_type(); // may throw + } + BOOST_CATCH(...) + { + destroy(first, it); + BOOST_RETHROW; + } + BOOST_CATCH_END +} + +template +inline +void uninitialized_fill(I first, I last, DisableTrivialInit const& disable_trivial_init) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + uninitialized_fill_dispatch(first, last + , bcd::bool_::value>() + , disable_trivial_init); // may throw +} + +// construct(I) + +template +inline +void construct_dispatch(bcd::true_type const& /*dont_init*/, I /*pos*/) +{} + +template +inline +void construct_dispatch(bcd::false_type const& /*dont_init*/, I pos) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + new (static_cast(::boost::container::dtl::addressof(*pos))) value_type(); // may throw +} + +template +inline +void construct(DisableTrivialInit const&, I pos) +{ + typedef typename ::boost::container::iterator_traits::value_type value_type; + bcd::bool_< + bcd::is_trivially_default_constructible::value && + DisableTrivialInit::value + > dont_init; + construct_dispatch(dont_init(), pos); // may throw +} + +// construct(I, V) + +template +inline +void construct_dispatch(I pos, V const& v, bcd::true_type const& /*use_memcpy*/) +{ + ::memcpy(boost::container::dtl::addressof(*pos), boost::container::dtl::addressof(v), sizeof(V)); +} + +template +inline +void construct_dispatch(I pos, P const& p, + bcd::false_type const& /*use_memcpy*/) +{ + typedef typename ::boost::container::iterator_traits::value_type V; + new (static_cast(boost::container::dtl::addressof(*pos))) V(p); // may throw +} + +template +inline +void construct(DisableTrivialInit const&, I pos, P const& p) +{ + typedef bcd::bool_ + < is_corresponding_value::value && + bcd::is_trivially_copy_constructible

::value + > use_memcpy; + construct_dispatch(pos, p, use_memcpy()); // may throw +} + +// Needed by push_back(V &&) + +template +inline +void construct(DisableTrivialInit const&, I pos, BOOST_RV_REF(P) p) +{ + typedef typename ::boost::container::iterator_traits::value_type V; + new (static_cast(boost::container::dtl::addressof(*pos))) V(::boost::move(p)); // may throw +} + +// Needed by emplace_back() and emplace() + +#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template +inline +void construct(DisableTrivialInit const&, + I pos, + BOOST_FWD_REF(Args) ...args) +{ + typedef typename ::boost::container::iterator_traits::value_type V; + new (static_cast(boost::container::dtl::addressof(*pos))) V(::boost::forward(args)...); // may throw +} + +#else // !BOOST_NO_CXX11_VARIADIC_TEMPLATES + +// BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 const& p0 +// !BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 && p0 +// which means that version with one parameter may take V const& v + +#define BOOST_CONTAINER_VARRAY_UTIL_CONSTRUCT_CODE(N) \ +template \ +inline void construct(DisableTrivialInit const&, I pos, BOOST_FWD_REF(P) p BOOST_MOVE_I##N BOOST_MOVE_UREF##N )\ +{\ + typedef typename ::boost::container::iterator_traits::value_type V;\ + new (static_cast(boost::container::dtl::addressof(*pos)))\ + V(::boost::forward

(p) BOOST_MOVE_I##N BOOST_MOVE_FWD##N); /*may throw*/\ +} +BOOST_MOVE_ITERATE_1TO9(BOOST_CONTAINER_VARRAY_UTIL_CONSTRUCT_CODE) +#undef BOOST_CONTAINER_VARRAY_UTIL_CONSTRUCT_CODE + +#endif // !BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE + +// assign(I, V) + +template +inline +void assign_dispatch(I pos, V const& v, + bcd::true_type const& /*use_memcpy*/) +{ + ::memcpy(boost::container::dtl::addressof(*pos), boost::container::dtl::addressof(v), sizeof(V)); +} + +template +inline +void assign_dispatch(I pos, V const& v, + bcd::false_type const& /*use_memcpy*/) +{ + *pos = v; // may throw +} + +template +inline +void assign(I pos, V const& v) +{ + typedef bcd::bool_ + < is_corresponding_value::value && + bcd::is_trivially_copy_assignable::value + > use_memcpy; + assign_dispatch(pos, v, use_memcpy()); // may throw +} + +template +inline +void assign(I pos, BOOST_RV_REF(V) v) +{ + *pos = boost::move(v); // may throw +} + + +// uninitialized_copy_s + +template +inline std::size_t uninitialized_copy_s(I first, I last, F dest, std::size_t max_count) +{ + std::size_t count = 0; + F it = dest; + + BOOST_TRY + { + for ( ; first != last ; ++it, ++first, ++count ) + { + if ( max_count <= count ) + return (std::numeric_limits::max)(); + + // dummy 0 as DisableTrivialInit + construct(0, it, *first); // may throw + } + } + BOOST_CATCH(...) + { + destroy(dest, it); + BOOST_RETHROW; + } + BOOST_CATCH_END + + return count; +} + +// scoped_destructor + +template +class scoped_destructor +{ +public: + scoped_destructor(T * ptr) : m_ptr(ptr) {} + + ~scoped_destructor() + { + if(m_ptr) + destroy(m_ptr); + } + + void release() { m_ptr = 0; } + +private: + T * m_ptr; +}; + +}}} // namespace boost::container::varray_detail + +#endif // BOOST_CONTAINER_DETAIL_VARRAY_UTIL_HPP diff --git a/src/boost/libs/container/bench/varray.hpp b/src/boost/libs/container/bench/varray.hpp new file mode 100644 index 00000000..98b71007 --- /dev/null +++ b/src/boost/libs/container/bench/varray.hpp @@ -0,0 +1,1000 @@ +// Boost.Container varray +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// Copyright (c) 2014-2014 Ion Gaztanaga +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_VARRAY_HPP +#define BOOST_CONTAINER_VARRAY_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "detail/varray.hpp" +#include + +namespace boost { namespace container { + +/** + * @defgroup varray_non_member varray non-member functions + */ + +/** + * @brief A variable-size array container with fixed capacity. + * + * varray is a sequence container like boost::container::vector with contiguous storage that can + * change in size, along with the static allocation, low overhead, and fixed capacity of boost::array. + * + * A varray is a sequence that supports random access to elements, constant time insertion and + * removal of elements at the end, and linear time insertion and removal of elements at the beginning or + * in the middle. The number of elements in a varray may vary dynamically up to a fixed capacity + * because elements are stored within the object itself similarly to an array. However, objects are + * initialized as they are inserted into varray unlike C arrays or std::array which must construct + * all elements on instantiation. The behavior of varray enables the use of statically allocated + * elements in cases with complex object lifetime requirements that would otherwise not be trivially + * possible. + * + * @par Error Handling + * Insertion beyond the capacity and out of bounds errors result in undefined behavior. + * The reason for this is because unlike vectors, varray does not perform allocation. + * + * @tparam Value The type of element that will be stored. + * @tparam Capacity The maximum number of elements varray can store, fixed at compile time. + */ +template +class varray + : public dtl::varray +{ + typedef dtl::varray base_t; + + BOOST_COPYABLE_AND_MOVABLE(varray) + +public: + //! @brief The type of elements stored in the container. + typedef typename base_t::value_type value_type; + //! @brief The unsigned integral type used by the container. + typedef typename base_t::size_type size_type; + //! @brief The pointers difference type. + typedef typename base_t::difference_type difference_type; + //! @brief The pointer type. + typedef typename base_t::pointer pointer; + //! @brief The const pointer type. + typedef typename base_t::const_pointer const_pointer; + //! @brief The value reference type. + typedef typename base_t::reference reference; + //! @brief The value const reference type. + typedef typename base_t::const_reference const_reference; + //! @brief The iterator type. + typedef typename base_t::iterator iterator; + //! @brief The const iterator type. + typedef typename base_t::const_iterator const_iterator; + //! @brief The reverse iterator type. + typedef typename base_t::reverse_iterator reverse_iterator; + //! @brief The const reverse iterator. + typedef typename base_t::const_reverse_iterator const_reverse_iterator; + + //! @brief Constructs an empty varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + varray() + : base_t() + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a varray containing count value initialized Values. + //! + //! @param count The number of values which will be contained in the container. + //! + //! @par Throws + //! If Value's value initialization throws. + //! + //! @par Complexity + //! Linear O(N). + explicit varray(size_type count) + : base_t(count) + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a varray containing count copies of value. + //! + //! @param count The number of copies of a values that will be contained in the container. + //! @param value The value which will be used to copy construct values. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + varray(size_type count, value_type const& value) + : base_t(count, value) + {} + + //! @pre + //! @li distance(first, last) <= capacity() + //! @li Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Constructs a varray containing copy of a range [first, last). + //! + //! @param first The iterator to the first element in range. + //! @param last The iterator to the one after the last element in range. + //! + //! @par Throws + //! If Value's constructor taking a dereferenced Iterator throws. + //! + //! @par Complexity + //! Linear O(N). + template + varray(Iterator first, Iterator last) + : base_t(first, last) + {} + + //! @brief Constructs a copy of other varray. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + varray(varray const& other) + : base_t(other) + {} + + //! @pre other.size() <= capacity(). + //! + //! @brief Constructs a copy of other varray. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + template + varray(varray const& other) : base_t(other) {} + + //! @brief Copy assigns Values stored in the other varray to this one. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_COPY_ASSIGN_REF(varray) other) + { + base_t::operator=(static_cast(other)); + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Copy assigns Values stored in the other varray to this one. + //! + //! @param other The varray which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template +// TEMPORARY WORKAROUND +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + varray & operator=(::boost::rv< varray > const& other) +#else + varray & operator=(varray const& other) +#endif + { + base_t::operator=(static_cast const&>(other)); + return *this; + } + + //! @brief Move constructor. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + varray(BOOST_RV_REF(varray) other) + : base_t(boost::move(static_cast(other))) + {} + + //! @pre other.size() <= capacity() + //! + //! @brief Move constructor. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + template + varray(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other) + : base_t(boost::move(static_cast&>(other))) + {} + + //! @brief Move assignment. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + varray & operator=(BOOST_RV_REF(varray) other) + { + base_t::operator=(boost::move(static_cast(other))); + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Move assignment. Moves Values stored in the other varray to this one. + //! + //! @param other The varray which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template + varray & operator=(BOOST_RV_REF_2_TEMPL_ARGS(varray, value_type, C) other) + { + base_t::operator=(boost::move(static_cast&>(other))); + return *this; + } + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! @brief Destructor. Destroys Values stored in this container. + //! + //! @par Throws + //! Nothing + //! + //! @par Complexity + //! Linear O(N). + ~varray(); + + //! @brief Swaps contents of the other varray and this one. + //! + //! @param other The varray which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + void swap(varray & other); + + //! @pre other.size() <= capacity() && size() <= other.capacity() + //! + //! @brief Swaps contents of the other varray and this one. + //! + //! @param other The varray which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void swap(varray & other); + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are value initialized. + //! + //! @param count The number of elements which will be stored in the container. + //! + //! @par Throws + //! If Value's value initialization throws. + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count); + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are copy constructed from value. + //! + //! @param count The number of elements which will be stored in the container. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count, value_type const& value); + + //! @pre count <= capacity() + //! + //! @brief This call has no effect because the Capacity of this container is constant. + //! + //! @param count The number of elements which the container should be able to contain. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Linear O(N). + void reserve(size_type count); + + //! @pre size() < capacity() + //! + //! @brief Adds a copy of value at the end. + //! + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Constant O(1). + void push_back(value_type const& value); + + //! @pre size() < capacity() + //! + //! @brief Moves value to the end. + //! + //! @param value The value to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor throws. + //! + //! @par Complexity + //! Constant O(1). + void push_back(BOOST_RV_REF(value_type) value); + + //! @pre !empty() + //! + //! @brief Destroys last value and decreases the size. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + void pop_back(); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a copy of element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, value_type const& value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a move-constructed element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, BOOST_RV_REF(value_type) value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() + count <= capacity() + //! + //! @brief Inserts a count copies of value at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param count The number of new elements which will be inserted. + //! @param value The value used to copy construct new elements. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws. + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator insert(iterator position, size_type count, value_type const& value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li distance(first, last) <= capacity() + //! @li \c Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Inserts a copy of a range [first, last) at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param first The iterator to the first element of a range used to construct new elements. + //! @param last The iterator to the one after the last element of a range used to construct new elements. + //! + //! @par Throws + //! @li If Value's constructor and assignment taking a dereferenced \c Iterator. + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template + iterator insert(iterator position, Iterator first, Iterator last); + + //! @pre \c position must be a valid iterator of \c *this in range [begin(), end()) + //! + //! @brief Erases Value from position. + //! + //! @param position The position of the element which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator position); + + //! @pre + //! @li \c first and \c last must define a valid range + //! @li iterators must be in range [begin(), end()] + //! + //! @brief Erases Values from a range [first, last). + //! + //! @param first The position of the first element of a range which will be erased from the container. + //! @param last The position of the one after the last element of a range which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator first, iterator last); + + //! @pre distance(first, last) <= capacity() + //! + //! @brief Assigns a range [first, last) of Values to this container. + //! + //! @param first The iterator to the first element of a range used to construct new content of this container. + //! @param last The iterator to the one after the last element of a range used to construct new content of this container. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void assign(Iterator first, Iterator last); + + //! @pre count <= capacity() + //! + //! @brief Assigns a count copies of value to this container. + //! + //! @param count The new number of elements which will be container in the container. + //! @param value The value which will be used to copy construct the new content. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + void assign(size_type count, value_type const& value); + + //! @pre size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... in the end of the container. + //! + //! @param args The arguments of the constructor of the new element which will be created at the end of the container. + //! + //! @par Throws + //! If in-place constructor throws or Value's move constructor throws. + //! + //! @par Complexity + //! Constant O(1). + template + void emplace_back(Args &&...args); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()] + //! @li size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... before position + //! + //! @param position The position at which new elements will be inserted. + //! @param args The arguments of the constructor of the new element. + //! + //! @par Throws + //! If in-place constructor throws or if Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + template + iterator emplace(iterator position, Args &&...args); + + //! @brief Removes all elements from the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + void clear(); + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + reference at(size_type i); + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference at(size_type i) const; + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference operator[](size_type i); + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference operator[](size_type i) const; + + //! @pre \c !empty() + //! + //! @brief Returns reference to the first element. + //! + //! @return reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference front(); + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference front() const; + + //! @pre \c !empty() + //! + //! @brief Returns reference to the last element. + //! + //! @return reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference back(); + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference back() const; + + //! @brief Pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + Value * data(); + + //! @brief Const pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const Value * data() const; + + //! @brief Returns iterator to the first element. + //! + //! @return iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator begin(); + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator begin() const; + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cbegin() const; + + //! @brief Returns iterator to the one after the last element. + //! + //! @return iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator end(); + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator end() const; + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cend() const; + + //! @brief Returns reverse iterator to the first element of the reversed container. + //! + //! @return reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rbegin(); + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rbegin() const; + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crbegin() const; + + //! @brief Returns reverse iterator to the one after the last element of the reversed container. + //! + //! @return reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rend(); + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rend() const; + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed varray. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crend() const; + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type capacity(); + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type max_size(); + + //! @brief Returns the number of stored elements. + //! + //! @return Number of elements contained in the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + size_type size() const; + + //! @brief Queries if the container contains elements. + //! + //! @return true if the number of elements contained in the + //! container is equal to 0. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + bool empty() const; + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}; + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! @brief Checks if contents of two varrays are equal. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if containers have the same size and elements in both containers are equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator== (varray const& x, varray const& y); + +//! @brief Checks if contents of two varrays are not equal. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if containers have different size or elements in both containers are not equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator!= (varray const& x, varray const& y); + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if x compares lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator< (varray const& x, varray const& y); + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if y compares lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator> (varray const& x, varray const& y); + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if y don't compare lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator<= (varray const& x, varray const& y); + +//! @brief Lexicographically compares varrays. +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @return \c true if x don't compare lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator>= (varray const& x, varray const& y); + +//! @brief Swaps contents of two varrays. +//! +//! This function calls varray::swap(). +//! +//! @ingroup varray_non_member +//! +//! @param x The first varray. +//! @param y The second varray. +//! +//! @par Complexity +//! Linear O(N). +template +inline void swap(varray & x, varray & y); + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}} // namespace boost::container + +#include + +#endif // BOOST_CONTAINER_VARRAY_HPP diff --git a/src/boost/libs/container/build/Jamfile.v2 b/src/boost/libs/container/build/Jamfile.v2 new file mode 100644 index 00000000..3adb451c --- /dev/null +++ b/src/boost/libs/container/build/Jamfile.v2 @@ -0,0 +1,22 @@ +# (C) Copyright Vladimir Prus, David Abrahams, Michael Stevens, Hartmut Kaiser, +# Ion Gaztanaga 2007-2008 +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import sequence ; + +project boost/container + : source-location ../src + : usage-requirements # pass these requirement to dependents (i.e. users) + shared:BOOST_CONTAINER_DYN_LINK=1 + static:BOOST_CONTAINER_STATIC_LINK=1 + ; + +lib boost_container + : alloc_lib.c [ sequence.insertion-sort [ glob *.cpp ] ] + : shared:BOOST_CONTAINER_DYN_LINK=1 + static:BOOST_CONTAINER_STATIC_LINK=1 + ; + +boost-install boost_container ; \ No newline at end of file diff --git a/src/boost/libs/container/example/Jamfile.v2 b/src/boost/libs/container/example/Jamfile.v2 new file mode 100644 index 00000000..0ba75ac4 --- /dev/null +++ b/src/boost/libs/container/example/Jamfile.v2 @@ -0,0 +1,34 @@ +# Boost Container Library Example Jamfile + +# (C) Copyright Ion Gaztanaga 2009 +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Adapted from John Maddock's TR1 Jamfile.v2 +# Copyright John Maddock 2005. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# this rule enumerates through all the sources and invokes +# the run rule for each source, the result is a list of all +# the run rules, which we can pass on to the test_suite rule: + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob doc_*.cpp ] + { + all_rules += [ run $(fileb) /boost/container//boost_container + : # additional args + : # test-files + : # requirements + ] ; + } + + return $(all_rules) ; +} + +test-suite container_example : [ test_all r ] : multi ; diff --git a/src/boost/libs/container/example/doc_custom_deque.cpp b/src/boost/libs/container/example/doc_custom_deque.cpp new file mode 100644 index 00000000..004796ea --- /dev/null +++ b/src/boost/libs/container/example/doc_custom_deque.cpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_custom_deque +#include +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //This option specifies the desired block size for deque + typedef deque_options< block_size<128u> >::type block_128_option_t; + + //This deque will allocate blocks of 128 elements + typedef deque block_128_deque_t; + assert(block_128_deque_t::get_block_size() == 128u); + + //This option specifies the maximum block size for deque + //in bytes + typedef deque_options< block_bytes<1024u> >::type block_1024_bytes_option_t; + + //This deque will allocate blocks of 1024 bytes + typedef deque block_1024_bytes_deque_t; + assert(block_1024_bytes_deque_t::get_block_size() == 1024u/sizeof(int)); + + return 0; +} +//] diff --git a/src/boost/libs/container/example/doc_custom_small_vector.cpp b/src/boost/libs/container/example/doc_custom_small_vector.cpp new file mode 100644 index 00000000..55fe9613 --- /dev/null +++ b/src/boost/libs/container/example/doc_custom_small_vector.cpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_custom_small_vector +#include +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //This option specifies the desired alignment for the internal value_type + typedef small_vector_options< inplace_alignment<16u> >::type alignment_16_option_t; + + //Check 16 byte alignment option + small_vector sv; + assert(((std::size_t)sv.data() % 16u) == 0); + + + //This option specifies that a vector will increase its capacity 50% + //each time the previous capacity was exhausted. + typedef small_vector_options< growth_factor >::type growth_50_option_t; + + //Fill the vector until full capacity is reached + small_vector growth_50_vector(10, 0); + const std::size_t old_cap = growth_50_vector.capacity(); + growth_50_vector.resize(old_cap); + + //Now insert an additional item and check the new buffer is 50% bigger + growth_50_vector.push_back(1); + assert(growth_50_vector.capacity() == old_cap*3/2); + + return 0; +} +//] diff --git a/src/boost/libs/container/example/doc_custom_static_vector.cpp b/src/boost/libs/container/example/doc_custom_static_vector.cpp new file mode 100644 index 00000000..817ec4cd --- /dev/null +++ b/src/boost/libs/container/example/doc_custom_static_vector.cpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_custom_static_vector +#include +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //This option specifies the desired alignment for value_type + typedef static_vector_options< inplace_alignment<16u> >::type alignment_16_option_t; + + //Check 16 byte alignment option + static_vector sv; + assert(((std::size_t)sv.data() % 16u) == 0); + + //This static_vector won't throw on overflow, for maximum performance + typedef static_vector_options< throw_on_overflow >::type no_throw_options_t; + + //Create static_vector with no throw on overflow + static_vector sv2; + + return 0; +} +//] diff --git a/src/boost/libs/container/example/doc_custom_tree.cpp b/src/boost/libs/container/example/doc_custom_tree.cpp new file mode 100644 index 00000000..ad9d9e0a --- /dev/null +++ b/src/boost/libs/container/example/doc_custom_tree.cpp @@ -0,0 +1,69 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_custom_tree +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //First define several options + // + + //This option specifies an AVL tree based associative container + typedef tree_assoc_options< tree_type >::type AVLTree; + + //This option specifies an AVL tree based associative container + //disabling node size optimization. + typedef tree_assoc_options< tree_type + , optimize_size >::type AVLTreeNoSizeOpt; + + //This option specifies an Splay tree based associative container + typedef tree_assoc_options< tree_type >::type SplayTree; + + //Now define new tree-based associative containers + // + + //AVLTree based set container + typedef set, std::allocator, AVLTree> AvlSet; + + //AVLTree based set container without size optimization + typedef set, std::allocator, AVLTreeNoSizeOpt> AvlSetNoSizeOpt; + + //Splay tree based multiset container + typedef multiset, std::allocator, SplayTree> SplayMultiset; + + //Use them + // + AvlSet avl_set; + avl_set.insert(0); + assert(avl_set.find(0) != avl_set.end()); + + AvlSetNoSizeOpt avl_set_no_szopt; + avl_set_no_szopt.insert(1); + avl_set_no_szopt.insert(1); + assert(avl_set_no_szopt.count(1) == 1); + + SplayMultiset splay_mset; + splay_mset.insert(2); + splay_mset.insert(2); + assert(splay_mset.count(2) == 2); + return 0; +} +//] +#include diff --git a/src/boost/libs/container/example/doc_custom_vector.cpp b/src/boost/libs/container/example/doc_custom_vector.cpp new file mode 100644 index 00000000..08dfad74 --- /dev/null +++ b/src/boost/libs/container/example/doc_custom_vector.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_custom_vector +#include +#include + +//Make sure assertions are active +#ifdef NDEBUG +#undef NDEBUG +#endif +#include + +int main () +{ + using namespace boost::container; + + //This option specifies that a vector that will use "unsigned char" as + //the type to store capacity or size internally. + typedef vector_options< stored_size >::type size_option_t; + + //Size-optimized vector is smaller than the default one. + typedef vector, size_option_t > size_optimized_vector_t; + BOOST_STATIC_ASSERT(( sizeof(size_optimized_vector_t) < sizeof(vector) )); + + //Requesting capacity for more elements than representable by "unsigned char" + //is an error in the size optimized vector. + bool exception_thrown = false; + try { size_optimized_vector_t v(256); } + catch(...){ exception_thrown = true; } + assert(exception_thrown == true); + + //This option specifies that a vector will increase its capacity 50% + //each time the previous capacity was exhausted. + typedef vector_options< growth_factor >::type growth_50_option_t; + + //Fill the vector until full capacity is reached + vector, growth_50_option_t > growth_50_vector(5, 0); + const std::size_t old_cap = growth_50_vector.capacity(); + growth_50_vector.resize(old_cap); + + //Now insert an additional item and check the new buffer is 50% bigger + growth_50_vector.push_back(1); + assert(growth_50_vector.capacity() == old_cap*3/2); + + return 0; +} +//] diff --git a/src/boost/libs/container/example/doc_emplace.cpp b/src/boost/libs/container/example/doc_emplace.cpp new file mode 100644 index 00000000..10ab7437 --- /dev/null +++ b/src/boost/libs/container/example/doc_emplace.cpp @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_emplace +#include +#include + +//Non-copyable and non-movable class +class non_copy_movable +{ + non_copy_movable(const non_copy_movable &); + non_copy_movable& operator=(const non_copy_movable &); + + public: + non_copy_movable(int = 0) {} +}; + +int main () +{ + using namespace boost::container; + + //Store non-copyable and non-movable objects in a list + list l; + non_copy_movable ncm; + + //A new element will be built calling non_copy_movable(int) constructor + l.emplace(l.begin(), 0); + assert(l.size() == 1); + + //A new element will be value initialized + l.emplace(l.begin()); + assert(l.size() == 2); + return 0; +} +//] +#include diff --git a/src/boost/libs/container/example/doc_extended_allocators.cpp b/src/boost/libs/container/example/doc_extended_allocators.cpp new file mode 100644 index 00000000..0eceba41 --- /dev/null +++ b/src/boost/libs/container/example/doc_extended_allocators.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_extended_allocators +#include +#include +#include +#include + +//"allocator" is a general purpose allocator that can reallocate +//memory, something useful for vector and flat associative containers +#include + +//"adaptive_pool" is a node allocator, specially suited for +//node-based containers +#include + +int main () +{ + using namespace boost::container; + + //A vector that can reallocate memory to implement faster insertions + vector > extended_alloc_vector; + + //A flat set that can reallocate memory to implement faster insertions + flat_set, allocator > extended_alloc_flat_set; + + //A list that can manages nodes to implement faster + //range insertions and deletions + list > extended_alloc_list; + + //A set that can recycle nodes to implement faster + //range insertions and deletions + set, adaptive_pool > extended_alloc_set; + + //Now user them as always + extended_alloc_vector.push_back(0); + extended_alloc_flat_set.insert(0); + extended_alloc_list.push_back(0); + extended_alloc_set.insert(0); + + //... + return 0; +} +//] +#include diff --git a/src/boost/libs/container/example/doc_move_containers.cpp b/src/boost/libs/container/example/doc_move_containers.cpp new file mode 100644 index 00000000..e7b09f09 --- /dev/null +++ b/src/boost/libs/container/example/doc_move_containers.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_move_containers +#include +#include +#include + +//Non-copyable class +class non_copyable +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(non_copyable) + + public: + non_copyable(){} + non_copyable(BOOST_RV_REF(non_copyable)) {} + non_copyable& operator=(BOOST_RV_REF(non_copyable)) { return *this; } +}; + +int main () +{ + using namespace boost::container; + + //Store non-copyable objects in a vector + vector v; + non_copyable nc; + v.push_back(boost::move(nc)); + assert(v.size() == 1); + + //Reserve no longer needs copy-constructible + v.reserve(100); + assert(v.capacity() >= 100); + + //This resize overload only needs movable and default constructible + v.resize(200); + assert(v.size() == 200); + + //Containers are also movable + vector v_other(boost::move(v)); + assert(v_other.size() == 200); + assert(v.empty()); + + return 0; +} +//] +#include diff --git a/src/boost/libs/container/example/doc_pmr.cpp b/src/boost/libs/container/example/doc_pmr.cpp new file mode 100644 index 00000000..0d4f5a26 --- /dev/null +++ b/src/boost/libs/container/example/doc_pmr.cpp @@ -0,0 +1,98 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +//[doc_pmr_ShoppingList_hpp +//ShoppingList.hpp +#include +#include + +class ShoppingList +{ + // A vector of strings using polymorphic allocators. Every element + // of the vector will use the same allocator as the vector itself. + boost::container::pmr::vector_of + ::type m_strvec; + //Alternatively in compilers that support template aliases: + // boost::container::pmr::vector m_strvec; + public: + + // This makes uses_allocator::value true + typedef boost::container::pmr::memory_resource* allocator_type; + + // If the allocator is not specified, "m_strvec" uses pmr::get_default_resource(). + explicit ShoppingList(allocator_type alloc = 0) + : m_strvec(alloc) {} + + // Copy constructor. As allocator is not specified, + // "m_strvec" uses pmr::get_default_resource(). + ShoppingList(const ShoppingList& other) + : m_strvec(other.m_strvec) {} + + // Copy construct using the given memory_resource. + ShoppingList(const ShoppingList& other, allocator_type a) + : m_strvec(other.m_strvec, a) {} + + allocator_type get_allocator() const + { return m_strvec.get_allocator().resource(); } + + void add_item(const char *item) + { m_strvec.emplace_back(item); } + + //... +}; + +//]] + +//[doc_pmr_main_cpp + +//=#include "ShoppingList.hpp" +#include +#include +#include + +void processShoppingList(const ShoppingList&) +{ /**/ } + +int main() +{ + using namespace boost::container; + //All memory needed by folder and its contained objects will + //be allocated from the default memory resource (usually new/delete) + pmr::list_of::type folder; // Default allocator resource + //Alternatively in compilers that support template aliases: + // boost::container::pmr::list folder; + { + char buffer[1024]; + pmr::monotonic_buffer_resource buf_rsrc(&buffer, 1024); + + //All memory needed by temporaryShoppingList will be allocated + //from the local buffer (speeds up "processShoppingList") + ShoppingList temporaryShoppingList(&buf_rsrc); + assert(&buf_rsrc == temporaryShoppingList.get_allocator()); + + //list nodes, and strings "salt" and "pepper" will be allocated + //in the stack thanks to "monotonic_buffer_resource". + temporaryShoppingList.add_item("salt"); + temporaryShoppingList.add_item("pepper"); + //... + + //All modifications and additions to "temporaryShoppingList" + //will use memory from "buffer" until it's exhausted. + processShoppingList(temporaryShoppingList); + + //Processing done, now insert it in "folder", + //which uses the default memory resource + folder.push_back(temporaryShoppingList); + assert(pmr::get_default_resource() == folder.back().get_allocator()); + //temporaryShoppingList, buf_rsrc, and buffer go out of scope + } + return 0; +} + +//] diff --git a/src/boost/libs/container/example/doc_recursive_containers.cpp b/src/boost/libs/container/example/doc_recursive_containers.cpp new file mode 100644 index 00000000..6a1746a6 --- /dev/null +++ b/src/boost/libs/container/example/doc_recursive_containers.cpp @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_recursive_containers +#include +#include +#include +#include +#include +#include + +using namespace boost::container; + +struct data +{ + int i_; + //A vector holding still undefined class 'data' + vector v_; + vector::iterator vi_; + //A stable_vector holding still undefined class 'data' + stable_vector sv_; + stable_vector::iterator svi_; + //A stable_vector holding still undefined class 'data' + deque d_; + deque::iterator di_; + //A list holding still undefined 'data' + list l_; + list::iterator li_; + //A map holding still undefined 'data' + map m_; + map::iterator mi_; + + friend bool operator <(const data &l, const data &r) + { return l.i_ < r.i_; } +}; + +struct tree_node +{ + string name; + string value; + + //children nodes of this node + list children_; + list::iterator selected_child_; +}; + + + +int main() +{ + //a container holding a recursive data type + stable_vector sv; + sv.resize(100); + + //Let's build a tree based in + //a recursive data type + tree_node root; + root.name = "root"; + root.value = "root_value"; + root.children_.resize(7); + root.selected_child_ = root.children_.begin(); + return 0; +} +//] +#include diff --git a/src/boost/libs/container/example/doc_type_erasure.cpp b/src/boost/libs/container/example/doc_type_erasure.cpp new file mode 100644 index 00000000..e7760623 --- /dev/null +++ b/src/boost/libs/container/example/doc_type_erasure.cpp @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_type_erasure_MyClassHolder_h +#include + +//MyClassHolder.h + +//We don't need to include "MyClass.h" +//to store vector +class MyClass; + +class MyClassHolder +{ + public: + + void AddNewObject(const MyClass &o); + const MyClass & GetLastObject() const; + + private: + ::boost::container::vector vector_; +}; + +//] + +//[doc_type_erasure_MyClass_h + +//MyClass.h + +class MyClass +{ + private: + int value_; + + public: + MyClass(int val = 0) : value_(val){} + + friend bool operator==(const MyClass &l, const MyClass &r) + { return l.value_ == r.value_; } + //... +}; + +//] + + + +//[doc_type_erasure_main_cpp + +//Main.cpp + +//=#include "MyClassHolder.h" +//=#include "MyClass.h" + +#include + +int main() +{ + MyClass mc(7); + MyClassHolder myclassholder; + myclassholder.AddNewObject(mc); + return myclassholder.GetLastObject() == mc ? 0 : 1; +} +//] + +//[doc_type_erasure_MyClassHolder_cpp + +//MyClassHolder.cpp + +//=#include "MyClassHolder.h" + +//In the implementation MyClass must be a complete +//type so we include the appropriate header +//=#include "MyClass.h" + +void MyClassHolder::AddNewObject(const MyClass &o) +{ vector_.push_back(o); } + +const MyClass & MyClassHolder::GetLastObject() const +{ return vector_.back(); } + +//] + +#include diff --git a/src/boost/libs/container/index.html b/src/boost/libs/container/index.html new file mode 100644 index 00000000..c0373e9b --- /dev/null +++ b/src/boost/libs/container/index.html @@ -0,0 +1,14 @@ + + + + + + +Automatic redirection failed, please go to +../../doc/html/container.html + + diff --git a/src/boost/libs/container/meta/libraries.json b/src/boost/libs/container/meta/libraries.json new file mode 100644 index 00000000..03263b32 --- /dev/null +++ b/src/boost/libs/container/meta/libraries.json @@ -0,0 +1,15 @@ +{ + "key": "container", + "name": "Container", + "authors": [ + "Ion Gazta\u00f1aga" + ], + "description": "Standard library containers and extensions.", + "category": [ + "Containers", + "Data" + ], + "maintainers": [ + "Ion Gaztanaga " + ] +} diff --git a/src/boost/libs/container/proj/to-do.txt b/src/boost/libs/container/proj/to-do.txt new file mode 100644 index 00000000..9c332238 --- /dev/null +++ b/src/boost/libs/container/proj/to-do.txt @@ -0,0 +1,62 @@ +->Change "insert" and "push_back"/"push_front" to catch non-const rvalues +->Add an example with stateful allocators +->Add test to check convertible types in push_back/insert +->Align with C++11 [multi]map::insert(P &&p) overload. +->Fix code marked with "//to-do: if possible, an efficient way to deallocate allocated blocks" +->Add BOOST_CONTAINER_TRY, etc. macros to allow disabling exceptions only in this library (just like Boost.Intrusive) +->Add macro to change the default allocator std::allocator to another one +->Add front()/back() to string + + +Review allocator traits +-> Avoid any rebind<>::other +-> Review select_on_container_copy_xxx +-> Review propagate_on_xxx +-> Put default constructed containers with their own constructor (different nothrow guarantees). Optimization, not needed +-> Default + swap move constructors correct? +-> Review container documentation in swap/copy/move regarding allocators + +Check all move constructors: swap might not be a valid idiom, allocators must be move constructed, +intrusive containers are now movable + +Add and test: + +Test different propagation values and with inequal allocators + +propagate_on_container_move_assignment +select_on_container_copy_construction +propagate_on_container_swap +propagate_on_container_copy_assignment + +Test move constructors with data values and unequal allocators + +An allocator should use a smart allocator not constructible from raw pointers to catch missing pointer_traits calls + +Add initializer lists + +Write forward_list + +check move if noexcept conditions in vector, deque and stable_vector + +Add noexcept testing using static_assert (Howard Hinnants's suggestion): + + #include + + struct A + { + void foo() noexcept; + }; + + static_assert(noexcept(std::declval().foo()), "A::foo() should be noexcept"); + +Detect always equal or unequal allocators at compiler time. operator== returns true_type or false_type + +change virtual functions with pointers to avoid template instantiation for every type + +Add hash for containers + +Add std:: hashing support + +Fix trivial destructor after move and other optimizing traits + +Implement n3586, "Splicing Maps and Sets" (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3586.pdf) diff --git a/src/boost/libs/container/proj/vc7ide/alloc_basic_test.vcproj b/src/boost/libs/container/proj/vc7ide/alloc_basic_test.vcproj new file mode 100644 index 00000000..cb13a889 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/alloc_basic_test.vcproj @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/alloc_full_test.vcproj b/src/boost/libs/container/proj/vc7ide/alloc_full_test.vcproj new file mode 100644 index 00000000..2508d0e6 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/alloc_full_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/alloc_lib.vcproj b/src/boost/libs/container/proj/vc7ide/alloc_lib.vcproj new file mode 100644 index 00000000..31983cc8 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/alloc_lib.vcproj @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/allocator_traits_test.vcproj b/src/boost/libs/container/proj/vc7ide/allocator_traits_test.vcproj new file mode 100644 index 00000000..fda5d865 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/allocator_traits_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_adaptive_node_pool.vcproj b/src/boost/libs/container/proj/vc7ide/bench_adaptive_node_pool.vcproj new file mode 100644 index 00000000..8749c282 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_adaptive_node_pool.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_alloc.vcproj b/src/boost/libs/container/proj/vc7ide/bench_alloc.vcproj new file mode 100644 index 00000000..90404bcc --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_alloc.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_alloc_expand_bwd.vcproj b/src/boost/libs/container/proj/vc7ide/bench_alloc_expand_bwd.vcproj new file mode 100644 index 00000000..306eeea5 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_alloc_expand_bwd.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_alloc_expand_fwd.vcproj b/src/boost/libs/container/proj/vc7ide/bench_alloc_expand_fwd.vcproj new file mode 100644 index 00000000..e3f14150 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_alloc_expand_fwd.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_alloc_shrink_to_fit.vcproj b/src/boost/libs/container/proj/vc7ide/bench_alloc_shrink_to_fit.vcproj new file mode 100644 index 00000000..cd1fa171 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_alloc_shrink_to_fit.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_alloc_stable_vector_burst.vcproj b/src/boost/libs/container/proj/vc7ide/bench_alloc_stable_vector_burst.vcproj new file mode 100644 index 00000000..3e07acff --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_alloc_stable_vector_burst.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_flat_multiset.vcproj b/src/boost/libs/container/proj/vc7ide/bench_flat_multiset.vcproj new file mode 100644 index 00000000..1c1bb900 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_flat_multiset.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_flat_set.vcproj b/src/boost/libs/container/proj/vc7ide/bench_flat_set.vcproj new file mode 100644 index 00000000..54d2cd4d --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_flat_set.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set.vcproj new file mode 100644 index 00000000..96b49f4c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set_adaptive_pool.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set_adaptive_pool.vcproj new file mode 100644 index 00000000..fcb8dbe4 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set_adaptive_pool.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set_alloc_v2.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set_alloc_v2.vcproj new file mode 100644 index 00000000..160c27e0 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set_alloc_v2.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set_avl.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set_avl.vcproj new file mode 100644 index 00000000..e18fa66a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set_avl.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set_multi.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set_multi.vcproj new file mode 100644 index 00000000..166df346 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set_multi.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set_sg.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set_sg.vcproj new file mode 100644 index 00000000..751e653d --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set_sg.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_set_sp.vcproj b/src/boost/libs/container/proj/vc7ide/bench_set_sp.vcproj new file mode 100644 index 00000000..5a123ab0 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_set_sp.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/bench_static_vector.vcproj b/src/boost/libs/container/proj/vc7ide/bench_static_vector.vcproj new file mode 100644 index 00000000..5648015b --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/bench_static_vector.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/container.sln b/src/boost/libs/container/proj/vc7ide/container.sln new file mode 100644 index 00000000..76933485 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/container.sln @@ -0,0 +1,685 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_containerlib", "container.vcproj", "{FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stable_vector_test", "stable_vector_test.vcproj", "{5E11C8D3-FA52-760A-84FE-943A6BA05A21}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "static_vector_test", "static_vector_test.vcproj", "{58E1C1C3-096A-84FE-4FA2-D6BA79201C02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_test", "string_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D4A792607}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "throw_exception_test", "throw_exception_test.vcproj", "{5A8D91E0-FA57-284F-84FE-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_test", "vector_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deque_test", "deque_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792655}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_map_test", "flat_map_test.vcproj", "{5188ECE3-6092-8FE0-44A7-BAD3A7926329}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_set_test", "flat_set_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792637}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_table_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pair_test", "pair_test.vcproj", "{58CA17C5-A74F-9602-48FE-B06310DA7FA6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scoped_allocator_usage_test", "scoped_allocator_usage_test.vcproj", "{B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_custom_tree", "doc_custom_tree.vcproj", "{5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_extended_allocators", "doc_extended_allocators.vcproj", "{5CE11C83-FA84-295A-4FA2-D7921A0BAB02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set_avl", "bench_set_avl.vcproj", "{5E1C1C23-26A9-AC4E-1FE5-C733DA52712B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set_multi", "bench_set_multi.vcproj", "{51E1C2C3-26A9-24FE-24DE-DB271C32332B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set_sg", "bench_set_sg.vcproj", "{51C2C0E3-6A93-4F4E-4DE1-D25273C32B3B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set_sp", "bench_set_sp.vcproj", "{5C2C01E3-4E4F-6A93-4DE1-D5273C316BBB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_flat_set", "bench_flat_set.vcproj", "{5C2C01E3-DE40-F4A9-63F3-D3C316B327AB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_flat_multiset", "bench_flat_multiset.vcproj", "{E5C01323-3F2C-D074-F4A9-D16B31CC275B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set_alloc_v2", "bench_set_alloc_v2.vcproj", "{5C2D1813-24CE-A826-4FE5-5732251A3FAF}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "insert_vs_emplace_test", "insert_vs_emplace_test.vcproj", "{A1C1C223-26A9-A20E-4CE5-D3325271A7CB}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "null_iterators_test", "null_iterators_test.vcproj", "{C90520E3-B8A9-EB54-76E2-25DFA3C7762A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_vector_test", "explicit_inst_vector_test.vcproj", "{CA85EE11-096A-4F8A-4FA2-92DA72020000}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_list_test", "explicit_inst_list_test.vcproj", "{CE1A85E0-096A-42FC-F83A-97A242002DA5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_deque_test", "explicit_inst_deque_test.vcproj", "{CEE1A855-096A-3AC8-2F5C-9DA2420523A5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_slist_test", "explicit_inst_slist_test.vcproj", "{CE1A8F65-AC48-096A-2F5C-7A2420D323A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_stable_vector_test", "explicit_inst_stable_vector_test.vcproj", "{AC285EA1-F8A3-306C-4FA2-A02029D5E720}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_static_vector_test", "explicit_inst_static_vector_test.vcproj", "{E287ACA1-FA42-3F7A-06C2-AC72012209F5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_string_test", "explicit_inst_string_test.vcproj", "{6A85ECE0-A596-24EA-F83A-9231D72A0217}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_set_test", "explicit_inst_set_test.vcproj", "{C11D9E85-16A9-4A2E-C4F6-92F7E138200D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_map_test", "explicit_inst_map_test.vcproj", "{CD9E8655-94A3-6C2E-C4F6-97E1382073FC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_flat_map_test", "explicit_inst_flat_map_test.vcproj", "{9845ECE5-C27E-4F6C-94A3-9C2E1E7231FC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_flat_set_test", "explicit_inst_flat_set_test.vcproj", "{C811D9F8-A27E-1A91-FC44-92F14F73820B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "small_vector_test", "small_vector_test.vcproj", "{5CE8E110-096A-84FE-4A2A-BA7E925A6002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_alloc_stable_vector_burst", "bench_alloc_stable_vector_burst.vcproj", "{C3AD2582-79BF-2FE1-8612-BD707552A6A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_resource_test", "memory_resource_test.vcproj", "{5711C8E3-84EE-396A-4FA2-D6B03AA79202}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scoped_allocator_adaptor_test", "scoped_allocator_adaptor_test.vcproj", "{B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uses_allocator_test", "uses_allocator_test.vcproj", "{B9FB0E62-D7C3-3A19-4461-58E6B252FAB7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polymorphic_allocator_test", "polymorphic_allocator_test.vcproj", "{5411C8E1-36A7-8E4C-4FA2-D0C903AA2072}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "resource_adaptor_test", "resource_adaptor.vcproj", "{5111AC8E-396A-4FA2-4F8E-3923DA7C03A2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monotonic_buffer_resource_test", "monotonic_buffer_resource_test.vcproj", "{531AC82E-41FA-96E3-4F8E-32372DA7C3C2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unsynchronized_pool_resource_test", "unsynchronized_pool_resource_test.vcproj", "{51FC821E-41FA-196E-F8E0-328DA3A37C72}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "synchronized_pool_resource_test", "synchronized_pool_resource_test.vcproj", "{5AC821FE-961F-4FA3-F8E0-38DC72DA3397}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "global_resource_test", "global_resource.vcproj", "{7C85E213-963A-84EE-4FA2-970396BAA802}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_pmr", "doc_pmr.vcproj", "{58E1C1F3-1A4F-15C5-4FA2-DA6A904B3041}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "explicit_inst_small_vector_test", "explicit_inst_small_vector_test.vcproj", "{CA85EE11-4F8A-0F96-A14F-92205A02D723}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_deque_test", "pmr_deque_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7231}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_flat_map_test", "pmr_flat_map_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E723A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_flat_set_test", "pmr_flat_set_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7239}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_list_test", "pmr_list_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7238}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_map_test", "pmr_map_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7237}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_set_test", "pmr_set_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7236}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_small_vector_test", "pmr_small_vector_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7234}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_stable_vector_test", "pmr_stable_vector_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7230}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_vector_test", "pmr_vector_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7232}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_string_test", "pmr_string_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7233}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_handle_test", "node_handle_test.vcproj", "{5A17C6C5-6C29-A74F-48FE-A7FA7A063106}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_view_compat_test", "string_view_compat_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D4A792607}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcproj", "{5CE185C3-2609-4FA5-FE38-792BA0D3A606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree_test.vcproj", "{DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_options_test", "vector_options_test.vcproj", "{3E10C8C3-4F8E-96A0-4FA2-D032BA7A6092}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_custom_vector", "doc_custom_vector.vcproj", "{5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_alloc_lib", "alloc_lib.vcproj", "{685AC59C-E667-4096-9DAA-AB76083C7092}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_alloc", "bench_alloc.vcproj", "{7CC83A22-8612-7BF8-2F4E-BD9493C6A071}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_adaptive_node_pool", "bench_adaptive_node_pool.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_alloc_expand_bwd", "bench_alloc_expand_bwd.vcproj", "{C7C283A2-7BF8-8612-42FE-B9D26A0793A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_alloc_shrink_to_fit", "bench_alloc_shrink_to_fit.vcproj", "{C7C283A2-7BF8-8612-42FE-B9D26A0793A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_alloc_expand_fwd", "bench_alloc_expand_fwd.vcproj", "{C7C283A2-7BF8-8612-42FE-B9D26A0793A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set", "bench_set.vcproj", "{5E1C1C23-26A9-4FE5-A24E-DA735271C32B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_static_vector", "bench_static_vector.vcproj", "{55E1C1C3-84FE-26A9-4A2E-D7901C32BA02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_emplace", "doc_emplace.vcproj", "{5CE11C83-FA84-295A-4FA2-D7921A0BAB02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_containers", "doc_move_containers.vcproj", "{5D1C8E13-255A-FA84-4FA2-DA92100BAD42}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_recursive_containers", "doc_recursive_containers.vcproj", "{1B51C8B2-A832-F55A-4FA2-210AF9D43BD2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_type_erasure", "doc_type_erasure.vcproj", "{5C8E1C13-A4F4-2C55-4FA2-D100BA6A9041}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_test", "map_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_string_test", "pmr_slist_test.vcproj", "{85EADC21-42FA-F8A3-306C-A2029D5E7235}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "set_test", "set_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alloc_basic_test", "alloc_basic_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alloc_full_test", "alloc_full_test.vcproj", "{CD57C283-1862-9FE5-BF87-BA91293A76D3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "allocator_traits_test", "allocator_traits_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_set_adaptive_pool", "bench_set_adaptive_pool.vcproj", "{5C2D1813-24CE-A826-4FE5-5732251A3FAF}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Debug.ActiveCfg = Debug|Win32 + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Debug.Build.0 = Debug|Win32 + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Release.ActiveCfg = Release|Win32 + {FF56BAF1-32EC-4B22-B6BD-95A3A67C3135}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.ActiveCfg = Debug|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.Build.0 = Debug|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.ActiveCfg = Release|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.Build.0 = Release|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Debug.ActiveCfg = Debug|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Debug.Build.0 = Debug|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Release.ActiveCfg = Release|Win32 + {58E1C1C3-096A-84FE-4FA2-D6BA79201C02}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 + {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5A8D91E0-FA57-284F-84FE-D3A6BA792002}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.Build.0 = Release|Win32 + {5188ECE3-6092-8FE0-44A7-BAD3A7926329}.Debug.ActiveCfg = Debug|Win32 + {5188ECE3-6092-8FE0-44A7-BAD3A7926329}.Debug.Build.0 = Debug|Win32 + {5188ECE3-6092-8FE0-44A7-BAD3A7926329}.Release.ActiveCfg = Release|Win32 + {5188ECE3-6092-8FE0-44A7-BAD3A7926329}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Debug.ActiveCfg = Debug|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Debug.Build.0 = Debug|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Release.ActiveCfg = Release|Win32 + {58CA17C5-A74F-9602-48FE-B06310DA7FA6}.Release.Build.0 = Release|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.ActiveCfg = Debug|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.Build.0 = Debug|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.ActiveCfg = Release|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.Build.0 = Release|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Debug.ActiveCfg = Debug|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Debug.Build.0 = Debug|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Release.ActiveCfg = Release|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Release.Build.0 = Release|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Debug.Build.0 = Debug|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Release.ActiveCfg = Release|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Release.Build.0 = Release|Win32 + {5E1C1C23-26A9-AC4E-1FE5-C733DA52712B}.Debug.ActiveCfg = Debug|Win32 + {5E1C1C23-26A9-AC4E-1FE5-C733DA52712B}.Debug.Build.0 = Debug|Win32 + {5E1C1C23-26A9-AC4E-1FE5-C733DA52712B}.Release.ActiveCfg = Release|Win32 + {5E1C1C23-26A9-AC4E-1FE5-C733DA52712B}.Release.Build.0 = Release|Win32 + {51E1C2C3-26A9-24FE-24DE-DB271C32332B}.Debug.ActiveCfg = Debug|Win32 + {51E1C2C3-26A9-24FE-24DE-DB271C32332B}.Debug.Build.0 = Debug|Win32 + {51E1C2C3-26A9-24FE-24DE-DB271C32332B}.Release.ActiveCfg = Release|Win32 + {51E1C2C3-26A9-24FE-24DE-DB271C32332B}.Release.Build.0 = Release|Win32 + {51C2C0E3-6A93-4F4E-4DE1-D25273C32B3B}.Debug.ActiveCfg = Debug|Win32 + {51C2C0E3-6A93-4F4E-4DE1-D25273C32B3B}.Debug.Build.0 = Debug|Win32 + {51C2C0E3-6A93-4F4E-4DE1-D25273C32B3B}.Release.ActiveCfg = Release|Win32 + {51C2C0E3-6A93-4F4E-4DE1-D25273C32B3B}.Release.Build.0 = Release|Win32 + {5C2C01E3-4E4F-6A93-4DE1-D5273C316BBB}.Debug.ActiveCfg = Debug|Win32 + {5C2C01E3-4E4F-6A93-4DE1-D5273C316BBB}.Debug.Build.0 = Debug|Win32 + {5C2C01E3-4E4F-6A93-4DE1-D5273C316BBB}.Release.ActiveCfg = Release|Win32 + {5C2C01E3-4E4F-6A93-4DE1-D5273C316BBB}.Release.Build.0 = Release|Win32 + {5C2C01E3-DE40-F4A9-63F3-D3C316B327AB}.Debug.ActiveCfg = Debug|Win32 + {5C2C01E3-DE40-F4A9-63F3-D3C316B327AB}.Debug.Build.0 = Debug|Win32 + {5C2C01E3-DE40-F4A9-63F3-D3C316B327AB}.Release.ActiveCfg = Release|Win32 + {5C2C01E3-DE40-F4A9-63F3-D3C316B327AB}.Release.Build.0 = Release|Win32 + {E5C01323-3F2C-D074-F4A9-D16B31CC275B}.Debug.ActiveCfg = Debug|Win32 + {E5C01323-3F2C-D074-F4A9-D16B31CC275B}.Debug.Build.0 = Debug|Win32 + {E5C01323-3F2C-D074-F4A9-D16B31CC275B}.Release.ActiveCfg = Release|Win32 + {E5C01323-3F2C-D074-F4A9-D16B31CC275B}.Release.Build.0 = Release|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Debug.ActiveCfg = Debug|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Debug.Build.0 = Debug|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Release.ActiveCfg = Release|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Release.Build.0 = Release|Win32 + {A1C1C223-26A9-A20E-4CE5-D3325271A7CB}.Debug.ActiveCfg = Debug|Win32 + {A1C1C223-26A9-A20E-4CE5-D3325271A7CB}.Release.ActiveCfg = Release|Win32 + {C90520E3-B8A9-EB54-76E2-25DFA3C7762A}.Debug.ActiveCfg = Debug|Win32 + {C90520E3-B8A9-EB54-76E2-25DFA3C7762A}.Debug.Build.0 = Debug|Win32 + {C90520E3-B8A9-EB54-76E2-25DFA3C7762A}.Release.ActiveCfg = Release|Win32 + {C90520E3-B8A9-EB54-76E2-25DFA3C7762A}.Release.Build.0 = Release|Win32 + {CA85EE11-096A-4F8A-4FA2-92DA72020000}.Debug.ActiveCfg = Debug|Win32 + {CA85EE11-096A-4F8A-4FA2-92DA72020000}.Debug.Build.0 = Debug|Win32 + {CA85EE11-096A-4F8A-4FA2-92DA72020000}.Release.ActiveCfg = Release|Win32 + {CA85EE11-096A-4F8A-4FA2-92DA72020000}.Release.Build.0 = Release|Win32 + {CE1A85E0-096A-42FC-F83A-97A242002DA5}.Debug.ActiveCfg = Debug|Win32 + {CE1A85E0-096A-42FC-F83A-97A242002DA5}.Debug.Build.0 = Debug|Win32 + {CE1A85E0-096A-42FC-F83A-97A242002DA5}.Release.ActiveCfg = Release|Win32 + {CE1A85E0-096A-42FC-F83A-97A242002DA5}.Release.Build.0 = Release|Win32 + {CEE1A855-096A-3AC8-2F5C-9DA2420523A5}.Debug.ActiveCfg = Debug|Win32 + {CEE1A855-096A-3AC8-2F5C-9DA2420523A5}.Debug.Build.0 = Debug|Win32 + {CEE1A855-096A-3AC8-2F5C-9DA2420523A5}.Release.ActiveCfg = Release|Win32 + {CEE1A855-096A-3AC8-2F5C-9DA2420523A5}.Release.Build.0 = Release|Win32 + {CE1A8F65-AC48-096A-2F5C-7A2420D323A1}.Debug.ActiveCfg = Debug|Win32 + {CE1A8F65-AC48-096A-2F5C-7A2420D323A1}.Debug.Build.0 = Debug|Win32 + {CE1A8F65-AC48-096A-2F5C-7A2420D323A1}.Release.ActiveCfg = Release|Win32 + {CE1A8F65-AC48-096A-2F5C-7A2420D323A1}.Release.Build.0 = Release|Win32 + {AC285EA1-F8A3-306C-4FA2-A02029D5E720}.Debug.ActiveCfg = Debug|Win32 + {AC285EA1-F8A3-306C-4FA2-A02029D5E720}.Debug.Build.0 = Debug|Win32 + {AC285EA1-F8A3-306C-4FA2-A02029D5E720}.Release.ActiveCfg = Release|Win32 + {AC285EA1-F8A3-306C-4FA2-A02029D5E720}.Release.Build.0 = Release|Win32 + {E287ACA1-FA42-3F7A-06C2-AC72012209F5}.Debug.ActiveCfg = Debug|Win32 + {E287ACA1-FA42-3F7A-06C2-AC72012209F5}.Debug.Build.0 = Debug|Win32 + {E287ACA1-FA42-3F7A-06C2-AC72012209F5}.Release.ActiveCfg = Release|Win32 + {E287ACA1-FA42-3F7A-06C2-AC72012209F5}.Release.Build.0 = Release|Win32 + {6A85ECE0-A596-24EA-F83A-9231D72A0217}.Debug.ActiveCfg = Debug|Win32 + {6A85ECE0-A596-24EA-F83A-9231D72A0217}.Debug.Build.0 = Debug|Win32 + {6A85ECE0-A596-24EA-F83A-9231D72A0217}.Release.ActiveCfg = Release|Win32 + {6A85ECE0-A596-24EA-F83A-9231D72A0217}.Release.Build.0 = Release|Win32 + {C11D9E85-16A9-4A2E-C4F6-92F7E138200D}.Debug.ActiveCfg = Debug|Win32 + {C11D9E85-16A9-4A2E-C4F6-92F7E138200D}.Debug.Build.0 = Debug|Win32 + {C11D9E85-16A9-4A2E-C4F6-92F7E138200D}.Release.ActiveCfg = Release|Win32 + {C11D9E85-16A9-4A2E-C4F6-92F7E138200D}.Release.Build.0 = Release|Win32 + {CD9E8655-94A3-6C2E-C4F6-97E1382073FC}.Debug.ActiveCfg = Debug|Win32 + {CD9E8655-94A3-6C2E-C4F6-97E1382073FC}.Debug.Build.0 = Debug|Win32 + {CD9E8655-94A3-6C2E-C4F6-97E1382073FC}.Release.ActiveCfg = Release|Win32 + {CD9E8655-94A3-6C2E-C4F6-97E1382073FC}.Release.Build.0 = Release|Win32 + {9845ECE5-C27E-4F6C-94A3-9C2E1E7231FC}.Debug.ActiveCfg = Debug|Win32 + {9845ECE5-C27E-4F6C-94A3-9C2E1E7231FC}.Debug.Build.0 = Debug|Win32 + {9845ECE5-C27E-4F6C-94A3-9C2E1E7231FC}.Release.ActiveCfg = Release|Win32 + {9845ECE5-C27E-4F6C-94A3-9C2E1E7231FC}.Release.Build.0 = Release|Win32 + {C811D9F8-A27E-1A91-FC44-92F14F73820B}.Debug.ActiveCfg = Debug|Win32 + {C811D9F8-A27E-1A91-FC44-92F14F73820B}.Debug.Build.0 = Debug|Win32 + {C811D9F8-A27E-1A91-FC44-92F14F73820B}.Release.ActiveCfg = Release|Win32 + {C811D9F8-A27E-1A91-FC44-92F14F73820B}.Release.Build.0 = Release|Win32 + {5CE8E110-096A-84FE-4A2A-BA7E925A6002}.Debug.ActiveCfg = Debug|Win32 + {5CE8E110-096A-84FE-4A2A-BA7E925A6002}.Debug.Build.0 = Debug|Win32 + {5CE8E110-096A-84FE-4A2A-BA7E925A6002}.Release.ActiveCfg = Release|Win32 + {5CE8E110-096A-84FE-4A2A-BA7E925A6002}.Release.Build.0 = Release|Win32 + {C3AD2582-79BF-2FE1-8612-BD707552A6A1}.Debug.ActiveCfg = Debug|Win32 + {C3AD2582-79BF-2FE1-8612-BD707552A6A1}.Debug.Build.0 = Debug|Win32 + {C3AD2582-79BF-2FE1-8612-BD707552A6A1}.Release.ActiveCfg = Release|Win32 + {C3AD2582-79BF-2FE1-8612-BD707552A6A1}.Release.Build.0 = Release|Win32 + {5711C8E3-84EE-396A-4FA2-D6B03AA79202}.Debug.ActiveCfg = Debug|Win32 + {5711C8E3-84EE-396A-4FA2-D6B03AA79202}.Debug.Build.0 = Debug|Win32 + {5711C8E3-84EE-396A-4FA2-D6B03AA79202}.Release.ActiveCfg = Release|Win32 + {5711C8E3-84EE-396A-4FA2-D6B03AA79202}.Release.Build.0 = Release|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.ActiveCfg = Debug|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Debug.Build.0 = Debug|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.ActiveCfg = Release|Win32 + {B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}.Release.Build.0 = Release|Win32 + {B9FB0E62-D7C3-3A19-4461-58E6B252FAB7}.Debug.ActiveCfg = Debug|Win32 + {B9FB0E62-D7C3-3A19-4461-58E6B252FAB7}.Debug.Build.0 = Debug|Win32 + {B9FB0E62-D7C3-3A19-4461-58E6B252FAB7}.Release.ActiveCfg = Release|Win32 + {B9FB0E62-D7C3-3A19-4461-58E6B252FAB7}.Release.Build.0 = Release|Win32 + {5411C8E1-36A7-8E4C-4FA2-D0C903AA2072}.Debug.ActiveCfg = Debug|Win32 + {5411C8E1-36A7-8E4C-4FA2-D0C903AA2072}.Debug.Build.0 = Debug|Win32 + {5411C8E1-36A7-8E4C-4FA2-D0C903AA2072}.Release.ActiveCfg = Release|Win32 + {5411C8E1-36A7-8E4C-4FA2-D0C903AA2072}.Release.Build.0 = Release|Win32 + {5111AC8E-396A-4FA2-4F8E-3923DA7C03A2}.Debug.ActiveCfg = Debug|Win32 + {5111AC8E-396A-4FA2-4F8E-3923DA7C03A2}.Debug.Build.0 = Debug|Win32 + {5111AC8E-396A-4FA2-4F8E-3923DA7C03A2}.Release.ActiveCfg = Release|Win32 + {5111AC8E-396A-4FA2-4F8E-3923DA7C03A2}.Release.Build.0 = Release|Win32 + {531AC82E-41FA-96E3-4F8E-32372DA7C3C2}.Debug.ActiveCfg = Debug|Win32 + {531AC82E-41FA-96E3-4F8E-32372DA7C3C2}.Debug.Build.0 = Debug|Win32 + {531AC82E-41FA-96E3-4F8E-32372DA7C3C2}.Release.ActiveCfg = Release|Win32 + {531AC82E-41FA-96E3-4F8E-32372DA7C3C2}.Release.Build.0 = Release|Win32 + {51FC821E-41FA-196E-F8E0-328DA3A37C72}.Debug.ActiveCfg = Debug|Win32 + {51FC821E-41FA-196E-F8E0-328DA3A37C72}.Debug.Build.0 = Debug|Win32 + {51FC821E-41FA-196E-F8E0-328DA3A37C72}.Release.ActiveCfg = Release|Win32 + {51FC821E-41FA-196E-F8E0-328DA3A37C72}.Release.Build.0 = Release|Win32 + {5AC821FE-961F-4FA3-F8E0-38DC72DA3397}.Debug.ActiveCfg = Debug|Win32 + {5AC821FE-961F-4FA3-F8E0-38DC72DA3397}.Debug.Build.0 = Debug|Win32 + {5AC821FE-961F-4FA3-F8E0-38DC72DA3397}.Release.ActiveCfg = Release|Win32 + {5AC821FE-961F-4FA3-F8E0-38DC72DA3397}.Release.Build.0 = Release|Win32 + {7C85E213-963A-84EE-4FA2-970396BAA802}.Debug.ActiveCfg = Debug|Win32 + {7C85E213-963A-84EE-4FA2-970396BAA802}.Debug.Build.0 = Debug|Win32 + {7C85E213-963A-84EE-4FA2-970396BAA802}.Release.ActiveCfg = Release|Win32 + {7C85E213-963A-84EE-4FA2-970396BAA802}.Release.Build.0 = Release|Win32 + {58E1C1F3-1A4F-15C5-4FA2-DA6A904B3041}.Debug.ActiveCfg = Debug|Win32 + {58E1C1F3-1A4F-15C5-4FA2-DA6A904B3041}.Debug.Build.0 = Debug|Win32 + {58E1C1F3-1A4F-15C5-4FA2-DA6A904B3041}.Release.ActiveCfg = Release|Win32 + {58E1C1F3-1A4F-15C5-4FA2-DA6A904B3041}.Release.Build.0 = Release|Win32 + {CA85EE11-4F8A-0F96-A14F-92205A02D723}.Debug.ActiveCfg = Debug|Win32 + {CA85EE11-4F8A-0F96-A14F-92205A02D723}.Debug.Build.0 = Debug|Win32 + {CA85EE11-4F8A-0F96-A14F-92205A02D723}.Release.ActiveCfg = Release|Win32 + {CA85EE11-4F8A-0F96-A14F-92205A02D723}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7231}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7231}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7231}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7231}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E723A}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E723A}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E723A}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E723A}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7239}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7239}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7239}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7239}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7238}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7238}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7238}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7238}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7237}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7237}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7237}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7237}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7236}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7236}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7236}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7236}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7234}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7234}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7234}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7234}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7230}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7230}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7230}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7230}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7232}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7232}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7232}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7232}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Release.Build.0 = Release|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Debug.ActiveCfg = Debug|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Debug.Build.0 = Debug|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Release.ActiveCfg = Release|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Debug.ActiveCfg = Debug|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Debug.Build.0 = Debug|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Release.ActiveCfg = Release|Win32 + {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Release.Build.0 = Release|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Debug.ActiveCfg = Debug|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Debug.Build.0 = Debug|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Release.ActiveCfg = Release|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Release.Build.0 = Release|Win32 + {3E10C8C3-4F8E-96A0-4FA2-D032BA7A6092}.Debug.ActiveCfg = Debug|Win32 + {3E10C8C3-4F8E-96A0-4FA2-D032BA7A6092}.Debug.Build.0 = Debug|Win32 + {3E10C8C3-4F8E-96A0-4FA2-D032BA7A6092}.Release.ActiveCfg = Release|Win32 + {3E10C8C3-4F8E-96A0-4FA2-D032BA7A6092}.Release.Build.0 = Release|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Debug.ActiveCfg = Debug|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Debug.Build.0 = Debug|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Release.ActiveCfg = Release|Win32 + {5E11C8B3-A8C4-4A2F-295A-7951A0EDAA02}.Release.Build.0 = Release|Win32 + {685AC59C-E667-4096-9DAA-AB76083C7092}.Debug.ActiveCfg = Debug|Win32 + {685AC59C-E667-4096-9DAA-AB76083C7092}.Debug.Build.0 = Debug|Win32 + {685AC59C-E667-4096-9DAA-AB76083C7092}.Release.ActiveCfg = Release|Win32 + {685AC59C-E667-4096-9DAA-AB76083C7092}.Release.Build.0 = Release|Win32 + {7CC83A22-8612-7BF8-2F4E-BD9493C6A071}.Debug.ActiveCfg = Debug|Win32 + {7CC83A22-8612-7BF8-2F4E-BD9493C6A071}.Debug.Build.0 = Debug|Win32 + {7CC83A22-8612-7BF8-2F4E-BD9493C6A071}.Release.ActiveCfg = Release|Win32 + {7CC83A22-8612-7BF8-2F4E-BD9493C6A071}.Release.Build.0 = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Debug.ActiveCfg = Debug|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Debug.Build.0 = Debug|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Release.ActiveCfg = Release|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Release.Build.0 = Release|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Debug.ActiveCfg = Debug|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Debug.Build.0 = Debug|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Release.ActiveCfg = Release|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Release.Build.0 = Release|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Debug.ActiveCfg = Debug|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Debug.Build.0 = Debug|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Release.ActiveCfg = Release|Win32 + {C7C283A2-7BF8-8612-42FE-B9D26A0793A1}.Release.Build.0 = Release|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Debug.ActiveCfg = Debug|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Debug.Build.0 = Debug|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Release.ActiveCfg = Release|Win32 + {5E1C1C23-26A9-4FE5-A24E-DA735271C32B}.Release.Build.0 = Release|Win32 + {55E1C1C3-84FE-26A9-4A2E-D7901C32BA02}.Debug.ActiveCfg = Debug|Win32 + {55E1C1C3-84FE-26A9-4A2E-D7901C32BA02}.Debug.Build.0 = Debug|Win32 + {55E1C1C3-84FE-26A9-4A2E-D7901C32BA02}.Release.ActiveCfg = Release|Win32 + {55E1C1C3-84FE-26A9-4A2E-D7901C32BA02}.Release.Build.0 = Release|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Debug.Build.0 = Debug|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Release.ActiveCfg = Release|Win32 + {5CE11C83-FA84-295A-4FA2-D7921A0BAB02}.Release.Build.0 = Release|Win32 + {5D1C8E13-255A-FA84-4FA2-DA92100BAD42}.Debug.ActiveCfg = Debug|Win32 + {5D1C8E13-255A-FA84-4FA2-DA92100BAD42}.Debug.Build.0 = Debug|Win32 + {5D1C8E13-255A-FA84-4FA2-DA92100BAD42}.Release.ActiveCfg = Release|Win32 + {5D1C8E13-255A-FA84-4FA2-DA92100BAD42}.Release.Build.0 = Release|Win32 + {1B51C8B2-A832-F55A-4FA2-210AF9D43BD2}.Debug.ActiveCfg = Debug|Win32 + {1B51C8B2-A832-F55A-4FA2-210AF9D43BD2}.Debug.Build.0 = Debug|Win32 + {1B51C8B2-A832-F55A-4FA2-210AF9D43BD2}.Release.ActiveCfg = Release|Win32 + {1B51C8B2-A832-F55A-4FA2-210AF9D43BD2}.Release.Build.0 = Release|Win32 + {5C8E1C13-A4F4-2C55-4FA2-D100BA6A9041}.Debug.ActiveCfg = Debug|Win32 + {5C8E1C13-A4F4-2C55-4FA2-D100BA6A9041}.Debug.Build.0 = Debug|Win32 + {5C8E1C13-A4F4-2C55-4FA2-D100BA6A9041}.Release.ActiveCfg = Release|Win32 + {5C8E1C13-A4F4-2C55-4FA2-D100BA6A9041}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7235}.Debug.ActiveCfg = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7235}.Debug.Build.0 = Debug|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7235}.Release.ActiveCfg = Release|Win32 + {85EADC21-42FA-F8A3-306C-A2029D5E7235}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-9FE5-BF87-BA91293A76D3}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-9FE5-BF87-BA91293A76D3}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-9FE5-BF87-BA91293A76D3}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-9FE5-BF87-BA91293A76D3}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Debug.ActiveCfg = Debug|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Debug.Build.0 = Debug|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Release.ActiveCfg = Release|Win32 + {5C2D1813-24CE-A826-4FE5-5732251A3FAF}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/src/boost/libs/container/proj/vc7ide/container.vcproj b/src/boost/libs/container/proj/vc7ide/container.vcproj new file mode 100644 index 00000000..28db9cdd --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/container.vcproj @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/deque_test.vcproj b/src/boost/libs/container/proj/vc7ide/deque_test.vcproj new file mode 100644 index 00000000..c2344fe9 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/deque_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_custom_tree.vcproj b/src/boost/libs/container/proj/vc7ide/doc_custom_tree.vcproj new file mode 100644 index 00000000..937a294a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_custom_tree.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_custom_vector.vcproj b/src/boost/libs/container/proj/vc7ide/doc_custom_vector.vcproj new file mode 100644 index 00000000..8faafca8 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_custom_vector.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_emplace.vcproj b/src/boost/libs/container/proj/vc7ide/doc_emplace.vcproj new file mode 100644 index 00000000..8140b54c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_emplace.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_extended_allocators.vcproj b/src/boost/libs/container/proj/vc7ide/doc_extended_allocators.vcproj new file mode 100644 index 00000000..2ffacc32 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_extended_allocators.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_move_containers.vcproj b/src/boost/libs/container/proj/vc7ide/doc_move_containers.vcproj new file mode 100644 index 00000000..46f4392a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_move_containers.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_pmr.vcproj b/src/boost/libs/container/proj/vc7ide/doc_pmr.vcproj new file mode 100644 index 00000000..ef0a461a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_pmr.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_recursive_containers.vcproj b/src/boost/libs/container/proj/vc7ide/doc_recursive_containers.vcproj new file mode 100644 index 00000000..5874d8d0 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_recursive_containers.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/doc_type_erasure.vcproj b/src/boost/libs/container/proj/vc7ide/doc_type_erasure.vcproj new file mode 100644 index 00000000..6f5d3ae6 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/doc_type_erasure.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_deque_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_deque_test.vcproj new file mode 100644 index 00000000..e1e44d9a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_deque_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_flat_map_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_flat_map_test.vcproj new file mode 100644 index 00000000..a390cefa --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_flat_map_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_flat_set_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_flat_set_test.vcproj new file mode 100644 index 00000000..2af4b870 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_flat_set_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_list_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_list_test.vcproj new file mode 100644 index 00000000..4d24787c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_list_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_map_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_map_test.vcproj new file mode 100644 index 00000000..8da1429f --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_map_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_set_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_set_test.vcproj new file mode 100644 index 00000000..e61403a6 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_set_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_slist_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_slist_test.vcproj new file mode 100644 index 00000000..33f1d3ca --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_slist_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_small_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_small_vector_test.vcproj new file mode 100644 index 00000000..51e9cbfa --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_small_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_stable_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_stable_vector_test.vcproj new file mode 100644 index 00000000..2227f5a5 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_stable_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_static_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_static_vector_test.vcproj new file mode 100644 index 00000000..6b576039 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_static_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_string_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_string_test.vcproj new file mode 100644 index 00000000..46031afe --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_string_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/explicit_inst_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/explicit_inst_vector_test.vcproj new file mode 100644 index 00000000..236b032c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/explicit_inst_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/flat_map_test.vcproj b/src/boost/libs/container/proj/vc7ide/flat_map_test.vcproj new file mode 100644 index 00000000..d7f13f2b --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/flat_map_test.vcproj @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/flat_set_test.vcproj b/src/boost/libs/container/proj/vc7ide/flat_set_test.vcproj new file mode 100644 index 00000000..539399fa --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/flat_set_test.vcproj @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/flat_tree_test.vcproj b/src/boost/libs/container/proj/vc7ide/flat_tree_test.vcproj new file mode 100644 index 00000000..566d6980 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/flat_tree_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/global_resource.vcproj b/src/boost/libs/container/proj/vc7ide/global_resource.vcproj new file mode 100644 index 00000000..bc996f5a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/global_resource.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/hash_table_test.vcproj b/src/boost/libs/container/proj/vc7ide/hash_table_test.vcproj new file mode 100644 index 00000000..fe909777 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/hash_table_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/insert_vs_emplace_test.vcproj b/src/boost/libs/container/proj/vc7ide/insert_vs_emplace_test.vcproj new file mode 100644 index 00000000..320c3b04 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/insert_vs_emplace_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/list_test.vcproj b/src/boost/libs/container/proj/vc7ide/list_test.vcproj new file mode 100644 index 00000000..1aec531c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/list_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/map_test.vcproj b/src/boost/libs/container/proj/vc7ide/map_test.vcproj new file mode 100644 index 00000000..d7023918 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/map_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/memory_resource_test.vcproj b/src/boost/libs/container/proj/vc7ide/memory_resource_test.vcproj new file mode 100644 index 00000000..45b62ac9 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/memory_resource_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/monotonic_buffer_resource_test.vcproj b/src/boost/libs/container/proj/vc7ide/monotonic_buffer_resource_test.vcproj new file mode 100644 index 00000000..8dea90c0 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/monotonic_buffer_resource_test.vcproj @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/node_handle_test.vcproj b/src/boost/libs/container/proj/vc7ide/node_handle_test.vcproj new file mode 100644 index 00000000..48d4f506 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/node_handle_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/null_iterators_test.vcproj b/src/boost/libs/container/proj/vc7ide/null_iterators_test.vcproj new file mode 100644 index 00000000..db5735f6 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/null_iterators_test.vcproj @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pair_test.vcproj b/src/boost/libs/container/proj/vc7ide/pair_test.vcproj new file mode 100644 index 00000000..0b29eb84 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pair_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_deque_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_deque_test.vcproj new file mode 100644 index 00000000..d34a65ce --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_deque_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_flat_map_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_flat_map_test.vcproj new file mode 100644 index 00000000..141eebca --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_flat_map_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_flat_set_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_flat_set_test.vcproj new file mode 100644 index 00000000..a11d96c5 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_flat_set_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_list_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_list_test.vcproj new file mode 100644 index 00000000..a3c93436 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_list_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_map_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_map_test.vcproj new file mode 100644 index 00000000..93120a4f --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_map_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_set_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_set_test.vcproj new file mode 100644 index 00000000..2935011c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_set_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_slist_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_slist_test.vcproj new file mode 100644 index 00000000..c8a2d989 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_slist_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_small_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_small_vector_test.vcproj new file mode 100644 index 00000000..6291009c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_small_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_stable_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_stable_vector_test.vcproj new file mode 100644 index 00000000..56471421 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_stable_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_string_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_string_test.vcproj new file mode 100644 index 00000000..7160fd4a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_string_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/pmr_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/pmr_vector_test.vcproj new file mode 100644 index 00000000..5c5249f1 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/pmr_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/polymorphic_allocator_test.vcproj b/src/boost/libs/container/proj/vc7ide/polymorphic_allocator_test.vcproj new file mode 100644 index 00000000..607cc9e0 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/polymorphic_allocator_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/resource_adaptor.vcproj b/src/boost/libs/container/proj/vc7ide/resource_adaptor.vcproj new file mode 100644 index 00000000..82679cd1 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/resource_adaptor.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/scoped_allocator_adaptor_test.vcproj b/src/boost/libs/container/proj/vc7ide/scoped_allocator_adaptor_test.vcproj new file mode 100644 index 00000000..e3ad785d --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/scoped_allocator_adaptor_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/scoped_allocator_usage_test.vcproj b/src/boost/libs/container/proj/vc7ide/scoped_allocator_usage_test.vcproj new file mode 100644 index 00000000..4faf10f4 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/scoped_allocator_usage_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/set_test.vcproj b/src/boost/libs/container/proj/vc7ide/set_test.vcproj new file mode 100644 index 00000000..98ae093a --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/set_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/slist_test.vcproj b/src/boost/libs/container/proj/vc7ide/slist_test.vcproj new file mode 100644 index 00000000..47c70115 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/slist_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/small_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/small_vector_test.vcproj new file mode 100644 index 00000000..7cb56405 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/small_vector_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/stable_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/stable_vector_test.vcproj new file mode 100644 index 00000000..02cf1764 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/stable_vector_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/static_vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/static_vector_test.vcproj new file mode 100644 index 00000000..2c3dcc92 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/static_vector_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/string_test.vcproj b/src/boost/libs/container/proj/vc7ide/string_test.vcproj new file mode 100644 index 00000000..f70f7565 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/string_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/string_view_compat_test.vcproj b/src/boost/libs/container/proj/vc7ide/string_view_compat_test.vcproj new file mode 100644 index 00000000..42a184be --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/string_view_compat_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/synchronized_pool_resource_test.vcproj b/src/boost/libs/container/proj/vc7ide/synchronized_pool_resource_test.vcproj new file mode 100644 index 00000000..997e2c19 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/synchronized_pool_resource_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/throw_exception_test.vcproj b/src/boost/libs/container/proj/vc7ide/throw_exception_test.vcproj new file mode 100644 index 00000000..8522325c --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/throw_exception_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/tree_test.vcproj b/src/boost/libs/container/proj/vc7ide/tree_test.vcproj new file mode 100644 index 00000000..6f800567 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/tree_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/unsynchronized_pool_resource_test.vcproj b/src/boost/libs/container/proj/vc7ide/unsynchronized_pool_resource_test.vcproj new file mode 100644 index 00000000..a11d7085 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/unsynchronized_pool_resource_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/uses_allocator_test.vcproj b/src/boost/libs/container/proj/vc7ide/uses_allocator_test.vcproj new file mode 100644 index 00000000..92f7094f --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/uses_allocator_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/vector_options_test.vcproj b/src/boost/libs/container/proj/vc7ide/vector_options_test.vcproj new file mode 100644 index 00000000..8d1608f4 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/vector_options_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/proj/vc7ide/vector_test.vcproj b/src/boost/libs/container/proj/vc7ide/vector_test.vcproj new file mode 100644 index 00000000..68e9a835 --- /dev/null +++ b/src/boost/libs/container/proj/vc7ide/vector_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/boost/libs/container/src/alloc_lib.c b/src/boost/libs/container/src/alloc_lib.c new file mode 100644 index 00000000..077768b9 --- /dev/null +++ b/src/boost/libs/container/src/alloc_lib.c @@ -0,0 +1,27 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + + +#define DLMALLOC_VERSION 286 + +#ifndef DLMALLOC_VERSION + #error "DLMALLOC_VERSION undefined" +#endif + +#ifdef __VXWORKS__ +// no sbrk() in VxWorks, configure dlmalloc to use only mmap() +#define HAVE_MORECORE 0 +#endif + +#if DLMALLOC_VERSION == 286 + #include "dlmalloc_ext_2_8_6.c" +#else + #error "Unsupported boost_cont_VERSION version" +#endif diff --git a/src/boost/libs/container/src/dlmalloc.cpp b/src/boost/libs/container/src/dlmalloc.cpp new file mode 100644 index 00000000..6ab6de3a --- /dev/null +++ b/src/boost/libs/container/src/dlmalloc.cpp @@ -0,0 +1,108 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#define BOOST_CONTAINER_SOURCE +#include + +namespace boost{ +namespace container{ + +BOOST_CONTAINER_DECL size_t dlmalloc_size(const void *p) +{ return boost_cont_size(p); } + +BOOST_CONTAINER_DECL void* dlmalloc_malloc(size_t bytes) +{ return boost_cont_malloc(bytes); } + +BOOST_CONTAINER_DECL void dlmalloc_free(void* mem) +{ return boost_cont_free(mem); } + +BOOST_CONTAINER_DECL void* dlmalloc_memalign(size_t bytes, size_t alignment) +{ return boost_cont_memalign(bytes, alignment); } + +BOOST_CONTAINER_DECL int dlmalloc_multialloc_nodes + (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain) +{ return boost_cont_multialloc_nodes(n_elements, elem_size, contiguous_elements, pchain); } + +BOOST_CONTAINER_DECL int dlmalloc_multialloc_arrays + (size_t n_elements, const size_t *sizes, size_t sizeof_element, size_t contiguous_elements, boost_cont_memchain *pchain) +{ return boost_cont_multialloc_arrays(n_elements, sizes, sizeof_element, contiguous_elements, pchain); } + +BOOST_CONTAINER_DECL void dlmalloc_multidealloc(boost_cont_memchain *pchain) +{ return boost_cont_multidealloc(pchain); } + +BOOST_CONTAINER_DECL size_t dlmalloc_footprint() +{ return boost_cont_footprint(); } + +BOOST_CONTAINER_DECL size_t dlmalloc_allocated_memory() +{ return boost_cont_allocated_memory(); } + +BOOST_CONTAINER_DECL size_t dlmalloc_chunksize(const void *p) +{ return boost_cont_chunksize(p); } + +BOOST_CONTAINER_DECL int dlmalloc_all_deallocated() +{ return boost_cont_all_deallocated(); } + +BOOST_CONTAINER_DECL boost_cont_malloc_stats_t dlmalloc_malloc_stats() +{ return boost_cont_malloc_stats(); } + +BOOST_CONTAINER_DECL size_t dlmalloc_in_use_memory() +{ return boost_cont_in_use_memory(); } + +BOOST_CONTAINER_DECL int dlmalloc_trim(size_t pad) +{ return boost_cont_trim(pad); } + +BOOST_CONTAINER_DECL int dlmalloc_mallopt(int parameter_number, int parameter_value) +{ return boost_cont_mallopt(parameter_number, parameter_value); } + +BOOST_CONTAINER_DECL int dlmalloc_grow + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received) +{ return boost_cont_grow(oldmem, minbytes, maxbytes, received); } + +BOOST_CONTAINER_DECL int dlmalloc_shrink + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit) +{ return boost_cont_shrink(oldmem, minbytes, maxbytes, received, do_commit); } + +BOOST_CONTAINER_DECL void* dlmalloc_alloc + (size_t minbytes, size_t preferred_bytes, size_t *received_bytes) +{ return boost_cont_alloc(minbytes, preferred_bytes, received_bytes); } + +BOOST_CONTAINER_DECL int dlmalloc_malloc_check() +{ return boost_cont_malloc_check(); } + +BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command + ( allocation_type command + , size_t sizeof_object + , size_t limit_objects + , size_t preferred_objects + , size_t *received_objects + , void *reuse_ptr + ) +{ return boost_cont_allocation_command(command, sizeof_object, limit_objects, preferred_objects, received_objects, reuse_ptr); } + +BOOST_CONTAINER_DECL void *dlmalloc_sync_create() +{ return boost_cont_sync_create(); } + +BOOST_CONTAINER_DECL void dlmalloc_sync_destroy(void *sync) +{ return boost_cont_sync_destroy(sync); } + +BOOST_CONTAINER_DECL bool dlmalloc_sync_lock(void *sync) +{ return boost_cont_sync_lock(sync) != 0; } + +BOOST_CONTAINER_DECL void dlmalloc_sync_unlock(void *sync) +{ return boost_cont_sync_unlock(sync); } + +BOOST_CONTAINER_DECL bool dlmalloc_global_sync_lock() +{ return boost_cont_global_sync_lock() != 0; } + +BOOST_CONTAINER_DECL void dlmalloc_global_sync_unlock() +{ return boost_cont_global_sync_unlock(); } + +} //namespace container{ +} //namespace boost{ diff --git a/src/boost/libs/container/src/dlmalloc_2_8_6.c b/src/boost/libs/container/src/dlmalloc_2_8_6.c new file mode 100644 index 00000000..7a53d353 --- /dev/null +++ b/src/boost/libs/container/src/dlmalloc_2_8_6.c @@ -0,0 +1,6280 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/publicdomain/zero/1.0/ Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version 2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (minimum) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + It is also possible to limit the maximum total allocatable + space, using malloc_set_footprint_limit. This is not + designed as a security feature in itself (calls to set limits + are not screened or privileged), but may be useful as one + aspect of a secure implementation. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with a lock. By default, this uses a plain + pthread mutex, win32 critical section, or a spin-lock if if + available for the platform and not disabled by setting + USE_SPIN_LOCKS=0. However, if USE_RECURSIVE_LOCKS is defined, + recursive versions are used instead (which are not required for + base functionality but may be needed in layered extensions). + Using a global lock is not especially fast, and can be a major + bottleneck. It is designed only to provide minimal protection + in concurrent environments, and to provide a basis for + extensions. If you are using malloc in a concurrent program, + consider instead using nedmalloc + (http://www.nedprod.com/programs/portable/nedmalloc/) or + ptmalloc (See http://www.malloc.de), which are derived from + versions of this malloc. + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. In real-time + applications, you can optionally suppress segment traversals using + NO_SEGMENT_TRAVERSAL, which assures bounded execution even when + system allocators return non-contiguous spaces, at the typical + expense of carrying around more memory and increased fragmentation. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. Normally, this requires use of locks. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. You can also +use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. Beware that there seem to be some + cases where this malloc might not be a pure drop-in replacement for + Win32 malloc: Random-looking failures from Win32 GDI API's (eg; + SetDIBits()) may be due to bugs in some video driver implementations + when pixel buffers are malloc()ed, and the region spans more than + one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) + default granularity, pixel buffers may straddle virtual allocation + regions more often than when using the Microsoft allocator. You can + avoid this by using VirtualAlloc() and VirtualFree() for all pixel + buffers rather than using malloc(). If this is not possible, + recompile this malloc with a larger DEFAULT_GRANULARITY. Note: + in cases where MSC and gcc (cygwin) are known to differ on WIN32, + conditions use _MSC_VER to distinguish them. + +DLMALLOC_EXPORT default: extern + Defines how public APIs are declared. If you want to export via a + Windows DLL, you might define this as + #define DLMALLOC_EXPORT extern __declspec(dllexport) + If you want a POSIX ELF shared object, you might use + #define DLMALLOC_EXPORT extern __attribute__((visibility("default"))) + +MALLOC_ALIGNMENT default: (size_t)(2 * sizeof(void *)) + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) If set to a + non-zero value other than 1, locks are used, but their + implementation is left out, so lock functions must be supplied manually, + as described below. + +USE_SPIN_LOCKS default: 1 iff USE_LOCKS and spin locks available + If true, uses custom spin locks for locking. This is currently + supported only gcc >= 4.1, older gccs on x86 platforms, and recent + MS compilers. Otherwise, posix locks or win32 critical sections are + used. + +USE_RECURSIVE_LOCKS default: not defined + If defined nonzero, uses recursive (aka reentrant) locks, otherwise + uses plain mutexes. This is not required for malloc proper, but may + be needed for layered allocators such as nedmalloc. + +LOCK_AT_FORK default: not defined + If defined nonzero, performs pthread_atfork upon initialization + to initialize child lock while holding parent lock. The implementation + assumes that pthread locks (not custom locks) are being used. In other + cases, you may need to customize the implementation. + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +MALLOC_INSPECT_ALL default: NOT defined + If defined, compiles malloc_inspect_all and mspace_inspect_all, that + perform traversal of all heap space. Unless access to these + functions is otherwise restricted, you probably do not want to + include them in secure implementations. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. + +MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +NO_SEGMENT_TRAVERSAL default: 0 + If non-zero, suppresses traversals of memory segments + returned by either MORECORE or CALL_MMAP. This disables + merging of segments that are contiguous, and selectively + releasing them to the OS if unused, but bounds execution times. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 except on WINCE. + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero and on WIN32 except for WINCE. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. Similarly for Win32 under recent MS compilers. + (On most x86s, the asm version is only slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +NO_MALLOC_STATS default: 0 + If defined, don't compile "malloc_stats". This avoids calls to + fprintf and bringing in stdio dependencies you might not want. + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP + The number of consolidated frees between checks to release + unused segments when freeing. When using non-contiguous segments, + especially with multiple mspaces, checking only for topmost space + doesn't always suffice to trigger trimming. To compensate for this, + free() will, with a period of MAX_RELEASE_CHECK_RATE (or the + current number of segments, if greater) try to release unused + segments to the OS when freeing chunks that result in + consolidation. The best value for this parameter is a compromise + between slowing down frees with relatively costly checks that + rarely trigger versus holding on to unused memory. To effectively + disable, set to MAX_SIZE_T. This may lead to a very slight speed + improvement at the expense of carrying around more memory. +*/ + +/* Version identifier to allow people to support multiple versions */ +#ifndef DLMALLOC_VERSION +#define DLMALLOC_VERSION 20806 +#endif /* DLMALLOC_VERSION */ + +#ifndef DLMALLOC_EXPORT +#define DLMALLOC_EXPORT extern +#endif + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#ifdef _WIN32_WCE +#define LACKS_FCNTL_H +#define WIN32 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define LACKS_SCHED_H +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef MMAP_CLEARS +#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ +#define MMAP_CLEARS 0 +#else +#define MMAP_CLEARS 1 +#endif /* _WIN32_WCE */ +#endif /*MMAP_CLEARS */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +/* OSX allocators provide 16 byte alignment */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)16U) +#endif +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */ +#define USE_LOCKS ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \ + (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0)) +#endif /* USE_LOCKS */ + +#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */ +#if ((defined(__GNUC__) && \ + ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && _MSC_VER>=1310)) +#ifndef USE_SPIN_LOCKS +#define USE_SPIN_LOCKS 1 +#endif /* USE_SPIN_LOCKS */ +#elif USE_SPIN_LOCKS +#error "USE_SPIN_LOCKS defined without implementation" +#endif /* ... locks available... */ +#elif !defined(USE_SPIN_LOCKS) +#define USE_SPIN_LOCKS 0 +#endif /* USE_LOCKS */ + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *))) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ + +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef MALLOC_INSPECT_ALL +#define MALLOC_INSPECT_ALL 0 +#endif /* MALLOC_INSPECT_ALL */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#define _GNU_SOURCE /* Turns on mremap() definition */ +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#define MORECORE_DEFAULT sbrk +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if (MORECORE_CONTIGUOUS || defined(WIN32)) +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef MAX_RELEASE_CHECK_RATE +#if HAVE_MMAP +#define MAX_RELEASE_CHECK_RATE 4095 +#else +#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* MAX_RELEASE_CHECK_RATE */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ +#ifndef NO_MALLOC_STATS +#define NO_MALLOC_STATS 0 +#endif /* NO_MALLOC_STATS */ +#ifndef NO_SEGMENT_TRAVERSAL +#define NO_SEGMENT_TRAVERSAL 0 +#endif /* NO_SEGMENT_TRAVERSAL */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ +#ifndef STRUCT_MALLINFO_DECLARED +/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */ +#define _STRUCT_MALLINFO +#define STRUCT_MALLINFO_DECLARED 1 +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; +#endif /* STRUCT_MALLINFO_DECLARED */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +/* + Try to persuade compilers to inline. The most critical functions for + inlining are defined as macros, so these aren't used for them. +*/ + +#ifndef FORCEINLINE + #if defined(__GNUC__) +#define FORCEINLINE __inline __attribute__ ((always_inline)) + #elif defined(_MSC_VER) + #define FORCEINLINE __forceinline + #endif +#endif +#ifndef NOINLINE + #if defined(__GNUC__) + #define NOINLINE __attribute__ ((noinline)) + #elif defined(_MSC_VER) + #define NOINLINE __declspec(noinline) + #else + #define NOINLINE + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#ifndef FORCEINLINE + #define FORCEINLINE inline +#endif +#endif /* __cplusplus */ +#ifndef FORCEINLINE + #define FORCEINLINE +#endif + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlposix_memalign posix_memalign +#define dlrealloc realloc +#define dlrealloc_in_place realloc_in_place +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlmalloc_footprint_limit malloc_footprint_limit +#define dlmalloc_set_footprint_limit malloc_set_footprint_limit +#define dlmalloc_inspect_all malloc_inspect_all +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#define dlbulk_free bulk_free +#endif /* USE_DL_PREFIX */ + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +DLMALLOC_EXPORT void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +DLMALLOC_EXPORT void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +DLMALLOC_EXPORT void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ +DLMALLOC_EXPORT void* dlrealloc(void*, size_t); + +/* + realloc_in_place(void* p, size_t n) + Resizes the space allocated for p to size n, only if this can be + done without moving p (i.e., only if there is adjacent space + available if n is greater than p's current allocated size, or n is + less than or equal to p's size). This may be used instead of plain + realloc if an alternative allocation strategy is needed upon failure + to expand space; for example, reallocation of a buffer that must be + memory-aligned or cleared. You can use realloc_in_place to trigger + these alternatives only when needed. + + Returns p if successful; otherwise null. +*/ +DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +DLMALLOC_EXPORT void* dlmemalign(size_t, size_t); + +/* + int posix_memalign(void** pp, size_t alignment, size_t n); + Allocates a chunk of n bytes, aligned in accord with the alignment + argument. Differs from memalign only in that it (1) assigns the + allocated memory to *pp rather than returning it, (2) fails and + returns EINVAL if the alignment is not a power of two (3) fails and + returns ENOMEM if memory cannot be allocated. +*/ +DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +DLMALLOC_EXPORT void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. To workaround the fact that mallopt is specified to use int, + not size_t parameters, the value -1 is specially treated as the + maximum unsigned size_t value. + + SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +DLMALLOC_EXPORT int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +DLMALLOC_EXPORT size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void); + +/* + malloc_footprint_limit(); + Returns the number of bytes that the heap is allowed to obtain from + the system, returning the last value returned by + malloc_set_footprint_limit, or the maximum size_t value if + never set. The returned value reflects a permission. There is no + guarantee that this number of bytes can actually be obtained from + the system. +*/ +DLMALLOC_EXPORT size_t dlmalloc_footprint_limit(); + +/* + malloc_set_footprint_limit(); + Sets the maximum number of bytes to obtain from the system, causing + failure returns from malloc and related functions upon attempts to + exceed this value. The argument value may be subject to page + rounding to an enforceable limit; this actual value is returned. + Using an argument of the maximum possible size_t effectively + disables checks. If the argument is less than or equal to the + current malloc_footprint, then all future allocations that require + additional system memory will fail. However, invocation cannot + retroactively deallocate existing used memory. +*/ +DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes); + +#if MALLOC_INSPECT_ALL +/* + malloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg); + Traverses the heap and calls the given handler for each managed + region, skipping all bytes that are (or may be) used for bookkeeping + purposes. Traversal does not include include chunks that have been + directly memory mapped. Each reported region begins at the start + address, and continues up to but not including the end address. The + first used_bytes of the region contain allocated data. If + used_bytes is zero, the region is unallocated. The handler is + invoked with the given callback argument. If locks are defined, they + are held during the entire traversal. It is a bad idea to invoke + other malloc functions from within the handler. + + For example, to count the number of in-use chunks with size greater + than 1000, you could write: + static int count = 0; + void count_chunks(void* start, void* end, size_t used, void* arg) { + if (used >= 1000) ++count; + } + then: + malloc_inspect_all(count_chunks, NULL); + + malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined. +*/ +DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), + void* arg); + +#endif /* MALLOC_INSPECT_ALL */ + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be freed when it is no longer needed. This can be + done all at once using bulk_free. + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be freed when it is no longer needed. This can be + done all at once using bulk_free. + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**); + +/* + bulk_free(void* array[], size_t n_elements) + Frees and clears (sets to null) each non-null pointer in the given + array. This is likely to be faster than freeing them one-by-one. + If footers are used, pointers that have been allocated in different + mspaces are not freed or cleared, and the count of all such pointers + is returned. For large arrays of pointers with poor locality, it + may be worthwhile to sort this array before calling bulk_free. +*/ +DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements); + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +DLMALLOC_EXPORT void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +DLMALLOC_EXPORT int dlmalloc_trim(size_t); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +DLMALLOC_EXPORT void dlmalloc_stats(void); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + +#endif /* ONLY_MSPACES */ + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +DLMALLOC_EXPORT size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_track_large_chunks controls whether requests for large chunks + are allocated in their own untracked mmapped regions, separate from + others in this mspace. By default large chunks are not tracked, + which reduces fragmentation. However, such chunks are not + necessarily released to the system upon destroy_mspace. Enabling + tracking by setting to true may increase fragmentation, but avoids + leakage when relying on destroy_mspace to release all memory + allocated using this space. The function returns the previous + setting. +*/ +DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable); + + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +DLMALLOC_EXPORT size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + malloc_usable_size(void* p) behaves the same as malloc_usable_size; +*/ +DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem); + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +DLMALLOC_EXPORT int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef _MSC_VER +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* _MSC_VER */ +#if !NO_MALLOC_STATS +#include /* for printing in malloc_stats */ +#endif /* NO_MALLOC_STATS */ +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#undef assert +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#ifndef assert +#define assert(x) +#endif +#define DEBUG 0 +#endif /* DEBUG */ +#if !defined(WIN32) && !defined(LACKS_TIME_H) +#include /* for magic initialization */ +#endif /* WIN32 */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ +#if (defined(linux) && !defined(__USE_GNU)) +#define __USE_GNU 1 +#include /* for mmap */ +#undef __USE_GNU +#else +#include /* for mmap */ +#endif /* linux */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#ifndef LACKS_UNISTD_H +#include /* for sbrk, sysconf */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ + +/* Declarations for locking */ +#if USE_LOCKS +#ifndef WIN32 +#if defined (__SVR4) && defined (__sun) /* solaris */ +#include +#elif !defined(LACKS_SCHED_H) +#include +#endif /* solaris or LACKS_SCHED_H */ +#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS +#include +#endif /* USE_RECURSIVE_LOCKS ... */ +#elif defined(_MSC_VER) +#ifndef _M_AMD64 +/* These are already defined on AMD64 builds */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); +LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _M_AMD64 */ +#pragma intrinsic (_InterlockedCompareExchange) +#pragma intrinsic (_InterlockedExchange) +#define interlockedcompareexchange _InterlockedCompareExchange +#define interlockedexchange _InterlockedExchange +#elif defined(WIN32) && defined(__GNUC__) +#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) +#define interlockedexchange __sync_lock_test_and_set +#endif /* Win32 */ +#else /* USE_LOCKS */ +#endif /* USE_LOCKS */ + +#ifndef LOCK_AT_FORK +#define LOCK_AT_FORK 0 +#endif + +/* Declarations for bit scanning on win32 */ +#if defined(_MSC_VER) && _MSC_VER>=1300 +#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) +#endif /* BitScanForward */ +#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some platforms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define SIZE_T_FOUR ((size_t)4) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if HAVE_MMAP + +#ifndef WIN32 +#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static FORCEINLINE void* win32mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static FORCEINLINE void* win32direct_mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static FORCEINLINE int win32munmap(void* ptr, size_t size) { + MEMORY_BASIC_INFORMATION minfo; + char* cptr = (char*)ptr; + while (size) { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + return 0; +} + +#define MMAP_DEFAULT(s) win32mmap(s) +#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MREMAP +#ifndef WIN32 +#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#endif /* WIN32 */ +#endif /* HAVE_MREMAP */ + +/** + * Define CALL_MORECORE + */ +#if HAVE_MORECORE + #ifdef MORECORE + #define CALL_MORECORE(S) MORECORE(S) + #else /* MORECORE */ + #define CALL_MORECORE(S) MORECORE_DEFAULT(S) + #endif /* MORECORE */ +#else /* HAVE_MORECORE */ + #define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/** + * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP + */ +#if HAVE_MMAP + #define USE_MMAP_BIT (SIZE_T_ONE) + + #ifdef MMAP + #define CALL_MMAP(s) MMAP(s) + #else /* MMAP */ + #define CALL_MMAP(s) MMAP_DEFAULT(s) + #endif /* MMAP */ + #ifdef MUNMAP + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) + #else /* MUNMAP */ + #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) + #endif /* MUNMAP */ + #ifdef DIRECT_MMAP + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #else /* DIRECT_MMAP */ + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) + #endif /* DIRECT_MMAP */ +#else /* HAVE_MMAP */ + #define USE_MMAP_BIT (SIZE_T_ZERO) + + #define MMAP(s) MFAIL + #define MUNMAP(a, s) (-1) + #define DIRECT_MMAP(s) MFAIL + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #define CALL_MMAP(s) MMAP(s) + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#endif /* HAVE_MMAP */ + +/** + * Define CALL_MREMAP + */ +#if HAVE_MMAP && HAVE_MREMAP + #ifdef MREMAP + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) + #else /* MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) + #endif /* MREMAP */ +#else /* HAVE_MMAP && HAVE_MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +/* mstate bit set if contiguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +/* + When locks are defined, there is one global lock, plus + one per-mspace lock. + + The global lock_ensures that mparams.magic and other unique + mparams values are initialized only once. It also protects + sequences of calls to MORECORE. In many cases sys_alloc requires + two calls, that should not be interleaved with calls by other + threads. This does not protect against direct calls to MORECORE + by other threads not using this lock, so there is still code to + cope the best we can on interference. + + Per-mspace locks surround calls to malloc, free, etc. + By default, locks are simple non-reentrant mutexes. + + Because lock-protected regions generally have bounded times, it is + OK to use the supplied simple spinlocks. Spinlocks are likely to + improve performance for lightly contended applications, but worsen + performance under heavy contention. + + If USE_LOCKS is > 1, the definitions of lock routines here are + bypassed, in which case you will need to define the type MLOCK_T, + and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK + and TRY_LOCK. You must also declare a + static MLOCK_T malloc_global_mutex = { initialization values };. + +*/ + +#if !USE_LOCKS +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) (0) +#define DESTROY_LOCK(l) (0) +#define ACQUIRE_MALLOC_GLOBAL_LOCK() +#define RELEASE_MALLOC_GLOBAL_LOCK() + +#else +#if USE_LOCKS > 1 +/* ----------------------- User-defined locks ------------------------ */ +/* Define your own lock implementation here */ +/* #define INITIAL_LOCK(lk) ... */ +/* #define DESTROY_LOCK(lk) ... */ +/* #define ACQUIRE_LOCK(lk) ... */ +/* #define RELEASE_LOCK(lk) ... */ +/* #define TRY_LOCK(lk) ... */ +/* static MLOCK_T malloc_global_mutex = ... */ + +#elif USE_SPIN_LOCKS + +/* First, define CAS_LOCK and CLEAR_LOCK on ints */ +/* Note CAS_LOCK defined to return 0 on success */ + +#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) +#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) +#define CLEAR_LOCK(sl) __sync_lock_release(sl) + +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) +/* Custom spin locks for older gcc on x86 */ +static FORCEINLINE int x86_cas_lock(int *sl) { + int ret; + int val = 1; + int cmp = 0; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(sl)), "0"(cmp) + : "memory", "cc"); + return ret; +} + +static FORCEINLINE void x86_clear_lock(int* sl) { + assert(*sl != 0); + int prev = 0; + int ret; + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(sl)), "0"(prev) + : "memory"); +} + +#define CAS_LOCK(sl) x86_cas_lock(sl) +#define CLEAR_LOCK(sl) x86_clear_lock(sl) + +#else /* Win32 MSC */ +#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1) +#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0) + +#endif /* ... gcc spins locks ... */ + +/* How to yield for a spin lock */ +#define SPINS_PER_YIELD 63 +#if defined(_MSC_VER) +#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ +#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) +#elif defined (__SVR4) && defined (__sun) /* solaris */ +#define SPIN_LOCK_YIELD thr_yield(); +#elif !defined(LACKS_SCHED_H) +#define SPIN_LOCK_YIELD sched_yield(); +#else +#define SPIN_LOCK_YIELD +#endif /* ... yield ... */ + +#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0 +/* Plain spin locks use single word (embedded in malloc_states) */ +static int spin_acquire_lock(int *sl) { + int spins = 0; + while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) { + if ((++spins & SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } + } + return 0; +} + +#define MLOCK_T int +#define TRY_LOCK(sl) !CAS_LOCK(sl) +#define RELEASE_LOCK(sl) CLEAR_LOCK(sl) +#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0) +#define INITIAL_LOCK(sl) (*sl = 0) +#define DESTROY_LOCK(sl) (0) +static MLOCK_T malloc_global_mutex = 0; + +#else /* USE_RECURSIVE_LOCKS */ +/* types for lock owners */ +#ifdef WIN32 +#define THREAD_ID_T DWORD +#define CURRENT_THREAD GetCurrentThreadId() +#define EQ_OWNER(X,Y) ((X) == (Y)) +#else +/* + Note: the following assume that pthread_t is a type that can be + initialized to (casted) zero. If this is not the case, you will need to + somehow redefine these or not use spin locks. +*/ +#define THREAD_ID_T pthread_t +#define CURRENT_THREAD pthread_self() +#define EQ_OWNER(X,Y) pthread_equal(X, Y) +#endif + +struct malloc_recursive_lock { + int sl; + unsigned int c; + THREAD_ID_T threadid; +}; + +#define MLOCK_T struct malloc_recursive_lock +static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0}; + +static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) { + assert(lk->sl != 0); + if (--lk->c == 0) { + CLEAR_LOCK(&lk->sl); + } +} + +static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) { + THREAD_ID_T mythreadid = CURRENT_THREAD; + int spins = 0; + for (;;) { + if (*((volatile int *)(&lk->sl)) == 0) { + if (!CAS_LOCK(&lk->sl)) { + lk->threadid = mythreadid; + lk->c = 1; + return 0; + } + } + else if (EQ_OWNER(lk->threadid, mythreadid)) { + ++lk->c; + return 0; + } + if ((++spins & SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } + } +} + +static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) { + THREAD_ID_T mythreadid = CURRENT_THREAD; + if (*((volatile int *)(&lk->sl)) == 0) { + if (!CAS_LOCK(&lk->sl)) { + lk->threadid = mythreadid; + lk->c = 1; + return 1; + } + } + else if (EQ_OWNER(lk->threadid, mythreadid)) { + ++lk->c; + return 1; + } + return 0; +} + +#define RELEASE_LOCK(lk) recursive_release_lock(lk) +#define TRY_LOCK(lk) recursive_try_lock(lk) +#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk) +#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0) +#define DESTROY_LOCK(lk) (0) +#endif /* USE_RECURSIVE_LOCKS */ + +#elif defined(WIN32) /* Win32 critical sections */ +#define MLOCK_T CRITICAL_SECTION +#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0) +#define RELEASE_LOCK(lk) LeaveCriticalSection(lk) +#define TRY_LOCK(lk) TryEnterCriticalSection(lk) +#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000)) +#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0) +#define NEED_GLOBAL_LOCK_INIT + +static MLOCK_T malloc_global_mutex; +static volatile LONG malloc_global_mutex_status; + +/* Use spin loop to initialize global lock */ +static void init_malloc_global_mutex() { + for (;;) { + long stat = malloc_global_mutex_status; + if (stat > 0) + return; + /* transition to < 0 while initializing, then to > 0) */ + if (stat == 0 && + interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) { + InitializeCriticalSection(&malloc_global_mutex); + interlockedexchange(&malloc_global_mutex_status, (LONG)1); + return; + } + SleepEx(0, FALSE); + } +} + +#else /* pthreads-based locks */ +#define MLOCK_T pthread_mutex_t +#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk) +#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk) +#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk)) +#define INITIAL_LOCK(lk) pthread_init_lock(lk) +#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk) + +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE) +/* Cope with old-style linux recursive lock initialization by adding */ +/* skipped internal declaration from pthread.h */ +extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr, + int __kind)); +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) +#endif /* USE_RECURSIVE_LOCKS ... */ + +static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int pthread_init_lock (MLOCK_T *lk) { + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) return 1; +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1; +#endif + if (pthread_mutex_init(lk, &attr)) return 1; + if (pthread_mutexattr_destroy(&attr)) return 1; + return 0; +} + +#endif /* ... lock types ... */ + +/* Common code for all lock types */ +#define USE_LOCK_BIT (2U) + +#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK +#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); +#endif + +#ifndef RELEASE_MALLOC_GLOBAL_LOCK +#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); +#endif + +#endif /* USE_LOCKS */ + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 0) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse (unless the chunk is mmapped). This redundancy enables usage + checks within free and realloc, and reduces indirection when freeing + and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, have both cinuse and pinuse bits + cleared in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use, unless mmapped, in which case both bits are cleared. + + FLAG4_BIT is not used by this malloc, but might be useful in extensions. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define FLAG4_BIT (SIZE_T_FOUR) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) +#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define flag4inuse(p) ((p)->head & FLAG4_BIT) +#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) +#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) + +#define chunksize(p) ((p)->head & ~(FLAG_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define set_flag4(p) ((p)->head |= FLAG4_BIT) +#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If USE_MMAP_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Max allowed footprint + The maximum allowed bytes to allocate from system (zero means no limit) + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Trim support + Fields holding the amount of unused topmost memory that should trigger + trimming, and a counter to force periodic scanning to release unused + non-topmost segments. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. + + Extension support + A void* pointer and a size_t field that can be used to help implement + extensions to this malloc. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t release_checks; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + size_t footprint_limit; /* zero means no limit */ + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; + void* extp; /* Unused but available for extensions */ + size_t exts; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. Note that the non-zeroness of "magic" + also serves as an initialization flag. +*/ + +struct malloc_params { + size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* Ensure mparams initialized */ +#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams()) + +#if !ONLY_MSPACES + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) + +#endif /* !ONLY_MSPACES */ + +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#if USE_LOCKS +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) +#else +#define disable_lock(M) +#endif + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#if HAVE_MMAP +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) +#else +#define disable_mmap(M) +#endif + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity - SIZE_T_ONE))\ + & ~(mparams.granularity - SIZE_T_ONE)) + + +/* For mmap, use granularity alignment on windows, else page-align */ +#ifdef WIN32 +#define mmap_align(S) granularity_align(S) +#else +#define mmap_align(S) page_align(S) +#endif + +/* For sys_alloc, enough padding to ensure can malloc request on success */ +#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS +#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I. Use x86 asm if possible */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_tree_index(S, I)\ +{\ + unsigned int X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = _bit_scan_reverse (X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + _BitScanReverse((DWORD *) &K, (DWORD) X);\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + +/* index corresponding to given bit. Use x86 asm if possible */ + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = __builtin_ctz(X); \ + I = (bindex_t)J;\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = _bit_scan_forward (X); \ + I = (bindex_t)J;\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + _BitScanForward((DWORD *) &J, X);\ + I = (bindex_t)J;\ +} + +#elif USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* GNUC */ + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probabalistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has inuse status */ +#define ok_inuse(p) is_inuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_inuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Macros for setting head/foot of non-mmapped chunks */ + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +#if LOCK_AT_FORK +static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); } +static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); } +static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } +#endif /* LOCK_AT_FORK */ + +/* Initialize mparams */ +static int init_mparams(void) { +#ifdef NEED_GLOBAL_LOCK_INIT + if (malloc_global_mutex_status <= 0) + init_malloc_global_mutex(); +#endif + + ACQUIRE_MALLOC_GLOBAL_LOCK(); + if (mparams.magic == 0) { + size_t magic; + size_t psize; + size_t gsize; + +#ifndef WIN32 + psize = malloc_getpagesize; + gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + psize = system_info.dwPageSize; + gsize = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((gsize & (gsize-SIZE_T_ONE)) != 0) || + ((psize & (psize-SIZE_T_ONE)) != 0)) + ABORT; + mparams.granularity = gsize; + mparams.page_size = psize; + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if !ONLY_MSPACES + /* Set up lock for main malloc area */ + gm->mflags = mparams.default_mflags; + (void)INITIAL_LOCK(&gm->mutex); +#endif +#if LOCK_AT_FORK + pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); +#endif + + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + magic = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ +#ifdef WIN32 + magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); +#elif defined(LACKS_TIME_H) + magic = (size_t)&magic ^ (size_t)0x55555555U; +#else + magic = (size_t)(time(0) ^ (size_t)0x55555555U); +#endif + magic |= (size_t)8U; /* ensure nonzero */ + magic &= ~(size_t)7U; /* improve chances of fault for bad values */ + /* Until memory modes commonly available, use volatile-write */ + (*(volatile size_t *)(&(mparams.magic))) = magic; + } + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val; + ensure_initialization(); + val = (value == -1)? MAX_SIZE_T : (size_t)value; + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) { + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) { + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!pinuse(chunk_plus_offset(p, sz))); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) { + do_check_any_chunk(m, p); + assert(is_inuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!is_inuse(p)); + assert(!next_pinuse(p)); + assert (!is_mmapped(p)); + if (p != m->dv && p != m->top) { + if (sz >= MIN_CHUNK_SIZE) { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert (next == m->top || is_inuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + assert(sz == SIZE_T_SIZE); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~INUSE_BITS; + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) { + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); + + do { /* traverse through chain of same-sized nodes */ + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!is_inuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + if (u->parent == 0) { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); + if (u->child[0] != 0) { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + if (u->child[1] != 0) { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + if (u->child[0] != 0 && u->child[1] != 0) { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + u = u->fd; + } while (u != t); + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) { + tbinptr* tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) { + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + if (p == b) + assert(empty); + if (!empty) { + for (; p != b; p = p->bk) { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) { + size_t size = chunksize(x); + if (is_small(size)) { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + if (smallmap_is_marked(m, sidx)) { + mchunkptr p = b; + do { + if (p == x) + return 1; + } while ((p = p->fd) != b); + } + } + else { + bindex_t tidx; + compute_tree_index(size, tidx); + if (treemap_is_marked(m, tidx)) { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + while (t != 0 && chunksize(t) != size) { + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) { + tchunkptr u = t; + do { + if (u == (tchunkptr)x) + return 1; + } while ((u = u->fd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) { + size_t sum = 0; + if (is_initialized(m)) { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + sum += chunksize(q); + if (is_inuse(q)) { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + lastq = q; + q = next_chunk(q); + } + s = s->next; + } + } + return sum; +} + + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) { + bindex_t i; + size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + do_check_smallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + do_check_treebin(m, i); + + if (m->dvsize != 0) { /* check dv chunk */ + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) { /* check top chunk */ + do_check_top_chunk(m, m->top); + /*assert(m->topsize == chunksize(m->top)); redundant */ + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + ensure_initialization(); + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!is_inuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + return nm; +} +#endif /* !NO_MALLINFO */ + +#if !NO_MALLOC_STATS +static void internal_malloc_stats(mstate m) { + ensure_initialization(); + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!is_inuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + POSTACTION(m); /* drop lock */ + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + } +} +#endif /* NO_MALLOC_STATS */ + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(B == smallbin_at(M,I) ||\ + (ok_address(M, B) && B->fd == P))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + assert(is_small(DVS));\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + ((m == gm)? dlmalloc(b) : mspace_malloc(m, b)) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (m->footprint_limit != 0) { + size_t fp = m->footprint + mmsize; + if (fp <= m->footprint || fp > m->footprint_limit) + return 0; + } + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(CALL_DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset; + p->head = psize; + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (m->least_addr == 0 || mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { + size_t oldsize = chunksize(oldp); + (void)flags; /* placate people compiling -Wunused */ + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, flags); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = psize; + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallmap = m->treemap = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!is_inuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + size_t asize; /* allocation size */ + + ensure_initialization(); + + /* Directly map large chunks, but only if already initialized */ + if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + asize = granularity_align(nb + SYS_ALLOC_PADDING); + if (asize <= nb) + return 0; /* wraparound */ + if (m->footprint_limit != 0) { + size_t fp = m->footprint + asize; + if (fp <= m->footprint || fp > m->footprint_limit) + return 0; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + + In all cases, we need to request enough bytes from system to ensure + we can malloc nb bytes upon success, so pad with enough space for + top_foot, plus alignment-pad to make sure we don't lose bytes if + not on boundary, and round this up to a granularity unit. + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + size_t ssize = asize; /* sbrk call size */ + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + ACQUIRE_MALLOC_GLOBAL_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + size_t fp; + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + ssize += (page_align((size_t)base) - (size_t)base); + fp = m->footprint + ssize; /* recheck limits */ + if (ssize > nb && ssize < HALF_MAX_SIZE_T && + (m->footprint_limit == 0 || + (fp > m->footprint && fp <= m->footprint_limit)) && + (br = (char*)(CALL_MORECORE(ssize))) == base) { + tbase = base; + tsize = ssize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); + /* Use mem here only if it did continuously extend old space */ + if (ssize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) { + tbase = br; + tsize = ssize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (ssize < HALF_MAX_SIZE_T && + ssize < nb + SYS_ALLOC_PADDING) { + size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + ssize += esize; + else { /* Can't use; try to release */ + (void) CALL_MORECORE(-ssize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = ssize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + char* mp = (char*)(CALL_MMAP(asize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = asize; + mmap_flag = USE_MMAP_BIT; + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MALLOC_GLOBAL_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + if (m->least_addr == 0 || tbase < m->least_addr) + m->least_addr = tbase; + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + init_bins(m); +#if !ONLY_MSPACES + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else +#endif + { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + /* Only consider most recent segment if traversal suppressed */ + while (sp != 0 && tbase != sp->base + sp->size) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & USE_MMAP_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & USE_MMAP_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + int nsegs = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + ++nsegs; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + break; + pred = sp; + sp = next; + } + /* Reset check counter */ + m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)? + (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE); + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + ensure_initialization(); + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + (void)newsize; /* placate people compiling -Wunused-variable */ + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MALLOC_GLOBAL_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0 && m->topsize > m->trim_check) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + +/* Consolidate and bin a chunk. Differs from exported versions + of free mainly in that the chunk need not be marked as inuse. +*/ +static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + mchunkptr prev; + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + m->footprint -= psize; + return; + } + prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */ + if (p != m->dv) { + unlink_chunk(m, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + m->dvsize = psize; + set_free_with_pinuse(p, psize, next); + return; + } + } + else { + CORRUPTION_ERROR_ACTION(m); + return; + } + } + if (RTCHECK(ok_address(m, next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == m->top) { + size_t tsize = m->topsize += psize; + m->top = p; + p->head = tsize | PINUSE_BIT; + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + return; + } + else if (next == m->dv) { + size_t dsize = m->dvsize += psize; + m->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + return; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(m, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == m->dv) { + m->dvsize = psize; + return; + } + } + } + else { + set_free_with_pinuse(p, psize, next); + } + insert_chunk(m, p, psize); + } + else { + CORRUPTION_ERROR_ACTION(m); + } +} + +/* ---------------------------- malloc --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + +#if USE_LOCKS + ensure_initialization(); /* initialize in sys_alloc if not using locks */ +#endif + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +/* ---------------------------- free --------------------------- */ + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +#endif /* !ONLY_MSPACES */ + +/* ------------ Internal support for realloc, memalign, etc -------------- */ + +/* Try to realloc; only in-place unless can_move true */ +static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, + int can_move) { + mchunkptr newp = 0; + size_t oldsize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, oldsize); + if (RTCHECK(ok_address(m, p) && ok_inuse(p) && + ok_next(p, next) && ok_pinuse(next))) { + if (is_mmapped(p)) { + newp = mmap_resize(m, p, nb, can_move); + } + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + newp = p; + } + else if (next == m->top) { /* extend into top */ + if (oldsize + m->topsize > nb) { + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = p; + } + } + else if (next == m->dv) { /* extend into dv */ + size_t dvs = m->dvsize; + if (oldsize + dvs >= nb) { + size_t dsize = oldsize + dvs - nb; + if (dsize >= MIN_CHUNK_SIZE) { + mchunkptr r = chunk_plus_offset(p, nb); + mchunkptr n = chunk_plus_offset(r, dsize); + set_inuse(m, p, nb); + set_size_and_pinuse_of_free_chunk(r, dsize); + clear_pinuse(n); + m->dvsize = dsize; + m->dv = r; + } + else { /* exhaust dv */ + size_t newsize = oldsize + dvs; + set_inuse(m, p, newsize); + m->dvsize = 0; + m->dv = 0; + } + newp = p; + } + } + else if (!cinuse(next)) { /* extend into next free chunk */ + size_t nextsize = chunksize(next); + if (oldsize + nextsize >= nb) { + size_t rsize = oldsize + nextsize - nb; + unlink_chunk(m, next, nextsize); + if (rsize < MIN_CHUNK_SIZE) { + size_t newsize = oldsize + nextsize; + set_inuse(m, p, newsize); + } + else { + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + newp = p; + } + } + } + else { + USAGE_ERROR_ACTION(m, chunk2mem(p)); + } + return newp; +} + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + void* mem = 0; + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + mem = internal_malloc(m, req); + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (PREACTION(m)) + return 0; + if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = newsize; + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + dispose_chunk(m, p, leadsize); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + dispose_chunk(m, remainder, remainder_size); + } + } + + mem = chunk2mem(p); + assert (chunksize(p) >= nb); + assert(((size_t)mem & (alignment - 1)) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + } + } + return mem; +} + +/* + Common support for independent_X routines, handling + all of the combinations that can result. + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed +*/ +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + ensure_initialization(); + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + +/* Try to free all pointers in the given array. + Note: this could be made faster, by delaying consolidation, + at the price of disabling some user integrity checks, We + still optimize some consolidations by combining adjacent + chunks before freeing, which will occur often if allocated + with ialloc or the array is sorted. +*/ +static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) { + size_t unfreed = 0; + if (!PREACTION(m)) { + void** a; + void** fence = &(array[nelem]); + for (a = array; a != fence; ++a) { + void* mem = *a; + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t psize = chunksize(p); +#if FOOTERS + if (get_mstate_for(p) != m) { + ++unfreed; + continue; + } +#endif + check_inuse_chunk(m, p); + *a = 0; + if (RTCHECK(ok_address(m, p) && ok_inuse(p))) { + void ** b = a + 1; /* try to merge with next chunk */ + mchunkptr next = next_chunk(p); + if (b != fence && *b == chunk2mem(next)) { + size_t newsize = chunksize(next) + psize; + set_inuse(m, p, newsize); + *b = chunk2mem(p); + } + else + dispose_chunk(m, p, psize); + } + else { + CORRUPTION_ERROR_ACTION(m); + break; + } + } + } + if (should_trim(m, m->topsize)) + sys_trim(m, 0); + POSTACTION(m); + } + return unfreed; +} + +/* Traversal */ +#if MALLOC_INSPECT_ALL +static void internal_inspect_all(mstate m, + void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { + if (is_initialized(m)) { + mchunkptr top = m->top; + msegmentptr s; + for (s = &m->seg; s != 0; s = s->next) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) { + mchunkptr next = next_chunk(q); + size_t sz = chunksize(q); + size_t used; + void* start; + if (is_inuse(q)) { + used = sz - CHUNK_OVERHEAD; /* must not be mmapped */ + start = chunk2mem(q); + } + else { + used = 0; + if (is_small(sz)) { /* offset by possible bookkeeping */ + start = (void*)((char*)q + sizeof(struct malloc_chunk)); + } + else { + start = (void*)((char*)q + sizeof(struct malloc_tree_chunk)); + } + } + if (start < (void*)next) /* skip if all space is bookkeeping */ + handler(start, next, used, arg); + if (q == top) + break; + q = next; + } + } + } +} +#endif /* MALLOC_INSPECT_ALL */ + +/* ------------------ Exported realloc, memalign, etc -------------------- */ + +#if !ONLY_MSPACES + +void* dlrealloc(void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem == 0) { + mem = dlmalloc(bytes); + } + else if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } +#ifdef REALLOC_ZERO_BYTES_FREES + else if (bytes == 0) { + dlfree(oldmem); + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + if (newp != 0) { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } + else { + mem = internal_malloc(m, bytes); + if (mem != 0) { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + } + } + } + return mem; +} + +void* dlrealloc_in_place(void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem != 0) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); + POSTACTION(m); + if (newp == oldp) { + check_inuse_chunk(m, newp); + mem = oldmem; + } + } + } + } + return mem; +} + +void* dlmemalign(size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) { + return dlmalloc(bytes); + } + return internal_memalign(gm, alignment, bytes); +} + +int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { + void* mem = 0; + if (alignment == MALLOC_ALIGNMENT) + mem = dlmalloc(bytes); + else { + size_t d = alignment / sizeof(void*); + size_t r = alignment % sizeof(void*); + if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0) + return EINVAL; + else if (bytes <= MAX_REQUEST - alignment) { + if (alignment < MIN_CHUNK_SIZE) + alignment = MIN_CHUNK_SIZE; + mem = internal_memalign(gm, alignment, bytes); + } + } + if (mem == 0) + return ENOMEM; + else { + *pp = mem; + return 0; + } +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +size_t dlbulk_free(void* array[], size_t nelem) { + return internal_bulk_free(gm, array, nelem); +} + +#if MALLOC_INSPECT_ALL +void dlmalloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { + ensure_initialization(); + if (!PREACTION(gm)) { + internal_inspect_all(gm, handler, arg); + POSTACTION(gm); + } +} +#endif /* MALLOC_INSPECT_ALL */ + +int dlmalloc_trim(size_t pad) { + int result = 0; + ensure_initialization(); + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +size_t dlmalloc_footprint_limit(void) { + size_t maf = gm->footprint_limit; + return maf == 0 ? MAX_SIZE_T : maf; +} + +size_t dlmalloc_set_footprint_limit(size_t bytes) { + size_t result; /* invert sense of 0 */ + if (bytes == 0) + result = granularity_align(1); /* Use minimal size */ + if (bytes == MAX_SIZE_T) + result = 0; /* disable */ + else + result = granularity_align(bytes); + return gm->footprint_limit = result; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +#if !NO_MALLOC_STATS +void dlmalloc_stats() { + internal_malloc_stats(gm); +} +#endif /* NO_MALLOC_STATS */ + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (is_inuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +#endif /* !ONLY_MSPACES */ + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + (void)INITIAL_LOCK(&m->mutex); + msp->head = (msize|INUSE_BITS); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + m->mflags = mparams.default_mflags; + m->extp = 0; + m->exts = 0; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char* tbase = (char*)(CALL_MMAP(tsize)); + if (tbase != CMFAIL) { + m = init_user_mstate(tbase, tsize); + m->seg.sflags = USE_MMAP_BIT; + set_lock(m, locked); + } + } + return (mspace)m; +} + +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); + m->seg.sflags = EXTERN_BIT; + set_lock(m, locked); + } + return (mspace)m; +} + +int mspace_track_large_chunks(mspace msp, int enable) { + int ret = 0; + mstate ms = (mstate)msp; + if (!PREACTION(ms)) { + if (!use_mmap(ms)) { + ret = 1; + } + if (!enable) { + enable_mmap(ms); + } else { + disable_mmap(ms); + } + POSTACTION(ms); + } + return ret; +} + +size_t destroy_mspace(mspace msp) { + size_t freed = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + msegmentptr sp = &ms->seg; + (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */ + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + flag_t flag = sp->sflags; + (void)base; /* placate people compiling -Wunused-variable */ + sp = sp->next; + if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + freed += size; + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + +void* mspace_malloc(mspace msp, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + (void)msp; /* placate people compiling -Wunused */ +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +} + +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = internal_malloc(ms, req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem == 0) { + mem = mspace_malloc(msp, bytes); + } + else if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } +#ifdef REALLOC_ZERO_BYTES_FREES + else if (bytes == 0) { + mspace_free(msp, oldmem); + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = (mstate)msp; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + if (newp != 0) { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } + else { + mem = mspace_malloc(m, bytes); + if (mem != 0) { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes)? oc : bytes); + mspace_free(m, oldmem); + } + } + } + } + return mem; +} + +void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) { + void* mem = 0; + if (oldmem != 0) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + } + else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = (mstate)msp; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + (void)msp; /* placate people compiling -Wunused */ + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); + POSTACTION(m); + if (newp == oldp) { + check_inuse_chunk(m, newp); + mem = oldmem; + } + } + } + } + return mem; +} + +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (alignment <= MALLOC_ALIGNMENT) + return mspace_malloc(msp, bytes); + return internal_memalign(ms, alignment, bytes); +} + +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) { + return internal_bulk_free((mstate)msp, array, nelem); +} + +#if MALLOC_INSPECT_ALL +void mspace_inspect_all(mspace msp, + void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + internal_inspect_all(ms, handler, arg); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} +#endif /* MALLOC_INSPECT_ALL */ + +int mspace_trim(mspace msp, size_t pad) { + int result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +#if !NO_MALLOC_STATS +void mspace_malloc_stats(mspace msp) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + internal_malloc_stats(ms); + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} +#endif /* NO_MALLOC_STATS */ + +size_t mspace_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +size_t mspace_max_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->max_footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +size_t mspace_footprint_limit(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + size_t maf = ms->footprint_limit; + result = (maf == 0) ? MAX_SIZE_T : maf; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +size_t mspace_set_footprint_limit(mspace msp, size_t bytes) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (bytes == 0) + result = granularity_align(1); /* Use minimal size */ + if (bytes == MAX_SIZE_T) + result = 0; /* disable */ + else + result = granularity_align(bytes); + ms->footprint_limit = result; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +size_t mspace_usable_size(const void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (is_inuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int mspace_mallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea + * fix bad comparison in dlposix_memalign + * don't reuse adjusted asize in sys_alloc + * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion + * reduce compiler warnings -- thanks to all who reported/suggested these + + v2.8.5 Sun May 22 10:26:02 2011 Doug Lea (dl at gee) + * Always perform unlink checks unless INSECURE + * Add posix_memalign. + * Improve realloc to expand in more cases; expose realloc_in_place. + Thanks to Peter Buhr for the suggestion. + * Add footprint_limit, inspect_all, bulk_free. Thanks + to Barry Hayes and others for the suggestions. + * Internal refactorings to avoid calls while holding locks + * Use non-reentrant locks by default. Thanks to Roland McGrath + for the suggestion. + * Small fixes to mspace_destroy, reset_on_error. + * Various configuration extensions/changes. Thanks + to all who contributed these. + + V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu) + * Update Creative Commons URL + + V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee) + * Use zeros instead of prev foot for is_mmapped + * Add mspace_track_large_chunks; thanks to Jean Brouwers + * Fix set_inuse in internal_realloc; thanks to Jean Brouwers + * Fix insufficient sys_alloc padding when using 16byte alignment + * Fix bad error check in mspace_footprint + * Adaptations for ptmalloc; thanks to Wolfram Gloger. + * Reentrant spin locks; thanks to Earl Chew and others + * Win32 improvements; thanks to Niall Douglas and Earl Chew + * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options + * Extension hook in malloc_state + * Various small adjustments to reduce warnings on some compilers + * Various configuration extensions/changes for more platforms. Thanks + to all who contributed these. + + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occurring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/src/boost/libs/container/src/dlmalloc_ext_2_8_6.c b/src/boost/libs/container/src/dlmalloc_ext_2_8_6.c new file mode 100644 index 00000000..918ce020 --- /dev/null +++ b/src/boost/libs/container/src/dlmalloc_ext_2_8_6.c @@ -0,0 +1,1484 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +#include "errno.h" //dlmalloc bug EINVAL is used in posix_memalign without checking LACKS_ERRNO_H +#include "limits.h" //CHAR_BIT +#ifdef BOOST_CONTAINER_DLMALLOC_FOOTERS +#define FOOTERS 1 +#endif +#define USE_LOCKS 1 +#define MSPACES 1 +#define NO_MALLINFO 1 +#define NO_MALLOC_STATS 1 +//disable sbrk as it's deprecated in some systems and weakens ASLR +#define HAVE_MORECORE 0 + + +#if !defined(NDEBUG) + #if !defined(DEBUG) + #define DEBUG 1 + #define DL_DEBUG_DEFINED + #endif +#endif + +#define USE_DL_PREFIX + +#ifdef __GNUC__ +#define FORCEINLINE inline +#endif +#include "dlmalloc_2_8_6.c" + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4127) +#pragma warning (disable : 4267) +#pragma warning (disable : 4127) +#pragma warning (disable : 4702) +#pragma warning (disable : 4390) /*empty controlled statement found; is this the intent?*/ +#pragma warning (disable : 4251 4231 4660) /*dll warnings*/ +#endif + +#define DL_SIZE_IMPL(p) (chunksize(mem2chunk(p)) - overhead_for(mem2chunk(p))) + +static size_t s_allocated_memory; + +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +// +// SLIGHTLY MODIFIED DLMALLOC FUNCTIONS +// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// + +//This function is equal to mspace_free +//replacing PREACTION with 0 and POSTACTION with nothing +static void mspace_free_lockless(mspace msp, void* mem) +{ + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + msp = msp; /* placate people compiling -Wunused */ +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!0){//PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if (is_mmapped(p)) { + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + ;//POSTACTION(fm); + } + } +} + +//This function is equal to mspace_malloc +//replacing PREACTION with 0 and POSTACTION with nothing +void* mspace_malloc_lockless(mspace msp, size_t bytes) +{ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!0){//PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + ;//POSTACTION(ms); + return mem; + } + + return 0; +} + +//This function is equal to try_realloc_chunk but handling +//minimum and desired bytes +static mchunkptr try_realloc_chunk_with_min(mstate m, mchunkptr p, size_t min_nb, size_t des_nb, int can_move) +{ + mchunkptr newp = 0; + size_t oldsize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, oldsize); + if (RTCHECK(ok_address(m, p) && ok_inuse(p) && + ok_next(p, next) && ok_pinuse(next))) { + if (is_mmapped(p)) { + newp = mmap_resize(m, p, des_nb, can_move); + if(!newp) //mmap does not return how many bytes we could reallocate, so go the minimum + newp = mmap_resize(m, p, min_nb, can_move); + } + else if (oldsize >= min_nb) { /* already big enough */ + size_t nb = oldsize >= des_nb ? des_nb : oldsize; + size_t rsize = oldsize - nb; + if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + newp = p; + } + else if (next == m->top) { /* extend into top */ + if (oldsize + m->topsize > min_nb) { + size_t nb = (oldsize + m->topsize) > des_nb ? des_nb : (oldsize + m->topsize - MALLOC_ALIGNMENT); + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = p; + } + } + else if (next == m->dv) { /* extend into dv */ + size_t dvs = m->dvsize; + if (oldsize + dvs >= min_nb) { + size_t nb = (oldsize + dvs) >= des_nb ? des_nb : (oldsize + dvs); + size_t dsize = oldsize + dvs - nb; + if (dsize >= MIN_CHUNK_SIZE) { + mchunkptr r = chunk_plus_offset(p, nb); + mchunkptr n = chunk_plus_offset(r, dsize); + set_inuse(m, p, nb); + set_size_and_pinuse_of_free_chunk(r, dsize); + clear_pinuse(n); + m->dvsize = dsize; + m->dv = r; + } + else { /* exhaust dv */ + size_t newsize = oldsize + dvs; + set_inuse(m, p, newsize); + m->dvsize = 0; + m->dv = 0; + } + newp = p; + } + } + else if (!cinuse(next)) { /* extend into next free chunk */ + size_t nextsize = chunksize(next); + if (oldsize + nextsize >= min_nb) { + size_t nb = (oldsize + nextsize) >= des_nb ? des_nb : (oldsize + nextsize); + size_t rsize = oldsize + nextsize - nb; + unlink_chunk(m, next, nextsize); + if (rsize < MIN_CHUNK_SIZE) { + size_t newsize = oldsize + nextsize; + set_inuse(m, p, newsize); + } + else { + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + newp = p; + } + } + } + else { + USAGE_ERROR_ACTION(m, chunk2mem(p)); + } + return newp; +} + +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +// +// NEW FUNCTIONS BASED ON DLMALLOC INTERNALS +// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// + +#define GET_TRUNCATED_SIZE(ORIG_SIZE, ROUNDTO) ((ORIG_SIZE)/(ROUNDTO)*(ROUNDTO)) +#define GET_ROUNDED_SIZE(ORIG_SIZE, ROUNDTO) ((((ORIG_SIZE)-1)/(ROUNDTO)+1)*(ROUNDTO)) +#define GET_TRUNCATED_PO2_SIZE(ORIG_SIZE, ROUNDTO) ((ORIG_SIZE) & (~(ROUNDTO-1))) +#define GET_ROUNDED_PO2_SIZE(ORIG_SIZE, ROUNDTO) (((ORIG_SIZE - 1) & (~(ROUNDTO-1))) + ROUNDTO) + +/* Greatest common divisor and least common multiple + gcd is an algorithm that calculates the greatest common divisor of two + integers, using Euclid's algorithm. + + Pre: A > 0 && B > 0 + Recommended: A > B*/ +#define CALCULATE_GCD(A, B, OUT)\ +{\ + size_t a = A;\ + size_t b = B;\ + do\ + {\ + size_t tmp = b;\ + b = a % b;\ + a = tmp;\ + } while (b != 0);\ +\ + OUT = a;\ +} + +/* lcm is an algorithm that calculates the least common multiple of two + integers. + + Pre: A > 0 && B > 0 + Recommended: A > B*/ +#define CALCULATE_LCM(A, B, OUT)\ +{\ + CALCULATE_GCD(A, B, OUT);\ + OUT = (A / OUT)*B;\ +} + +static int calculate_lcm_and_needs_backwards_lcmed + (size_t backwards_multiple, size_t received_size, size_t size_to_achieve, + size_t *plcm, size_t *pneeds_backwards_lcmed) +{ + /* Now calculate lcm */ + size_t max = backwards_multiple; + size_t min = MALLOC_ALIGNMENT; + size_t needs_backwards; + size_t needs_backwards_lcmed; + size_t lcm; + size_t current_forward; + /*Swap if necessary*/ + if(max < min){ + size_t tmp = min; + min = max; + max = tmp; + } + /*Check if it's power of two*/ + if((backwards_multiple & (backwards_multiple-1)) == 0){ + if(0 != (size_to_achieve & ((backwards_multiple-1)))){ + USAGE_ERROR_ACTION(m, oldp); + return 0; + } + + lcm = max; + /*If we want to use minbytes data to get a buffer between maxbytes + and minbytes if maxbytes can't be achieved, calculate the + biggest of all possibilities*/ + current_forward = GET_TRUNCATED_PO2_SIZE(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = GET_ROUNDED_PO2_SIZE(needs_backwards, lcm); + *plcm = lcm; + *pneeds_backwards_lcmed = needs_backwards_lcmed; + return 1; + } + /*Check if it's multiple of alignment*/ + else if((backwards_multiple & (MALLOC_ALIGNMENT - 1u)) == 0){ + lcm = backwards_multiple; + current_forward = GET_TRUNCATED_SIZE(received_size, backwards_multiple); + //No need to round needs_backwards because backwards_multiple == lcm + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards_lcmed & (MALLOC_ALIGNMENT - 1u)) == 0); + *plcm = lcm; + *pneeds_backwards_lcmed = needs_backwards_lcmed; + return 1; + } + /*Check if it's multiple of the half of the alignmment*/ + else if((backwards_multiple & ((MALLOC_ALIGNMENT/2u) - 1u)) == 0){ + lcm = backwards_multiple*2u; + current_forward = GET_TRUNCATED_SIZE(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + if(0 != (needs_backwards_lcmed & (MALLOC_ALIGNMENT-1))) + //while(0 != (needs_backwards_lcmed & (MALLOC_ALIGNMENT-1))) + needs_backwards_lcmed += backwards_multiple; + assert((needs_backwards_lcmed % lcm) == 0); + *plcm = lcm; + *pneeds_backwards_lcmed = needs_backwards_lcmed; + return 1; + } + /*Check if it's multiple of the quarter of the alignmment*/ + else if((backwards_multiple & ((MALLOC_ALIGNMENT/4u) - 1u)) == 0){ + size_t remainder; + lcm = backwards_multiple*4u; + current_forward = GET_TRUNCATED_SIZE(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + //while(0 != (needs_backwards_lcmed & (MALLOC_ALIGNMENT-1))) + //needs_backwards_lcmed += backwards_multiple; + if(0 != (remainder = ((needs_backwards_lcmed & (MALLOC_ALIGNMENT-1))>>(MALLOC_ALIGNMENT/8u)))){ + if(backwards_multiple & MALLOC_ALIGNMENT/2u){ + needs_backwards_lcmed += (remainder)*backwards_multiple; + } + else{ + needs_backwards_lcmed += (4-remainder)*backwards_multiple; + } + } + assert((needs_backwards_lcmed % lcm) == 0); + *plcm = lcm; + *pneeds_backwards_lcmed = needs_backwards_lcmed; + return 1; + } + else{ + CALCULATE_LCM(max, min, lcm); + /*If we want to use minbytes data to get a buffer between maxbytes + and minbytes if maxbytes can't be achieved, calculate the + biggest of all possibilities*/ + current_forward = GET_TRUNCATED_SIZE(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = GET_ROUNDED_SIZE(needs_backwards, lcm); + *plcm = lcm; + *pneeds_backwards_lcmed = needs_backwards_lcmed; + return 1; + } +} + +static void *internal_grow_both_sides + (mstate m + ,allocation_type command + ,void *oldmem + ,size_t minbytes + ,size_t maxbytes + ,size_t *received_size + ,size_t backwards_multiple + ,int only_preferred_backwards) +{ + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + *received_size = oldsize - overhead_for(oldp); + if(minbytes <= *received_size) + return oldmem; + + if (RTCHECK(ok_address(m, oldp) && ok_inuse(oldp))) { + if(command & BOOST_CONTAINER_EXPAND_FWD){ + if(try_realloc_chunk_with_min(m, oldp, request2size(minbytes), request2size(maxbytes), 0)){ + check_inuse_chunk(m, oldp); + *received_size = DL_SIZE_IMPL(oldmem); + s_allocated_memory += chunksize(oldp) - oldsize; + return oldmem; + } + } + else{ + *received_size = DL_SIZE_IMPL(oldmem); + if(*received_size >= maxbytes) + return oldmem; + } +/* + Should we check this? + if(backwards_multiple && + (0 != (minbytes % backwards_multiple) && + 0 != (maxbytes % backwards_multiple)) ){ + USAGE_ERROR_ACTION(m, oldp); + return 0; + } +*/ + /* We reach here only if forward expansion fails */ + if(!(command & BOOST_CONTAINER_EXPAND_BWD) || pinuse(oldp)){ + return 0; + } + { + size_t prevsize = oldp->prev_foot; + if ((prevsize & USE_MMAP_BIT) != 0){ + /*Return failure the previous chunk was mmapped. + mremap does not allow expanding to a fixed address (MREMAP_MAYMOVE) without + copying (MREMAP_MAYMOVE must be also set).*/ + return 0; + } + else { + mchunkptr prev = chunk_minus_offset(oldp, prevsize); + size_t dsize = oldsize + prevsize; + size_t needs_backwards_lcmed; + size_t lcm; + + /* Let's calculate the number of extra bytes of data before the current + block's begin. The value is a multiple of backwards_multiple + and the alignment*/ + if(!calculate_lcm_and_needs_backwards_lcmed + ( backwards_multiple, *received_size + , only_preferred_backwards ? maxbytes : minbytes + , &lcm, &needs_backwards_lcmed) + || !RTCHECK(ok_address(m, prev))){ + USAGE_ERROR_ACTION(m, oldp); + return 0; + } + /* Check if previous block has enough size */ + else if(prevsize < needs_backwards_lcmed){ + /* preferred size? */ + return 0; + } + /* Now take all next space. This must succeed, as we've previously calculated the correct size */ + if(command & BOOST_CONTAINER_EXPAND_FWD){ + if(!try_realloc_chunk_with_min(m, oldp, request2size(*received_size), request2size(*received_size), 0)){ + assert(0); + } + check_inuse_chunk(m, oldp); + *received_size = DL_SIZE_IMPL(oldmem); + s_allocated_memory += chunksize(oldp) - oldsize; + oldsize = chunksize(oldp); + dsize = oldsize + prevsize; + } + /* We need a minimum size to split the previous one */ + if(prevsize >= (needs_backwards_lcmed + MIN_CHUNK_SIZE)){ + mchunkptr r = chunk_minus_offset(oldp, needs_backwards_lcmed); + size_t rsize = oldsize + needs_backwards_lcmed; + size_t newprevsize = dsize - rsize; + int prev_was_dv = prev == m->dv; + + assert(newprevsize >= MIN_CHUNK_SIZE); + + if (prev_was_dv) { + m->dvsize = newprevsize; + } + else{/* if ((next->head & INUSE_BITS) == INUSE_BITS) { */ + unlink_chunk(m, prev, prevsize); + insert_chunk(m, prev, newprevsize); + } + + set_size_and_pinuse_of_free_chunk(prev, newprevsize); + clear_pinuse(r); + set_inuse(m, r, rsize); + check_malloced_chunk(m, chunk2mem(r), rsize); + *received_size = chunksize(r) - overhead_for(r); + s_allocated_memory += chunksize(r) - oldsize; + return chunk2mem(r); + } + /* Check if there is no place to create a new block and + the whole new block is multiple of the backwards expansion multiple */ + else if(prevsize >= needs_backwards_lcmed && !(prevsize % lcm)) { + /* Just merge the whole previous block */ + /* prevsize is multiple of lcm (and backwards_multiple)*/ + *received_size += prevsize; + + if (prev != m->dv) { + unlink_chunk(m, prev, prevsize); + } + else{ + m->dvsize = 0; + m->dv = 0; + } + set_inuse(m, prev, dsize); + check_malloced_chunk(m, chunk2mem(prev), dsize); + s_allocated_memory += chunksize(prev) - oldsize; + return chunk2mem(prev); + } + else{ + /* Previous block was big enough but there is no room + to create an empty block and taking the whole block does + not fulfill alignment requirements */ + return 0; + } + } + } + } + else{ + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } + return 0; +} + +/* This is similar to mmap_resize but: + * Only to shrink + * It takes min and max sizes + * Takes additional 'do_commit' argument to obtain the final + size before doing the real shrink operation. +*/ +static int internal_mmap_shrink_in_place(mstate m, mchunkptr oldp, size_t nbmin, size_t nbmax, size_t *received_size, int do_commit) +{ + size_t oldsize = chunksize(oldp); + *received_size = oldsize; + #if HAVE_MREMAP + if (is_small(nbmax)) /* Can't shrink mmap regions below small size */ + return 0; + { + size_t effective_min = nbmin > MIN_LARGE_SIZE ? nbmin : MIN_LARGE_SIZE; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= effective_min + SIZE_T_SIZE && + (oldsize - effective_min) <= (mparams.granularity << 1)) + return 0; + /* Now calculate new sizes */ + { + size_t offset = oldp->prev_foot; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(effective_min + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + *received_size = newmmsize; + if(!do_commit){ + const int flags = 0; /* placate people compiling -Wunused */ + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, flags); + /*This must always succeed */ + if(!cp){ + USAGE_ERROR_ACTION(m, m); + return 0; + } + { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = psize; + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + } + } + } + return 1; + } + #else //#if HAVE_MREMAP + (void)m; + (void)oldp; + (void)nbmin; + (void)nbmax; + (void)received_size; + (void)do_commit; + return 0; + #endif //#if HAVE_MREMAP +} + +static int internal_shrink(mstate m, void* oldmem, size_t minbytes, size_t maxbytes, size_t *received_size, int do_commit) +{ + *received_size = chunksize(mem2chunk(oldmem)) - overhead_for(mem2chunk(oldmem)); + if (minbytes >= MAX_REQUEST || maxbytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + return 0; + } + else if(minbytes < MIN_REQUEST){ + minbytes = MIN_REQUEST; + } + if (minbytes > maxbytes) { + return 0; + } + + { + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + mchunkptr next = chunk_plus_offset(oldp, oldsize); + void* extra = 0; + + /* Try to either shrink or extend into top. Else malloc-copy-free*/ + if (RTCHECK(ok_address(m, oldp) && ok_inuse(oldp) && + ok_next(oldp, next) && ok_pinuse(next))) { + size_t nbmin = request2size(minbytes); + size_t nbmax = request2size(maxbytes); + + if (nbmin > oldsize){ + /* Return error if old size is too small */ + } + else if (is_mmapped(oldp)){ + return internal_mmap_shrink_in_place(m, oldp, nbmin, nbmax, received_size, do_commit); + } + else{ // nbmin <= oldsize /* already big enough*/ + size_t nb = nbmin; + size_t rsize = oldsize - nb; + if (rsize >= MIN_CHUNK_SIZE) { + if(do_commit){ + mchunkptr remainder = chunk_plus_offset(oldp, nb); + set_inuse(m, oldp, nb); + set_inuse(m, remainder, rsize); + s_allocated_memory -= rsize; + extra = chunk2mem(remainder); + mspace_free_lockless(m, extra); + check_inuse_chunk(m, oldp); + } + *received_size = nb - overhead_for(oldp); + return 1; + } + } + } + else { + USAGE_ERROR_ACTION(m, oldmem); + } + return 0; + } +} + +#define INTERNAL_MULTIALLOC_DEFAULT_CONTIGUOUS_MEM 4096 +#define SQRT_MAX_SIZE_T (((size_t)-1)>>(sizeof(size_t)*CHAR_BIT/2)) + +static int internal_node_multialloc +(mstate m, size_t n_elements, size_t element_size, size_t contiguous_elements, boost_cont_memchain *pchain) { + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + flag_t was_enabled; /* to disable mmap */ + size_t elements_per_segment = 0; + size_t element_req_size = request2size(element_size); + boost_cont_memchain_it prev_last_it = BOOST_CONTAINER_MEMCHAIN_LAST_IT(pchain); + + /*Error if wrong element_size parameter */ + if (!element_size || + /*OR Error if n_elements less than contiguous_elements */ + ((contiguous_elements + 1) > (DL_MULTIALLOC_DEFAULT_CONTIGUOUS + 1) && n_elements < contiguous_elements) || + /* OR Error if integer overflow */ + (SQRT_MAX_SIZE_T < (element_req_size | contiguous_elements) && + (MAX_SIZE_T / element_req_size) < contiguous_elements)) { + return 0; + } + switch (contiguous_elements) { + case DL_MULTIALLOC_DEFAULT_CONTIGUOUS: + { + /* Default contiguous, just check that we can store at least one element */ + elements_per_segment = INTERNAL_MULTIALLOC_DEFAULT_CONTIGUOUS_MEM / element_req_size; + elements_per_segment += (size_t)(!elements_per_segment); + } + break; + case DL_MULTIALLOC_ALL_CONTIGUOUS: + /* All elements should be allocated in a single call */ + elements_per_segment = n_elements; + break; + default: + /* Allocate in chunks of "contiguous_elements" */ + elements_per_segment = contiguous_elements; + } + + { + size_t i; + size_t next_i; + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + for (i = 0; i != n_elements; i = next_i) + { + size_t accum_size; + size_t n_elements_left = n_elements - i; + next_i = i + ((n_elements_left < elements_per_segment) ? n_elements_left : elements_per_segment); + accum_size = element_req_size * (next_i - i); + + mem = mspace_malloc_lockless(m, accum_size - CHUNK_OVERHEAD); + if (mem == 0) { + BOOST_CONTAINER_MEMIT_NEXT(prev_last_it); + while (i) { + void *addr = BOOST_CONTAINER_MEMIT_ADDR(prev_last_it); + --i; + BOOST_CONTAINER_MEMIT_NEXT(prev_last_it); + s_allocated_memory -= chunksize(mem2chunk(addr)); + mspace_free_lockless(m, addr); + } + if (was_enabled) + enable_mmap(m); + return 0; + } + p = mem2chunk(mem); + remainder_size = chunksize(p); + s_allocated_memory += remainder_size; + + assert(!is_mmapped(p)); + { /* split out elements */ + //void *mem_orig = mem; + //boost_cont_memchain_it last_it = BOOST_CONTAINER_MEMCHAIN_LAST_IT(pchain); + size_t num_elements = next_i - i; + + size_t num_loops = num_elements - 1; + remainder_size -= element_req_size * num_loops; + while (num_loops) { + --num_loops; + //void **mem_prev = ((void**)mem); + set_size_and_pinuse_of_inuse_chunk(m, p, element_req_size); + BOOST_CONTAINER_MEMCHAIN_PUSH_BACK(pchain, mem); + p = chunk_plus_offset(p, element_req_size); + mem = chunk2mem(p); + //*mem_prev = mem; + } + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + BOOST_CONTAINER_MEMCHAIN_PUSH_BACK(pchain, mem); + //BOOST_CONTAINER_MEMCHAIN_INCORPORATE_AFTER(pchain, last_it, mem_orig, mem, num_elements); + } + } + if (was_enabled) + enable_mmap(m); + } + return 1; +} + +#define BOOST_CONTAINER_DLMALLOC_SIMPLE_MULTIDEALLOC +#ifndef BOOST_CONTAINER_DLMALLOC_SIMPLE_MULTIDEALLOC + +#define BOOST_ALLOC_PLUS_MEMCHAIN_MEM_JUMP_NEXT(THISMEM, NEXTMEM) \ + *((void**)(THISMEM)) = *((void**)((NEXTMEM))) + +//This function is based on internal_bulk_free +//replacing iteration over array[] with boost_cont_memchain. +//Instead of returning the unallocated nodes, returns a chain of non-deallocated nodes. +//After forward merging, backwards merging is also tried +static void internal_multialloc_free(mstate m, boost_cont_memchain *pchain) +{ +#if FOOTERS + boost_cont_memchain ret_chain; + BOOST_CONTAINER_MEMCHAIN_INIT(&ret_chain); +#endif + if (!PREACTION(m)) { + boost_cont_memchain_it a_it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(pchain); + while (!BOOST_CONTAINER_MEMCHAIN_IS_END_IT(pchain, a_it)) { /* Iterate though all memory holded by the chain */ + void* a_mem = BOOST_CONTAINER_MEMIT_ADDR(a_it); + mchunkptr a_p = mem2chunk(a_mem); + size_t psize = chunksize(a_p); +#if FOOTERS + if (get_mstate_for(a_p) != m) { + BOOST_CONTAINER_MEMIT_NEXT(a_it); + BOOST_CONTAINER_MEMCHAIN_PUSH_BACK(&ret_chain, a_mem); + continue; + } +#endif + check_inuse_chunk(m, a_p); + if (RTCHECK(ok_address(m, a_p) && ok_inuse(a_p))) { + while (1) { /* Internal loop to speed up forward and backward merging (avoids some redundant checks) */ + boost_cont_memchain_it b_it = a_it; + BOOST_CONTAINER_MEMIT_NEXT(b_it); + if (!BOOST_CONTAINER_MEMCHAIN_IS_END_IT(pchain, b_it)) { + void *b_mem = BOOST_CONTAINER_MEMIT_ADDR(b_it); + mchunkptr b_p = mem2chunk(b_mem); + if (b_p == next_chunk(a_p)) { /* b chunk is contiguous and next so b's size can be added to a */ + psize += chunksize(b_p); + set_inuse(m, a_p, psize); + BOOST_ALLOC_PLUS_MEMCHAIN_MEM_JUMP_NEXT(a_mem, b_mem); + continue; + } + if (RTCHECK(ok_address(m, b_p) && ok_inuse(b_p))) { + /* b chunk is contiguous and previous so a's size can be added to b */ + if (a_p == next_chunk(b_p)) { + psize += chunksize(b_p); + set_inuse(m, b_p, psize); + a_it = b_it; + a_p = b_p; + a_mem = b_mem; + continue; + } + } + } + /* Normal deallocation starts again in the outer loop */ + a_it = b_it; + s_allocated_memory -= psize; + dispose_chunk(m, a_p, psize); + break; + } + } + else { + CORRUPTION_ERROR_ACTION(m); + break; + } + } + if (should_trim(m, m->topsize)) + sys_trim(m, 0); + POSTACTION(m); + } +#if FOOTERS + { + boost_cont_memchain_it last_pchain = BOOST_CONTAINER_MEMCHAIN_LAST_IT(pchain); + BOOST_CONTAINER_MEMCHAIN_INIT(pchain); + BOOST_CONTAINER_MEMCHAIN_INCORPORATE_AFTER + (pchain + , last_pchain + , BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ret_chain) + , BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ret_chain) + , BOOST_CONTAINER_MEMCHAIN_SIZE(&ret_chain) + ); + } +#endif +} + +#else //BOOST_CONTAINER_DLMALLOC_SIMPLE_MULTIDEALLOC + +//This function is based on internal_bulk_free +//replacing iteration over array[] with boost_cont_memchain. +//Instead of returning the unallocated nodes, returns a chain of non-deallocated nodes. +//After forward merging, backwards merging is also tried +static void internal_multialloc_free(mstate m, boost_cont_memchain *pchain) +{ + if (!PREACTION(m)) { + boost_cont_memchain_it a_it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(pchain); + while (!BOOST_CONTAINER_MEMCHAIN_IS_END_IT(pchain, a_it)) { /* Iterate though all memory holded by the chain */ + void* a_mem = BOOST_CONTAINER_MEMIT_ADDR(a_it); + BOOST_CONTAINER_MEMIT_NEXT(a_it); + s_allocated_memory -= chunksize(mem2chunk(a_mem)); + mspace_free_lockless(m, a_mem); + } + POSTACTION(m); + } +} + +#endif //BOOST_CONTAINER_DLMALLOC_SIMPLE_MULTIDEALLOC + +static int internal_multialloc_arrays + (mstate m, size_t n_elements, const size_t* sizes, size_t element_size, size_t contiguous_elements, boost_cont_memchain *pchain) { + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t boost_cont_multialloc_segmented_malloc_size; + size_t max_size; + + /* Check overflow */ + if(!element_size){ + return 0; + } + max_size = MAX_REQUEST/element_size; + /* Different sizes*/ + switch(contiguous_elements){ + case DL_MULTIALLOC_DEFAULT_CONTIGUOUS: + /* Use default contiguous mem */ + boost_cont_multialloc_segmented_malloc_size = INTERNAL_MULTIALLOC_DEFAULT_CONTIGUOUS_MEM; + break; + case DL_MULTIALLOC_ALL_CONTIGUOUS: + boost_cont_multialloc_segmented_malloc_size = MAX_REQUEST + CHUNK_OVERHEAD; + break; + default: + if(max_size < contiguous_elements){ + return 0; + } + else{ + /* The suggested buffer is just the the element count by the size */ + boost_cont_multialloc_segmented_malloc_size = element_size*contiguous_elements; + } + } + + { + size_t i; + size_t next_i; + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + for(i = 0, next_i = 0; i != n_elements; i = next_i) + { + int error = 0; + size_t accum_size; + for(accum_size = 0; next_i != n_elements; ++next_i){ + size_t cur_array_size = sizes[next_i]; + if(max_size < cur_array_size){ + error = 1; + break; + } + else{ + size_t reqsize = request2size(cur_array_size*element_size); + if(((boost_cont_multialloc_segmented_malloc_size - CHUNK_OVERHEAD) - accum_size) < reqsize){ + if(!accum_size){ + accum_size += reqsize; + ++next_i; + } + break; + } + accum_size += reqsize; + } + } + + mem = error ? 0 : mspace_malloc_lockless(m, accum_size - CHUNK_OVERHEAD); + if (mem == 0){ + boost_cont_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(pchain); + while(i--){ + void *addr = BOOST_CONTAINER_MEMIT_ADDR(it); + BOOST_CONTAINER_MEMIT_NEXT(it); + s_allocated_memory -= chunksize(mem2chunk(addr)); + mspace_free_lockless(m, addr); + } + if (was_enabled) + enable_mmap(m); + return 0; + } + p = mem2chunk(mem); + remainder_size = chunksize(p); + s_allocated_memory += remainder_size; + + assert(!is_mmapped(p)); + + { /* split out elements */ + void *mem_orig = mem; + boost_cont_memchain_it last_it = BOOST_CONTAINER_MEMCHAIN_LAST_IT(pchain); + size_t num_elements = next_i-i; + + for(++i; i != next_i; ++i) { + void **mem_prev = ((void**)mem); + size = request2size(sizes[i]*element_size); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + mem = chunk2mem(p); + *mem_prev = mem; + } + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + BOOST_CONTAINER_MEMCHAIN_INCORPORATE_AFTER(pchain, last_it, mem_orig, mem, num_elements); + } + } + if (was_enabled) + enable_mmap(m); + } + return 1; +} + +int boost_cont_multialloc_arrays + (size_t n_elements, const size_t *sizes, size_t element_size, size_t contiguous_elements, boost_cont_memchain *pchain) +{ + int ret = 0; + mstate ms = (mstate)gm; + ensure_initialization(); + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + else if (!PREACTION(ms)) { + ret = internal_multialloc_arrays(ms, n_elements, sizes, element_size, contiguous_elements, pchain); + POSTACTION(ms); + } + return ret; +} + + +/*Doug Lea malloc extensions*/ +static boost_cont_malloc_stats_t get_malloc_stats(mstate m) +{ + boost_cont_malloc_stats_t ret = { 0, 0, 0 }; + ensure_initialization(); + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!cinuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + + ret.max_system_bytes = maxfp; + ret.system_bytes = fp; + ret.in_use_bytes = used; + POSTACTION(m); + } + return ret; +} + +size_t boost_cont_size(const void *p) +{ return DL_SIZE_IMPL(p); } + +void* boost_cont_malloc(size_t bytes) +{ + size_t received_bytes; + ensure_initialization(); + return boost_cont_allocation_command + (BOOST_CONTAINER_ALLOCATE_NEW, 1, bytes, bytes, &received_bytes, 0).first; +} + +void boost_cont_free(void* mem) +{ + mstate ms = (mstate)gm; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + else if (!PREACTION(ms)) { + if(mem) + s_allocated_memory -= chunksize(mem2chunk(mem)); + mspace_free_lockless(ms, mem); + POSTACTION(ms); + } +} + +void* boost_cont_memalign(size_t bytes, size_t alignment) +{ + void *addr; + ensure_initialization(); + addr = mspace_memalign(gm, alignment, bytes); + if(addr){ + s_allocated_memory += chunksize(mem2chunk(addr)); + } + return addr; +} + +int boost_cont_multialloc_nodes + (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain) +{ + int ret = 0; + mstate ms = (mstate)gm; + ensure_initialization(); + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + else if (!PREACTION(ms)) { + ret = internal_node_multialloc(ms, n_elements, elem_size, contiguous_elements, pchain); + POSTACTION(ms); + } + return ret; +} + +size_t boost_cont_footprint() +{ + return ((mstate)gm)->footprint; +} + +size_t boost_cont_allocated_memory() +{ + size_t alloc_mem = 0; + mstate m = (mstate)gm; + ensure_initialization(); + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + + + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!is_inuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + { + size_t uordblks = m->footprint - mfree; + if(nfree) + alloc_mem = (size_t)(uordblks - (nfree-1)*TOP_FOOT_SIZE); + else + alloc_mem = uordblks; + } + } + + POSTACTION(m); + } + return alloc_mem; +} + +size_t boost_cont_chunksize(const void *p) +{ return chunksize(mem2chunk(p)); } + +int boost_cont_all_deallocated() +{ return !s_allocated_memory; } + +boost_cont_malloc_stats_t boost_cont_malloc_stats() +{ + mstate ms = (mstate)gm; + if (ok_magic(ms)) { + return get_malloc_stats(ms); + } + else { + boost_cont_malloc_stats_t r = { 0, 0, 0 }; + USAGE_ERROR_ACTION(ms,ms); + return r; + } +} + +size_t boost_cont_in_use_memory() +{ return s_allocated_memory; } + +int boost_cont_trim(size_t pad) +{ + ensure_initialization(); + return dlmalloc_trim(pad); +} + +int boost_cont_grow + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received) +{ + mstate ms = (mstate)gm; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + + if (!PREACTION(ms)) { + mchunkptr p = mem2chunk(oldmem); + size_t oldsize = chunksize(p); + p = try_realloc_chunk_with_min(ms, p, request2size(minbytes), request2size(maxbytes), 0); + POSTACTION(ms); + if(p){ + check_inuse_chunk(ms, p); + *received = DL_SIZE_IMPL(oldmem); + s_allocated_memory += chunksize(p) - oldsize; + } + return 0 != p; + } + return 0; +} + +int boost_cont_shrink + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit) +{ + mstate ms = (mstate)gm; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + + if (!PREACTION(ms)) { + int ret = internal_shrink(ms, oldmem, minbytes, maxbytes, received, do_commit); + POSTACTION(ms); + return 0 != ret; + } + return 0; +} + + +void* boost_cont_alloc + (size_t minbytes, size_t preferred_bytes, size_t *received_bytes) +{ + //ensure_initialization provided by boost_cont_allocation_command + return boost_cont_allocation_command + (BOOST_CONTAINER_ALLOCATE_NEW, 1, minbytes, preferred_bytes, received_bytes, 0).first; +} + +void boost_cont_multidealloc(boost_cont_memchain *pchain) +{ + mstate ms = (mstate)gm; + if (!ok_magic(ms)) { + (void)ms; + USAGE_ERROR_ACTION(ms,ms); + } + internal_multialloc_free(ms, pchain); +} + +int boost_cont_malloc_check() +{ +#ifdef DEBUG + mstate ms = (mstate)gm; + ensure_initialization(); + if (!ok_magic(ms)) { + (void)ms; + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + check_malloc_state(ms); + return 1; +#else + return 1; +#endif +} + + +boost_cont_command_ret_t boost_cont_allocation_command + (allocation_type command, size_t sizeof_object, size_t limit_size + , size_t preferred_size, size_t *received_size, void *reuse_ptr) +{ + boost_cont_command_ret_t ret = { 0, 0 }; + ensure_initialization(); + if(command & (BOOST_CONTAINER_SHRINK_IN_PLACE | BOOST_CONTAINER_TRY_SHRINK_IN_PLACE)){ + int success = boost_cont_shrink( reuse_ptr, preferred_size, limit_size + , received_size, (command & BOOST_CONTAINER_SHRINK_IN_PLACE)); + ret.first = success ? reuse_ptr : 0; + return ret; + } + + *received_size = 0; + + if(limit_size > preferred_size) + return ret; + + { + mstate ms = (mstate)gm; + + /*Expand in place*/ + if (!PREACTION(ms)) { + #if FOOTERS + if(reuse_ptr){ + mstate m = get_mstate_for(mem2chunk(reuse_ptr)); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, reuse_ptr); + return ret; + } + } + #endif + if(reuse_ptr && (command & (BOOST_CONTAINER_EXPAND_FWD | BOOST_CONTAINER_EXPAND_BWD))){ + void *r = internal_grow_both_sides + ( ms, command, reuse_ptr, limit_size + , preferred_size, received_size, sizeof_object, 1); + if(r){ + ret.first = r; + ret.second = 1; + goto postaction; + } + } + + if(command & BOOST_CONTAINER_ALLOCATE_NEW){ + void *addr = mspace_malloc_lockless(ms, preferred_size); + if(!addr) addr = mspace_malloc_lockless(ms, limit_size); + if(addr){ + s_allocated_memory += chunksize(mem2chunk(addr)); + *received_size = DL_SIZE_IMPL(addr); + } + ret.first = addr; + ret.second = 0; + if(addr){ + goto postaction; + } + } + + //Now try to expand both sides with min size + if(reuse_ptr && (command & (BOOST_CONTAINER_EXPAND_FWD | BOOST_CONTAINER_EXPAND_BWD))){ + void *r = internal_grow_both_sides + ( ms, command, reuse_ptr, limit_size + , preferred_size, received_size, sizeof_object, 0); + if(r){ + ret.first = r; + ret.second = 1; + goto postaction; + } + } + postaction: + POSTACTION(ms); + } + } + return ret; +} + +int boost_cont_mallopt(int param_number, int value) +{ + return change_mparam(param_number, value); +} + +void *boost_cont_sync_create() +{ + void *p = boost_cont_malloc(sizeof(MLOCK_T)); + if(p){ + if(0 != INITIAL_LOCK((MLOCK_T*)p)){ + boost_cont_free(p); + p = 0; + } + } + return p; +} + +void boost_cont_sync_destroy(void *sync) +{ + if(sync){ + (void)DESTROY_LOCK((MLOCK_T*)sync); + boost_cont_free(sync); + } +} + +int boost_cont_sync_lock(void *sync) +{ return 0 == (ACQUIRE_LOCK((MLOCK_T*)sync)); } + +void boost_cont_sync_unlock(void *sync) +{ RELEASE_LOCK((MLOCK_T*)sync); } + +int boost_cont_global_sync_lock() +{ + int ret; + ensure_initialization(); + ret = ACQUIRE_MALLOC_GLOBAL_LOCK(); + return 0 == ret; +} + +void boost_cont_global_sync_unlock() +{ + RELEASE_MALLOC_GLOBAL_LOCK() +} + +//#ifdef DL_DEBUG_DEFINED +// #undef DEBUG +//#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif diff --git a/src/boost/libs/container/src/global_resource.cpp b/src/boost/libs/container/src/global_resource.cpp new file mode 100644 index 00000000..df9c688b --- /dev/null +++ b/src/boost/libs/container/src/global_resource.cpp @@ -0,0 +1,106 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#define BOOST_CONTAINER_SOURCE +#include +#include +#include +#include +#include //For global lock + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +class new_delete_resource_imp + : public memory_resource +{ + public: + + virtual ~new_delete_resource_imp() + {} + + virtual void* do_allocate(std::size_t bytes, std::size_t alignment) + { (void)bytes; (void)alignment; return new char[bytes]; } + + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + { (void)bytes; (void)alignment; delete[]((char*)p); } + + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT + { return &other == this; } +} new_delete_resource_instance; + +struct null_memory_resource_imp + : public memory_resource +{ + public: + + virtual ~null_memory_resource_imp() + {} + + virtual void* do_allocate(std::size_t bytes, std::size_t alignment) + { + (void)bytes; (void)alignment; + throw_bad_alloc(); + return 0; + } + + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + { (void)p; (void)bytes; (void)alignment; } + + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT + { return &other == this; } +} null_memory_resource_instance; + +BOOST_CONTAINER_DECL memory_resource* new_delete_resource() BOOST_NOEXCEPT +{ + return &new_delete_resource_instance; +} + +BOOST_CONTAINER_DECL memory_resource* null_memory_resource() BOOST_NOEXCEPT +{ + return &null_memory_resource_instance; +} + +static memory_resource *default_memory_resource = &new_delete_resource_instance; + +BOOST_CONTAINER_DECL memory_resource* set_default_resource(memory_resource* r) BOOST_NOEXCEPT +{ + //TO-DO: synchronizes-with part using atomics + if(dlmalloc_global_sync_lock()){ + memory_resource *previous = default_memory_resource; + default_memory_resource = r ? r : new_delete_resource(); + dlmalloc_global_sync_unlock(); + return previous; + } + else{ + return new_delete_resource(); + } +} + +BOOST_CONTAINER_DECL memory_resource* get_default_resource() BOOST_NOEXCEPT +{ + //TO-DO: synchronizes-with part using atomics + if(dlmalloc_global_sync_lock()){ + memory_resource *current = default_memory_resource; + dlmalloc_global_sync_unlock(); + return current; + } + else{ + return new_delete_resource(); + } +} + +} //namespace pmr { +} //namespace container { +} //namespace boost { diff --git a/src/boost/libs/container/src/monotonic_buffer_resource.cpp b/src/boost/libs/container/src/monotonic_buffer_resource.cpp new file mode 100644 index 00000000..29ffde1d --- /dev/null +++ b/src/boost/libs/container/src/monotonic_buffer_resource.cpp @@ -0,0 +1,165 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#define BOOST_CONTAINER_SOURCE +#include +#include + +#include +#include + +#include +#include +#include + + +#include + +namespace { + +#ifdef BOOST_HAS_INTPTR_T +typedef boost::uintptr_t uintptr_type; +#else +typedef std::size_t uintptr_type; +#endif + +static const std::size_t minimum_buffer_size = 2*sizeof(void*); + +} //namespace { + +namespace boost { +namespace container { +namespace pmr { + +void monotonic_buffer_resource::increase_next_buffer() +{ + m_next_buffer_size = (std::size_t(-1)/2 < m_next_buffer_size) ? std::size_t(-1) : m_next_buffer_size*2; +} + +void monotonic_buffer_resource::increase_next_buffer_at_least_to(std::size_t minimum_size) +{ + if(m_next_buffer_size < minimum_size){ + if(bi::detail::is_pow2(minimum_size)){ + m_next_buffer_size = minimum_size; + } + else if(std::size_t(-1)/2 < minimum_size){ + m_next_buffer_size = minimum_size; + } + else{ + m_next_buffer_size = bi::detail::ceil_pow2(minimum_size); + } + } +} + +monotonic_buffer_resource::monotonic_buffer_resource(memory_resource* upstream) BOOST_NOEXCEPT + : m_memory_blocks(upstream ? *upstream : *get_default_resource()) + , m_current_buffer(0) + , m_current_buffer_size(0u) + , m_next_buffer_size(initial_next_buffer_size) + , m_initial_buffer(0) + , m_initial_buffer_size(0u) +{} + +monotonic_buffer_resource::monotonic_buffer_resource(std::size_t initial_size, memory_resource* upstream) BOOST_NOEXCEPT + : m_memory_blocks(upstream ? *upstream : *get_default_resource()) + , m_current_buffer(0) + , m_current_buffer_size(0u) + , m_next_buffer_size(minimum_buffer_size) + , m_initial_buffer(0) + , m_initial_buffer_size(0u) +{ //In case initial_size is zero + this->increase_next_buffer_at_least_to(initial_size + !initial_size); +} + +monotonic_buffer_resource::monotonic_buffer_resource(void* buffer, std::size_t buffer_size, memory_resource* upstream) BOOST_NOEXCEPT + : m_memory_blocks(upstream ? *upstream : *get_default_resource()) + , m_current_buffer(buffer) + , m_current_buffer_size(buffer_size) + , m_next_buffer_size + (bi::detail::previous_or_equal_pow2 + (boost::container::dtl::max_value(buffer_size, std::size_t(initial_next_buffer_size)))) + , m_initial_buffer(buffer) + , m_initial_buffer_size(buffer_size) +{ this->increase_next_buffer(); } + +monotonic_buffer_resource::~monotonic_buffer_resource() +{ this->release(); } + +void monotonic_buffer_resource::release() BOOST_NOEXCEPT +{ + m_memory_blocks.release(); + m_current_buffer = m_initial_buffer; + m_current_buffer_size = m_initial_buffer_size; + m_next_buffer_size = initial_next_buffer_size; +} + +memory_resource* monotonic_buffer_resource::upstream_resource() const BOOST_NOEXCEPT +{ return &m_memory_blocks.upstream_resource(); } + +std::size_t monotonic_buffer_resource::remaining_storage(std::size_t alignment, std::size_t &wasted_due_to_alignment) const BOOST_NOEXCEPT +{ + const uintptr_type up_alignment_minus1 = alignment - 1u; + const uintptr_type up_alignment_mask = ~up_alignment_minus1; + const uintptr_type up_addr = uintptr_type(m_current_buffer); + const uintptr_type up_aligned_addr = (up_addr + up_alignment_minus1) & up_alignment_mask; + wasted_due_to_alignment = std::size_t(up_aligned_addr - up_addr); + return m_current_buffer_size <= wasted_due_to_alignment ? 0u : m_current_buffer_size - wasted_due_to_alignment; +} + +std::size_t monotonic_buffer_resource::remaining_storage(std::size_t alignment) const BOOST_NOEXCEPT +{ + std::size_t ignore_this; + return this->remaining_storage(alignment, ignore_this); +} + +const void *monotonic_buffer_resource::current_buffer() const BOOST_NOEXCEPT +{ return m_current_buffer; } + +std::size_t monotonic_buffer_resource::next_buffer_size() const BOOST_NOEXCEPT +{ return m_next_buffer_size; } + +void *monotonic_buffer_resource::allocate_from_current(std::size_t aligner, std::size_t bytes) +{ + char * p = (char*)m_current_buffer + aligner; + m_current_buffer = p + bytes; + m_current_buffer_size -= aligner + bytes; + return p; +} + +void* monotonic_buffer_resource::do_allocate(std::size_t bytes, std::size_t alignment) +{ + if(alignment > memory_resource::max_align) + throw_bad_alloc(); + + //See if there is room in current buffer + std::size_t aligner = 0u; + if(this->remaining_storage(alignment, aligner) < bytes){ + //Update next_buffer_size to at least bytes + this->increase_next_buffer_at_least_to(bytes); + //Now allocate and update internal data + m_current_buffer = (char*)m_memory_blocks.allocate(m_next_buffer_size); + m_current_buffer_size = m_next_buffer_size; + this->increase_next_buffer(); + } + //Enough internal storage, extract from it + return this->allocate_from_current(aligner, bytes); +} + +void monotonic_buffer_resource::do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_NOEXCEPT +{ (void)p; (void)bytes; (void)alignment; } + +bool monotonic_buffer_resource::do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT +{ return this == dynamic_cast(&other); } + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include diff --git a/src/boost/libs/container/src/pool_resource.cpp b/src/boost/libs/container/src/pool_resource.cpp new file mode 100644 index 00000000..e6829e28 --- /dev/null +++ b/src/boost/libs/container/src/pool_resource.cpp @@ -0,0 +1,291 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#define BOOST_CONTAINER_SOURCE +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +//pool_data_t + +class pool_data_t + : public block_slist_base<> +{ + typedef block_slist_base<> block_slist_base_t; + + public: + explicit pool_data_t(std::size_t initial_blocks_per_chunk) + : block_slist_base_t(), next_blocks_per_chunk(initial_blocks_per_chunk) + { slist_algo::init_header(&free_slist); } + + void *allocate_block() BOOST_NOEXCEPT + { + if(slist_algo::unique(&free_slist)){ + return 0; + } + slist_node *pv = slist_algo::node_traits::get_next(&free_slist); + slist_algo::unlink_after(&free_slist); + pv->~slist_node(); + return pv; + } + + void deallocate_block(void *p) BOOST_NOEXCEPT + { + slist_node *pv = ::new(p, boost_container_new_t()) slist_node(); + slist_algo::link_after(&free_slist, pv); + } + + void release(memory_resource &upstream) + { + slist_algo::init_header(&free_slist); + this->block_slist_base_t::release(upstream); + next_blocks_per_chunk = pool_options_minimum_max_blocks_per_chunk; + } + + void replenish(memory_resource &mr, std::size_t pool_block, std::size_t max_blocks_per_chunk) + { + //Limit max value + std::size_t blocks_per_chunk = boost::container::dtl::min_value(max_blocks_per_chunk, next_blocks_per_chunk); + //Avoid overflow + blocks_per_chunk = boost::container::dtl::min_value(blocks_per_chunk, std::size_t(-1)/pool_block); + + //Minimum block size is at least max_align, so all pools allocate sizes that are multiple of max_align, + //meaning that all blocks are max_align-aligned. + char *p = static_cast(block_slist_base_t::allocate(blocks_per_chunk*pool_block, mr)); + + //Create header types. This is no-throw + for(std::size_t i = 0, max = blocks_per_chunk; i != max; ++i){ + slist_node *const pv = ::new(p, boost_container_new_t()) slist_node(); + slist_algo::link_after(&free_slist, pv); + p += pool_block; + } + + //Update next block per chunk + next_blocks_per_chunk = max_blocks_per_chunk/2u < blocks_per_chunk ? max_blocks_per_chunk : blocks_per_chunk*2u; + } + + std::size_t cache_count() const + { return slist_algo::count(&free_slist) - 1u; } + + slist_node free_slist; + std::size_t next_blocks_per_chunk; +}; + +//pool_resource + +//Detect overflow in ceil_pow2 +BOOST_STATIC_ASSERT(pool_options_default_max_blocks_per_chunk <= (std::size_t(-1)/2u+1u)); +//Sanity checks +BOOST_STATIC_ASSERT(bi::detail::static_is_pow2::value); +BOOST_STATIC_ASSERT(bi::detail::static_is_pow2::value); + +//unsynchronized_pool_resource + +void pool_resource::priv_limit_option(std::size_t &val, std::size_t min, std::size_t max) //static +{ + if(!val){ + val = max; + } + else{ + val = val < min ? min : boost::container::dtl::min_value(val, max); + } +} + +std::size_t pool_resource::priv_pool_index(std::size_t block_size) //static +{ + //For allocations equal or less than pool_options_minimum_largest_required_pool_block + //the smallest pool is used + block_size = boost::container::dtl::max_value(block_size, pool_options_minimum_largest_required_pool_block); + return bi::detail::ceil_log2(block_size) + - bi::detail::ceil_log2(pool_options_minimum_largest_required_pool_block); +} + +std::size_t pool_resource::priv_pool_block(std::size_t index) //static +{ + //For allocations equal or less than pool_options_minimum_largest_required_pool_block + //the smallest pool is used + return pool_options_minimum_largest_required_pool_block << index; +} + +void pool_resource::priv_fix_options() +{ + priv_limit_option(m_options.max_blocks_per_chunk + , pool_options_minimum_max_blocks_per_chunk + , pool_options_default_max_blocks_per_chunk); + priv_limit_option + ( m_options.largest_required_pool_block + , pool_options_minimum_largest_required_pool_block + , pool_options_default_largest_required_pool_block); + m_options.largest_required_pool_block = bi::detail::ceil_pow2(m_options.largest_required_pool_block); +} + +void pool_resource::priv_init_pools() +{ + const std::size_t num_pools = priv_pool_index(m_options.largest_required_pool_block)+1u; + //Otherwise, just use the default alloc (zero pools) + void *p = 0; + //This can throw + p = m_upstream.allocate(sizeof(pool_data_t)*num_pools); + //This is nothrow + m_pool_data = static_cast(p); + for(std::size_t i = 0, max = num_pools; i != max; ++i){ + ::new(&m_pool_data[i], boost_container_new_t()) pool_data_t(pool_options_minimum_max_blocks_per_chunk); + } + m_pool_count = num_pools; +} + +void pool_resource::priv_constructor_body() +{ + this->priv_fix_options(); +} + +pool_resource::pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT + : m_options(opts), m_upstream(*upstream), m_oversized_list(), m_pool_data(), m_pool_count() +{ this->priv_constructor_body(); } + +pool_resource::pool_resource() BOOST_NOEXCEPT + : m_options(), m_upstream(*get_default_resource()), m_oversized_list(), m_pool_data(), m_pool_count() +{ this->priv_constructor_body(); } + +pool_resource::pool_resource(memory_resource* upstream) BOOST_NOEXCEPT + : m_options(), m_upstream(*upstream), m_oversized_list(), m_pool_data(), m_pool_count() +{ this->priv_constructor_body(); } + +pool_resource::pool_resource(const pool_options& opts) BOOST_NOEXCEPT + : m_options(opts), m_upstream(*get_default_resource()), m_oversized_list(), m_pool_data(), m_pool_count() +{ this->priv_constructor_body(); } + +pool_resource::~pool_resource() //virtual +{ + this->release(); + + for(std::size_t i = 0, max = m_pool_count; i != max; ++i){ + m_pool_data[i].~pool_data_t(); + } + if(m_pool_data){ + m_upstream.deallocate((void*)m_pool_data, sizeof(pool_data_t)*m_pool_count); + } +} + +void pool_resource::release() +{ + m_oversized_list.release(m_upstream); + for(std::size_t i = 0, max = m_pool_count; i != max; ++i) + { + m_pool_data[i].release(m_upstream); + } +} + +memory_resource* pool_resource::upstream_resource() const +{ return &m_upstream; } + +pool_options pool_resource::options() const +{ return m_options; } + +void* pool_resource::do_allocate(std::size_t bytes, std::size_t alignment) //virtual +{ + if(!m_pool_data){ + this->priv_init_pools(); + } + (void)alignment; //alignment ignored here, max_align is used by pools + if(bytes > m_options.largest_required_pool_block){ + return m_oversized_list.allocate(bytes, m_upstream); + } + else{ + const std::size_t pool_idx = priv_pool_index(bytes); + pool_data_t & pool = m_pool_data[pool_idx]; + void *p = pool.allocate_block(); + if(!p){ + pool.replenish(m_upstream, priv_pool_block(pool_idx), m_options.max_blocks_per_chunk); + p = pool.allocate_block(); + } + return p; + } +} + +void pool_resource::do_deallocate(void* p, std::size_t bytes, std::size_t alignment) //virtual +{ + (void)alignment; //alignment ignored here, max_align is used by pools + if(bytes > m_options.largest_required_pool_block){ + //Just cached + return m_oversized_list.deallocate(p, m_upstream); + } + else{ + const std::size_t pool_idx = priv_pool_index(bytes); + return m_pool_data[pool_idx].deallocate_block(p); + } +} + +bool pool_resource::do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT //virtual +{ return this == dynamic_cast(&other); } + + +std::size_t pool_resource::pool_count() const +{ + if(BOOST_LIKELY((0 != m_pool_data))){ + return m_pool_count; + } + else{ + return priv_pool_index(m_options.largest_required_pool_block)+1u; + } +} + +std::size_t pool_resource::pool_index(std::size_t bytes) const +{ + if(bytes > m_options.largest_required_pool_block){ + return pool_count(); + } + else{ + return priv_pool_index(bytes); + } +} + +std::size_t pool_resource::pool_next_blocks_per_chunk(std::size_t pool_idx) const +{ + if(BOOST_LIKELY((m_pool_data && pool_idx < m_pool_count))){ + return m_pool_data[pool_idx].next_blocks_per_chunk; + } + else{ + return 1u; + } +} + +std::size_t pool_resource::pool_block(std::size_t pool_idx) const +{ return priv_pool_block(pool_idx); } + +std::size_t pool_resource::pool_cached_blocks(std::size_t pool_idx) const +{ + if(BOOST_LIKELY((m_pool_data && pool_idx < m_pool_count))){ + return m_pool_data[pool_idx].cache_count(); + } + else{ + return 0u; + } +} + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include diff --git a/src/boost/libs/container/src/synchronized_pool_resource.cpp b/src/boost/libs/container/src/synchronized_pool_resource.cpp new file mode 100644 index 00000000..0a725e9f --- /dev/null +++ b/src/boost/libs/container/src/synchronized_pool_resource.cpp @@ -0,0 +1,111 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#define BOOST_CONTAINER_SOURCE +#include +#include +#include + +#include +#include + +namespace { + +using namespace boost::container::dtl; + +class thread_mutex_lock +{ + thread_mutex &m_mut; + + public: + explicit thread_mutex_lock(thread_mutex &m) + : m_mut(m) + { + m_mut.lock(); + } + + ~thread_mutex_lock() + { + m_mut.unlock(); + } +}; + +} //namespace { + +namespace boost { +namespace container { +namespace pmr { + +synchronized_pool_resource::synchronized_pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT + : m_mut(), m_pool_resource(opts, upstream) +{} + +synchronized_pool_resource::synchronized_pool_resource() BOOST_NOEXCEPT + : m_mut(), m_pool_resource() +{} + +synchronized_pool_resource::synchronized_pool_resource(memory_resource* upstream) BOOST_NOEXCEPT + : m_mut(), m_pool_resource(upstream) +{} + +synchronized_pool_resource::synchronized_pool_resource(const pool_options& opts) BOOST_NOEXCEPT + : m_mut(), m_pool_resource(opts) +{} + +synchronized_pool_resource::~synchronized_pool_resource() //virtual +{} + +void synchronized_pool_resource::release() +{ + thread_mutex_lock lck(m_mut); (void)lck; + m_pool_resource.release(); +} + +memory_resource* synchronized_pool_resource::upstream_resource() const +{ return m_pool_resource.upstream_resource(); } + +pool_options synchronized_pool_resource::options() const +{ return m_pool_resource.options(); } + +void* synchronized_pool_resource::do_allocate(std::size_t bytes, std::size_t alignment) //virtual +{ + thread_mutex_lock lck(m_mut); (void)lck; + return m_pool_resource.do_allocate(bytes, alignment); +} + +void synchronized_pool_resource::do_deallocate(void* p, std::size_t bytes, std::size_t alignment) //virtual +{ + thread_mutex_lock lck(m_mut); (void)lck; + return m_pool_resource.do_deallocate(p, bytes, alignment); +} + +bool synchronized_pool_resource::do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT //virtual +{ return this == dynamic_cast(&other); } + +std::size_t synchronized_pool_resource::pool_count() const +{ return m_pool_resource.pool_count(); } + +std::size_t synchronized_pool_resource::pool_index(std::size_t bytes) const +{ return m_pool_resource.pool_index(bytes); } + +std::size_t synchronized_pool_resource::pool_next_blocks_per_chunk(std::size_t pool_idx) const +{ return m_pool_resource.pool_next_blocks_per_chunk(pool_idx); } + +std::size_t synchronized_pool_resource::pool_block(std::size_t pool_idx) const +{ return m_pool_resource.pool_block(pool_idx); } + +std::size_t synchronized_pool_resource::pool_cached_blocks(std::size_t pool_idx) const +{ return m_pool_resource.pool_cached_blocks(pool_idx); } + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include diff --git a/src/boost/libs/container/src/unsynchronized_pool_resource.cpp b/src/boost/libs/container/src/unsynchronized_pool_resource.cpp new file mode 100644 index 00000000..0c84f694 --- /dev/null +++ b/src/boost/libs/container/src/unsynchronized_pool_resource.cpp @@ -0,0 +1,79 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#define BOOST_CONTAINER_SOURCE +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +unsynchronized_pool_resource::unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT + : m_resource(opts, upstream) +{} + +unsynchronized_pool_resource::unsynchronized_pool_resource() BOOST_NOEXCEPT + : m_resource() +{} + +unsynchronized_pool_resource::unsynchronized_pool_resource(memory_resource* upstream) BOOST_NOEXCEPT + : m_resource(upstream) +{} + +unsynchronized_pool_resource::unsynchronized_pool_resource(const pool_options& opts) BOOST_NOEXCEPT + : m_resource(opts) +{} + +unsynchronized_pool_resource::~unsynchronized_pool_resource() //virtual +{} + +void unsynchronized_pool_resource::release() +{ + m_resource.release(); +} + +memory_resource* unsynchronized_pool_resource::upstream_resource() const +{ return m_resource.upstream_resource(); } + +pool_options unsynchronized_pool_resource::options() const +{ return m_resource.options(); } + +void* unsynchronized_pool_resource::do_allocate(std::size_t bytes, std::size_t alignment) //virtual +{ return m_resource.do_allocate(bytes, alignment); } + +void unsynchronized_pool_resource::do_deallocate(void* p, std::size_t bytes, std::size_t alignment) //virtual +{ return m_resource.do_deallocate(p, bytes, alignment); } + +bool unsynchronized_pool_resource::do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT //virtual +{ return this == dynamic_cast(&other); } + +std::size_t unsynchronized_pool_resource::pool_count() const +{ return m_resource.pool_count(); } + +std::size_t unsynchronized_pool_resource::pool_index(std::size_t bytes) const +{ return m_resource.pool_index(bytes); } + +std::size_t unsynchronized_pool_resource::pool_next_blocks_per_chunk(std::size_t pool_idx) const +{ return m_resource.pool_next_blocks_per_chunk(pool_idx); } + +std::size_t unsynchronized_pool_resource::pool_block(std::size_t pool_idx) const +{ return m_resource.pool_block(pool_idx); } + +std::size_t unsynchronized_pool_resource::pool_cached_blocks(std::size_t pool_idx) const +{ return m_resource.pool_cached_blocks(pool_idx); } + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include diff --git a/src/boost/libs/container/test/Jamfile.v2 b/src/boost/libs/container/test/Jamfile.v2 new file mode 100644 index 00000000..2b4995be --- /dev/null +++ b/src/boost/libs/container/test/Jamfile.v2 @@ -0,0 +1,40 @@ +# Boost Container Library Test Jamfile + +# (C) Copyright Ion Gaztanaga 2009-2013. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# Adapted from John Maddock's TR1 Jamfile.v2 +# Copyright John Maddock 2005. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +project + : requirements + shared:BOOST_CONTAINER_DYN_LINK=1 + gcc-cygwin:static + ; + +# this rule enumerates through all the sources and invokes +# the run rule for each source, the result is a list of all +# the run rules, which we can pass on to the test_suite rule: + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) /boost/container//boost_container + : # additional args + : # test-files + : # requirements + ] ; + } + + return $(all_rules) ; +} + +test-suite container_test : [ test_all r ] ; diff --git a/src/boost/libs/container/test/alloc_basic_test.cpp b/src/boost/libs/container/test/alloc_basic_test.cpp new file mode 100644 index 00000000..4bfdcf48 --- /dev/null +++ b/src/boost/libs/container/test/alloc_basic_test.cpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +using namespace boost::container; + +bool basic_test() +{ + size_t received = 0; + if(!dlmalloc_all_deallocated()) + return false; + void *ptr = dlmalloc_alloc(50, 98, &received); + if(dlmalloc_size(ptr) != received) + return false; + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) + return false; + + if(dlmalloc_all_deallocated()) + return false; + + dlmalloc_grow(ptr, received + 20, received + 30, &received); + + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) + return false; + + if(dlmalloc_size(ptr) != received) + return false; + + if(!dlmalloc_shrink(ptr, 100, 140, &received, 1)) + return false; + + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) + return false; + + if(!dlmalloc_shrink(ptr, 0, 140, &received, 1)) + return false; + + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) + return false; + + if(dlmalloc_shrink(ptr, 0, received/2, &received, 1)) + return false; + + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) + return false; + + if(dlmalloc_size(ptr) != received) + return false; + + dlmalloc_free(ptr); + + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) + return false; + return true; +} + +bool vector_test() +{ + typedef boost::container::vector > Vector; + if(!dlmalloc_all_deallocated()) + return false; + { + const int NumElem = 1000; + Vector v; + v.resize(NumElem); + int *orig_buf = &v[0]; + int *new_buf = &v[0]; + while(orig_buf == new_buf){ + Vector::size_type cl = v.capacity() - v.size(); + while(cl--){ + v.push_back(0); + } + v.push_back(0); + new_buf = &v[0]; + } + } + if(!dlmalloc_all_deallocated()) + return false; + return true; +} + +bool list_test() +{ + typedef boost::container::list > List; + if(!dlmalloc_all_deallocated()) + return false; + { + const int NumElem = 1000; + List l; + int values[NumElem]; + l.insert(l.end(), &values[0], &values[NumElem]); + } + if(!dlmalloc_all_deallocated()) + return false; + return true; +} + +int main() +{ + if(!basic_test()) + return 1; + if(!vector_test()) + return 1; + if(!list_test()) + return 1; + return 0; +} diff --git a/src/boost/libs/container/test/alloc_full_test.cpp b/src/boost/libs/container/test/alloc_full_test.cpp new file mode 100644 index 00000000..54e1160c --- /dev/null +++ b/src/boost/libs/container/test/alloc_full_test.cpp @@ -0,0 +1,849 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + + +#ifdef _MSC_VER +#pragma warning (disable:4702) +#endif + +#include +#include +#include +#include //std::remove +#include + +namespace boost { namespace container { namespace test { + +static const int NumIt = 200; + +enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocation, EndDeallocationType }; + +//This test allocates until there is no more memory +//and after that deallocates all in the inverse order + +bool test_allocation() +{ + if(!dlmalloc_all_deallocated()) + return false; + dlmalloc_malloc_check(); + for( deallocation_type t = DirectDeallocation + ; t != EndDeallocationType + ; t = (deallocation_type)((int)t + 1)){ + std::vector buffers; + //std::size_t free_memory = a.get_free_memory(); + + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i); + if(!ptr) + break; + buffers.push_back(ptr); + } + + switch(t){ + case DirectDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + dlmalloc_free(buffers[j]); + } + } + break; + case InverseDeallocation: + { + for(int j = (int)buffers.size() + ;j-- + ;){ + dlmalloc_free(buffers[j]); + } + } + break; + case MixedDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + } + break; + default: + break; + } + if(!dlmalloc_all_deallocated()) + return false; + //bool ok = free_memory == a.get_free_memory() && + //a.all_memory_deallocated() && a.check_sanity(); + //if(!ok) return ok; + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated(); +} + +//This test allocates until there is no more memory +//and after that tries to shrink all the buffers to the +//half of the original size + +bool test_allocation_shrink() +{ + dlmalloc_malloc_check(); + std::vector buffers; + + //Allocate buffers with extra memory + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i*2); + if(!ptr) + break; + buffers.push_back(ptr); + } + + //Now shrink to half + for(int i = 0, max = (int)buffers.size() + ;i < max + ; ++i){ + std::size_t try_received_size = 0; + void* try_result = dlmalloc_allocation_command + ( BOOST_CONTAINER_TRY_SHRINK_IN_PLACE, 1, i*2 + , i, &try_received_size, (char*)buffers[i]).first; + + std::size_t received_size = 0; + void* result = dlmalloc_allocation_command + ( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, i*2 + , i, &received_size, (char*)buffers[i]).first; + + if(result != try_result) + return false; + + if(received_size != try_received_size) + return false; + + if(result){ + if(received_size > std::size_t(i*2)){ + return false; + } + if(received_size < std::size_t(i)){ + return false; + } + } + } + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that tries to expand all the buffers to +//avoid the wasted internal fragmentation + +bool test_allocation_expand() +{ + dlmalloc_malloc_check(); + std::vector buffers; + + //Allocate buffers with extra memory + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i); + if(!ptr) + break; + buffers.push_back(ptr); + } + + //Now try to expand to the double of the size + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + std::size_t received_size = 0; + std::size_t min_size = i+1; + std::size_t preferred_size = i*2; + preferred_size = min_size > preferred_size ? min_size : preferred_size; + while(dlmalloc_allocation_command + ( BOOST_CONTAINER_EXPAND_FWD, 1, min_size + , preferred_size, &received_size, (char*)buffers[i]).first){ + //Check received size is bigger than minimum + if(received_size < min_size){ + return false; + } + //Now, try to expand further + min_size = received_size+1; + preferred_size = min_size*2; + } + } + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that tries to expand all the buffers to +//avoid the wasted internal fragmentation +bool test_allocation_shrink_and_expand() +{ + std::vector buffers; + std::vector received_sizes; + std::vector size_reduced; + + //Allocate buffers wand store received sizes + for(int i = 0; i != NumIt; ++i){ + std::size_t received_size = 0; + void *ptr = dlmalloc_allocation_command + (BOOST_CONTAINER_ALLOCATE_NEW, 1, i, i*2, &received_size, 0).first; + if(!ptr){ + ptr = dlmalloc_allocation_command + ( BOOST_CONTAINER_ALLOCATE_NEW, 1, 1, i*2, &received_size, 0).first; + if(!ptr) + break; + } + buffers.push_back(ptr); + received_sizes.push_back(received_size); + } + + //Now shrink to half + for(int i = 0, max = (int)buffers.size() + ; i < max + ; ++i){ + std::size_t received_size = 0; + bool size_reduced_flag; + if(true == (size_reduced_flag = !! + dlmalloc_allocation_command + ( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, received_sizes[i] + , i, &received_size, (char*)buffers[i]).first)){ + if(received_size > std::size_t(received_sizes[i])){ + return false; + } + if(received_size < std::size_t(i)){ + return false; + } + } + size_reduced.push_back(size_reduced_flag); + } + + //Now try to expand to the original size + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + if(!size_reduced[i]) continue; + std::size_t received_size = 0; + std::size_t request_size = received_sizes[i]; + if(dlmalloc_allocation_command + ( BOOST_CONTAINER_EXPAND_FWD, 1, request_size + , request_size, &received_size, (char*)buffers[i]).first){ + if(received_size != request_size){ + return false; + } + } + else{ + return false; + } + } + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that deallocates the odd buffers to +//make room for expansions. The expansion will probably +//success since the deallocation left room for that. + +bool test_allocation_deallocation_expand() +{ + dlmalloc_malloc_check(); + std::vector buffers; + + //Allocate buffers with extra memory + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i); + if(!ptr) + break; + buffers.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + if(i%2){ + dlmalloc_free(buffers[i]); + buffers[i] = 0; + } + } + + //Now try to expand to the double of the size + for(int i = 0, max = (int)buffers.size() + ;i < max + ;++i){ + // + if(buffers[i]){ + std::size_t received_size = 0; + std::size_t min_size = i+1; + std::size_t preferred_size = i*2; + preferred_size = min_size > preferred_size ? min_size : preferred_size; + + while(dlmalloc_allocation_command + ( BOOST_CONTAINER_EXPAND_FWD, 1, min_size + , preferred_size, &received_size, (char*)buffers[i]).first){ + //Check received size is bigger than minimum + if(received_size < min_size){ + return false; + } + //Now, try to expand further + min_size = received_size+1; + preferred_size = min_size*2; + } + } + } + + //Now erase null values from the vector + buffers.erase(std::remove(buffers.begin(), buffers.end(), (void*)0) + ,buffers.end()); + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates until there is no more memory +//and after that deallocates all except the last. +//If the allocation algorithm is a bottom-up algorithm +//the last buffer will be in the end of the segment. +//Then the test will start expanding backwards, until +//the buffer fills all the memory + +bool test_allocation_with_reuse() +{ + dlmalloc_malloc_check(); + //We will repeat this test for different sized elements + for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){ + std::vector buffers; + + //Allocate buffers with extra memory + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i*sizeof_object); + if(!ptr) + break; + buffers.push_back(ptr); + } + + //Now deallocate all except the latest + //Now try to expand to the double of the size + for(int i = 0, max = (int)buffers.size() - 1 + ;i < max + ;++i){ + dlmalloc_free(buffers[i]); + } + + //Save the unique buffer and clear vector + void *ptr = buffers.back(); + buffers.clear(); + + //Now allocate with reuse + std::size_t received_size = 0; + for(int i = 0; i != NumIt; ++i){ + std::size_t min_size = (received_size/sizeof_object + 1)*sizeof_object; + std::size_t prf_size = (received_size/sizeof_object + (i+1)*2)*sizeof_object; + dlmalloc_command_ret_t ret = dlmalloc_allocation_command + ( BOOST_CONTAINER_EXPAND_BWD, sizeof_object, min_size + , prf_size, &received_size, (char*)ptr); + //If we have memory, this must be a buffer reuse + if(!ret.first) + break; + //If we have memory, this must be a buffer reuse + if(!ret.second) + return false; + if(received_size < min_size) + return false; + ptr = ret.first; + } + //There should be only a single block so deallocate it + dlmalloc_free(ptr); + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) + return false; + } + return true; +} + + +//This test allocates memory with different alignments +//and checks returned memory is aligned. + +bool test_aligned_allocation() +{ + dlmalloc_malloc_check(); + //Allocate aligned buffers in a loop + //and then deallocate it + for(unsigned int i = 1; i != (1 << (sizeof(int)/2)); i <<= 1){ + for(unsigned int j = 1; j != 512; j <<= 1){ + void *ptr = dlmalloc_memalign(i-1, j); + if(!ptr){ + return false; + } + + if(((std::size_t)ptr & (j - 1)) != 0) + return false; + dlmalloc_free(ptr); + //if(!a.all_memory_deallocated() || !a.check_sanity()){ + // return false; + //} + } + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates memory with different alignments +//and checks returned memory is aligned. + +bool test_continuous_aligned_allocation() +{ + dlmalloc_malloc_check(); + std::vector buffers; + //Allocate aligned buffers in a loop + //and then deallocate it + bool continue_loop = true; + unsigned int MaxAlign = 4096; + unsigned int MaxSize = 4096; + for(unsigned i = 1; i < MaxSize; i <<= 1){ + for(unsigned int j = 1; j < MaxAlign; j <<= 1){ + for(int k = 0; k != NumIt; ++k){ + void *ptr = dlmalloc_memalign(i-1, j); + buffers.push_back(ptr); + if(!ptr){ + continue_loop = false; + break; + } + + if(((std::size_t)ptr & (j - 1)) != 0) + return false; + } + //Deallocate all + for(int k = (int)buffers.size(); k--;){ + dlmalloc_free(buffers[k]); + } + buffers.clear(); + //if(!a.all_memory_deallocated() && a.check_sanity()) + // return false; + if(!continue_loop) + break; + } + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); +} + +//This test allocates multiple values until there is no more memory +//and after that deallocates all in the inverse order +bool test_many_equal_allocation() +{ + dlmalloc_malloc_check(); + for( deallocation_type t = DirectDeallocation + ; t != EndDeallocationType + ; t = (deallocation_type)((int)t + 1)){ + //std::size_t free_memory = a.get_free_memory(); + + std::vector buffers2; + + //Allocate buffers with extra memory + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i); + if(!ptr) + break; + //if(!a.check_sanity()) + //return false; + buffers2.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers2.size() + ;i < max + ;++i){ + if(i%2){ + dlmalloc_free(buffers2[i]); + buffers2[i] = 0; + } + } + + //if(!a.check_sanity()) + //return false; + + std::vector buffers; + for(int i = 0; i != NumIt/10; ++i){ + dlmalloc_memchain chain; + BOOST_CONTAINER_MEMCHAIN_INIT(&chain); + dlmalloc_multialloc_nodes((i+1)*2, i+1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); + if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) + break; + + std::size_t n = 0; + for(; !BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it); ++n){ + buffers.push_back(BOOST_CONTAINER_MEMIT_ADDR(it)); + BOOST_CONTAINER_MEMIT_NEXT(it); + } + if(n != std::size_t((i+1)*2)) + return false; + } + + //if(!a.check_sanity()) + //return false; + + switch(t){ + case DirectDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + dlmalloc_free(buffers[j]); + } + } + break; + case InverseDeallocation: + { + for(int j = (int)buffers.size() + ;j-- + ;){ + dlmalloc_free(buffers[j]); + } + } + break; + case MixedDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + } + break; + default: + break; + } + + //Deallocate the rest of the blocks + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers2.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers2.size())/4; + dlmalloc_free(buffers2[pos]); + buffers2.erase(buffers2.begin()+pos); + } + + //bool ok = free_memory == a.get_free_memory() && + //a.all_memory_deallocated() && a.check_sanity(); + //if(!ok) return ok; + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated(); +} + +//This test allocates multiple values until there is no more memory +//and after that deallocates all in the inverse order + +bool test_many_different_allocation() +{ + dlmalloc_malloc_check(); + const std::size_t ArraySize = 11; + std::size_t requested_sizes[ArraySize]; + for(std::size_t i = 0; i < ArraySize; ++i){ + requested_sizes[i] = 4*i; + } + + for( deallocation_type t = DirectDeallocation + ; t != EndDeallocationType + ; t = (deallocation_type)((int)t + 1)){ + //std::size_t free_memory = a.get_free_memory(); + + std::vector buffers2; + + //Allocate buffers with extra memory + for(int i = 0; i != NumIt; ++i){ + void *ptr = dlmalloc_malloc(i); + if(!ptr) + break; + buffers2.push_back(ptr); + } + + //Now deallocate the half of the blocks + //so expand maybe can merge new free blocks + for(int i = 0, max = (int)buffers2.size() + ;i < max + ;++i){ + if(i%2){ + dlmalloc_free(buffers2[i]); + buffers2[i] = 0; + } + } + + std::vector buffers; + for(int i = 0; i != NumIt; ++i){ + dlmalloc_memchain chain; + BOOST_CONTAINER_MEMCHAIN_INIT(&chain); + dlmalloc_multialloc_arrays(ArraySize, requested_sizes, 1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); + if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) + break; + std::size_t n = 0; + for(; !BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it); ++n){ + buffers.push_back(BOOST_CONTAINER_MEMIT_ADDR(it)); + BOOST_CONTAINER_MEMIT_NEXT(it); + } + if(n != ArraySize) + return false; + } + + switch(t){ + case DirectDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + dlmalloc_free(buffers[j]); + } + } + break; + case InverseDeallocation: + { + for(int j = (int)buffers.size() + ;j-- + ;){ + dlmalloc_free(buffers[j]); + } + } + break; + case MixedDeallocation: + { + for(int j = 0, max = (int)buffers.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers.size())/4; + dlmalloc_free(buffers[pos]); + buffers.erase(buffers.begin()+pos); + } + } + break; + default: + break; + } + + //Deallocate the rest of the blocks + + //Deallocate it in non sequential order + for(int j = 0, max = (int)buffers2.size() + ;j < max + ;++j){ + int pos = (j%4)*((int)buffers2.size())/4; + dlmalloc_free(buffers2[pos]); + buffers2.erase(buffers2.begin()+pos); + } + + //bool ok = free_memory == a.get_free_memory() && + //a.all_memory_deallocated() && a.check_sanity(); + //if(!ok) return ok; + } + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated(); +} + +bool test_many_deallocation() +{ + const std::size_t ArraySize = 11; + std::vector buffers; + std::size_t requested_sizes[ArraySize]; + for(std::size_t i = 0; i < ArraySize; ++i){ + requested_sizes[i] = 4*i; + } + + for(int i = 0; i != NumIt; ++i){ + dlmalloc_memchain chain; + BOOST_CONTAINER_MEMCHAIN_INIT(&chain); + dlmalloc_multialloc_arrays(ArraySize, requested_sizes, 1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); + if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) + return false; + buffers.push_back(chain); + } + for(int i = 0; i != NumIt; ++i){ + dlmalloc_multidealloc(&buffers[i]); + } + buffers.clear(); + + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) + return false; + + for(int i = 0; i != NumIt; ++i){ + dlmalloc_memchain chain; + BOOST_CONTAINER_MEMCHAIN_INIT(&chain); + dlmalloc_multialloc_nodes(ArraySize, i*4+1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); + dlmalloc_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&chain); + if(BOOST_CONTAINER_MEMCHAIN_IS_END_IT(chain, it)) + return false; + buffers.push_back(chain); + } + for(int i = 0; i != NumIt; ++i){ + dlmalloc_multidealloc(&buffers[i]); + } + buffers.clear(); + + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) + return false; + + return true; +} + +//This function calls all tests + +bool test_all_allocation() +{ + std::cout << "Starting test_allocation" + << std::endl; + + if(!test_allocation()){ + std::cout << "test_allocation_direct_deallocation failed" + << std::endl; + return false; + } + + std::cout << "Starting test_many_equal_allocation" + << std::endl; + + if(!test_many_equal_allocation()){ + std::cout << "test_many_equal_allocation failed" + << std::endl; + return false; + } + + std::cout << "Starting test_many_different_allocation" + << std::endl; + + if(!test_many_different_allocation()){ + std::cout << "test_many_different_allocation failed" + << std::endl; + return false; + } + + std::cout << "Starting test_allocation_shrink" + << std::endl; + + if(!test_allocation_shrink()){ + std::cout << "test_allocation_shrink failed" + << std::endl; + return false; + } + + if(!test_allocation_shrink_and_expand()){ + std::cout << "test_allocation_shrink_and_expand failed" + << std::endl; + return false; + } + + std::cout << "Starting test_allocation_expand" + << std::endl; + + if(!test_allocation_expand()){ + std::cout << "test_allocation_expand failed" + << std::endl; + return false; + } + + std::cout << "Starting test_allocation_deallocation_expand" + << std::endl; + + if(!test_allocation_deallocation_expand()){ + std::cout << "test_allocation_deallocation_expand failed" + << std::endl; + return false; + } + + std::cout << "Starting test_allocation_with_reuse" + << std::endl; + + if(!test_allocation_with_reuse()){ + std::cout << "test_allocation_with_reuse failed" + << std::endl; + return false; + } + + std::cout << "Starting test_aligned_allocation" + << std::endl; + + if(!test_aligned_allocation()){ + std::cout << "test_aligned_allocation failed" + << std::endl; + return false; + } + + std::cout << "Starting test_continuous_aligned_allocation" + << std::endl; + + if(!test_continuous_aligned_allocation()){ + std::cout << "test_continuous_aligned_allocation failed" + << std::endl; + return false; + } + + if(!test_many_deallocation()){ + std::cout << "test_many_deallocation failed" + << std::endl; + return false; + } + + return 0 != dlmalloc_all_deallocated(); +} + +}}} //namespace boost { namespace container { namespace test { + + +int main() +{ + if(!boost::container::test::test_all_allocation()) + return 1; + return 0; +} diff --git a/src/boost/libs/container/test/allocator_argument_tester.hpp b/src/boost/libs/container/test/allocator_argument_tester.hpp new file mode 100644 index 00000000..73993285 --- /dev/null +++ b/src/boost/libs/container/test/allocator_argument_tester.hpp @@ -0,0 +1,233 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_ALLOCATOR_ARGUMENT_TESTER_HPP +#define BOOST_CONTAINER_TEST_ALLOCATOR_ARGUMENT_TESTER_HPP + +#include +#include +#include + +template +class propagation_test_allocator +{ + BOOST_COPYABLE_AND_MOVABLE(propagation_test_allocator) + public: + + template + struct rebind + { + typedef propagation_test_allocator other; + }; + + typedef boost::container::dtl::bool_ propagate_on_container_copy_assignment; + typedef boost::container::dtl::bool_ propagate_on_container_move_assignment; + typedef boost::container::dtl::bool_ propagate_on_container_swap; + typedef boost::container::dtl::bool_ is_always_equal; + typedef T value_type; + + propagation_test_allocator() + : m_move_contructed(false), m_move_assigned(false) + {} + + propagation_test_allocator(const propagation_test_allocator&) + : m_move_contructed(false), m_move_assigned(false) + {} + + propagation_test_allocator(BOOST_RV_REF(propagation_test_allocator) ) + : m_move_contructed(true), m_move_assigned(false) + {} + + template + propagation_test_allocator(BOOST_RV_REF_BEG propagation_test_allocator BOOST_RV_REF_END) + : m_move_contructed(true), m_move_assigned(false) + {} + + template + propagation_test_allocator(const propagation_test_allocator &) + {} + + propagation_test_allocator & operator=(BOOST_COPY_ASSIGN_REF(propagation_test_allocator)) + { + return *this; + } + + propagation_test_allocator & operator=(BOOST_RV_REF(propagation_test_allocator)) + { + m_move_assigned = true; + return *this; + } + + std::size_t max_size() const + { return std::size_t(-1); } + + T* allocate(std::size_t n) + { return (T*)::new char[n*sizeof(T)]; } + + void deallocate(T*p, std::size_t) + { delete []static_cast(static_cast(p)); } + + bool m_move_contructed; + bool m_move_assigned; +}; + +template +bool operator==( const propagation_test_allocator& + , const propagation_test_allocator&) +{ return true; } + +template +bool operator!=( const propagation_test_allocator& + , const propagation_test_allocator&) +{ return false; } + +//This enum lists the construction options +//for an allocator-aware type +enum ConstructionTypeEnum +{ + ConstructiblePrefix, + ConstructibleSuffix, + NotUsesAllocator +}; + +//This base class provices types for +//the derived class to implement each construction +//type. If a construction type does not apply +//the typedef is set to an internal nat +//so that the class is not constructible from +//the user arguments. +template +struct uses_allocator_base; + +template +struct uses_allocator_base +{ + typedef propagation_test_allocator allocator_type; + typedef allocator_type allocator_constructor_type; + struct nat{}; + typedef nat allocator_arg_type; +}; + +template +struct uses_allocator_base +{ + typedef propagation_test_allocator allocator_type; + typedef allocator_type allocator_constructor_type; + typedef boost::container::allocator_arg_t allocator_arg_type; +}; + +template +struct uses_allocator_base +{ + struct nat{}; + typedef nat allocator_constructor_type; + typedef nat allocator_arg_type; +}; + +template +struct allocator_argument_tester + : uses_allocator_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(allocator_argument_tester) + + public: + + typedef uses_allocator_base base_type; + + //0 user argument constructors + allocator_argument_tester() + : construction_type(NotUsesAllocator), value(0) + {} + + explicit allocator_argument_tester + (typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(0) + {} + + explicit allocator_argument_tester + (typename base_type::allocator_arg_type, typename base_type::allocator_constructor_type) + : construction_type(ConstructiblePrefix), value(0) + {} + + //1 user argument constructors + explicit allocator_argument_tester(int i) + : construction_type(NotUsesAllocator), value(i) + {} + + allocator_argument_tester + (int i, typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(i) + {} + + allocator_argument_tester + ( typename base_type::allocator_arg_type + , typename base_type::allocator_constructor_type + , int i) + : construction_type(ConstructiblePrefix), value(i) + {} + + //Copy constructors + allocator_argument_tester(const allocator_argument_tester &other) + : construction_type(NotUsesAllocator), value(other.value) + {} + + allocator_argument_tester( const allocator_argument_tester &other + , typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(other.value) + {} + + allocator_argument_tester( typename base_type::allocator_arg_type + , typename base_type::allocator_constructor_type + , const allocator_argument_tester &other) + : construction_type(ConstructiblePrefix), value(other.value) + {} + + //Move constructors + allocator_argument_tester(BOOST_RV_REF(allocator_argument_tester) other) + : construction_type(NotUsesAllocator), value(other.value) + { other.value = 0; other.construction_type = NotUsesAllocator; } + + allocator_argument_tester( BOOST_RV_REF(allocator_argument_tester) other + , typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(other.value) + { other.value = 0; other.construction_type = ConstructibleSuffix; } + + allocator_argument_tester( typename base_type::allocator_arg_type + , typename base_type::allocator_constructor_type + , BOOST_RV_REF(allocator_argument_tester) other) + : construction_type(ConstructiblePrefix), value(other.value) + { other.value = 0; other.construction_type = ConstructiblePrefix; } + + ConstructionTypeEnum construction_type; + int value; +}; + +namespace boost { +namespace container { + +template +struct constructible_with_allocator_prefix + < ::allocator_argument_tester > +{ + static const bool value = true; +}; + +template +struct constructible_with_allocator_suffix + < ::allocator_argument_tester > +{ + static const bool value = true; +}; + +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_TEST_ALLOCATOR_ARGUMENT_TESTER_HPP diff --git a/src/boost/libs/container/test/allocator_traits_test.cpp b/src/boost/libs/container/test/allocator_traits_test.cpp new file mode 100644 index 00000000..40144241 --- /dev/null +++ b/src/boost/libs/container/test/allocator_traits_test.cpp @@ -0,0 +1,447 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include + +template +class SimpleAllocator +{ + public: + bool allocate_called_; + bool deallocate_called_; + + typedef boost::container::dtl:: + true_type is_always_equal; + + typedef T value_type; + + template + SimpleAllocator(SimpleAllocator) + : allocate_called_(false) + , deallocate_called_(false) + {} + + SimpleAllocator() + : allocate_called_(false) + , deallocate_called_(false) + {} + + T* allocate(std::size_t) + { allocate_called_ = true; return 0; } + + void deallocate(T*, std::size_t) + { deallocate_called_ = true; } + + bool allocate_called() const + { return allocate_called_; } + + bool deallocate_called() const + { return deallocate_called_; } + + friend bool operator==(const SimpleAllocator &, const SimpleAllocator &) + { return true; } + + friend bool operator!=(const SimpleAllocator &, const SimpleAllocator &) + { return false; } +}; + +template +class SimpleSmartPtr +{ + void unspecified_bool_type_func() const {} + typedef void (SimpleSmartPtr::*unspecified_bool_type)() const; + + public: + + typedef T* pointer; + + explicit SimpleSmartPtr(pointer p = 0) + : ptr_(p) + {} + + SimpleSmartPtr(const SimpleSmartPtr &c) + { this->ptr_ = c.ptr_; } + + SimpleSmartPtr & operator=(const SimpleSmartPtr &c) + { this->ptr_ = c.ptr_; } + + operator unspecified_bool_type() const + { return ptr_? &SimpleSmartPtr::unspecified_bool_type_func : 0; } + + private: + T *ptr_; +}; + +template +class ComplexAllocator +{ + public: + bool allocate_called_; + bool deallocate_called_; + bool allocate_hint_called_; + bool destroy_called_; + mutable bool max_size_called_; + mutable bool select_on_container_copy_construction_called_; + bool construct_called_; + mutable bool storage_is_unpropagable_; + + typedef T value_type; + typedef SimpleSmartPtr pointer; + typedef SimpleSmartPtr const_pointer; + typedef typename ::boost::container:: + dtl::unvoid_ref::type reference; + typedef typename ::boost::container:: + dtl::unvoid_ref::type const_reference; + typedef SimpleSmartPtr void_pointer; + typedef SimpleSmartPtr const_void_pointer; + typedef signed short difference_type; + typedef unsigned short size_type; + typedef boost::container::dtl:: + true_type propagate_on_container_copy_assignment; + typedef boost::container::dtl:: + true_type propagate_on_container_move_assignment; + typedef boost::container::dtl:: + true_type propagate_on_container_swap; + typedef boost::container::dtl:: + true_type is_partially_propagable; + + ComplexAllocator() + : allocate_called_(false) + , deallocate_called_(false) + , allocate_hint_called_(false) + , destroy_called_(false) + , max_size_called_(false) + , select_on_container_copy_construction_called_(false) + , construct_called_(false) + {} + + pointer allocate(size_type) + { allocate_called_ = true; return pointer(); } + + void deallocate(pointer, size_type) + { deallocate_called_ = true; } + + //optional + ComplexAllocator select_on_container_copy_construction() const + { select_on_container_copy_construction_called_ = true; return *this; } + + pointer allocate(size_type n, const const_void_pointer &) + { allocate_hint_called_ = true; return allocate(n); } + + template + void destroy(U*) + { destroy_called_ = true; } + + size_type max_size() const + { max_size_called_ = true; return size_type(size_type(0)-1); } + + #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #define BOOST_CONTAINER_COMPLEXALLOCATOR_CONSTRUCT_IMPL(N)\ + \ + template< class U BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \ + void construct(U *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ + { construct_called_ = true; ::new(p) U ( BOOST_MOVE_FWD##N ); }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_COMPLEXALLOCATOR_CONSTRUCT_IMPL) + #undef BOOST_CONTAINER_COMPLEXALLOCATOR_CONSTRUCT_IMPL + #else + + template< class U, class ...Args> + void construct(U *p, BOOST_FWD_REF(Args) ...args) + { construct_called_ = true; ::new(p) U( ::boost::forward(args)...); } + + #endif + + template + void construct(U *p, boost::container::default_init_t) + { construct_called_ = true; ::new(p)U; } + + bool storage_is_unpropagable(pointer p) const + { storage_is_unpropagable_ = true; return !p; } + + //getters + bool allocate_called() const + { return allocate_called_; } + + bool deallocate_called() const + { return deallocate_called_; } + + bool allocate_hint_called() const + { return allocate_hint_called_; } + + bool destroy_called() const + { return destroy_called_; } + + bool max_size_called() const + { return max_size_called_; } + + bool select_on_container_copy_construction_called() const + { return select_on_container_copy_construction_called_; } + + bool construct_called() const + { return construct_called_; } + + bool storage_is_unpropagable_called() const + { return storage_is_unpropagable_; } +}; + +class copymovable +{ + BOOST_COPYABLE_AND_MOVABLE(copymovable) + + public: + + bool copymoveconstructed_; + bool moved_; + + copymovable(int, int, int) + : copymoveconstructed_(false), moved_(false) + {} + + copymovable() + : copymoveconstructed_(false), moved_(false) + {} + + copymovable(const copymovable &) + : copymoveconstructed_(true), moved_(false) + {} + + copymovable(BOOST_RV_REF(copymovable)) + : copymoveconstructed_(true), moved_(true) + {} + + copymovable & operator=(BOOST_COPY_ASSIGN_REF(copymovable) ){ return *this; } + copymovable & operator=(BOOST_RV_REF(copymovable) ){ return *this; } + + bool copymoveconstructed() const + { return copymoveconstructed_; } + + bool moved() const + { return moved_; } +}; + +void test_void_allocator() +{ + boost::container::allocator_traits > stdtraits; (void)stdtraits; + boost::container::allocator_traits > simtraits; (void)simtraits; + boost::container::allocator_traits > comtraits; (void)comtraits; +} + +int main() +{ + using namespace boost::container::dtl; + test_void_allocator(); + + //SimpleAllocator + BOOST_STATIC_ASSERT(( is_same >::value_type, int>::value )); + BOOST_STATIC_ASSERT(( is_same >::pointer, int*>::value )); + BOOST_STATIC_ASSERT(( is_same >::const_pointer, const int*>::value )); + BOOST_STATIC_ASSERT(( is_same >::void_pointer, void*>::value )); + BOOST_STATIC_ASSERT(( is_same >::const_void_pointer, const void*>::value )); + BOOST_STATIC_ASSERT(( is_same >::difference_type, std::ptrdiff_t>::value )); + BOOST_STATIC_ASSERT(( is_same >::size_type, std::size_t>::value )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::propagate_on_container_copy_assignment::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::propagate_on_container_move_assignment::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::propagate_on_container_swap::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::is_always_equal::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < SimpleAllocator >::is_partially_propagable::value == false )); + BOOST_STATIC_ASSERT(( is_same >::rebind_traits::allocator_type + , SimpleAllocator >::value )); + BOOST_STATIC_ASSERT(( is_same >::rebind_alloc::value_type + , double >::value )); + + //ComplexAllocator + BOOST_STATIC_ASSERT(( is_same >::value_type, int>::value )); + BOOST_STATIC_ASSERT(( is_same >::pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( is_same >::const_pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( is_same >::void_pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( is_same >::const_void_pointer, SimpleSmartPtr >::value )); + BOOST_STATIC_ASSERT(( is_same >::difference_type, signed short>::value )); + BOOST_STATIC_ASSERT(( is_same >::size_type, unsigned short>::value )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::propagate_on_container_copy_assignment::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::propagate_on_container_move_assignment::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::propagate_on_container_swap::value == true )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::is_always_equal::value == false )); + BOOST_STATIC_ASSERT(( boost::container::allocator_traits + < ComplexAllocator >::is_partially_propagable::value == true )); + BOOST_STATIC_ASSERT(( is_same >::rebind_traits::allocator_type + , ComplexAllocator >::value )); + BOOST_STATIC_ASSERT(( is_same >::rebind_alloc::value_type + , double >::value )); + + typedef ComplexAllocator CAlloc; + typedef SimpleAllocator SAlloc; + typedef boost::container::allocator_traits CAllocTraits; + typedef boost::container::allocator_traits SAllocTraits; + CAlloc c_alloc; + SAlloc s_alloc; + + //allocate + CAllocTraits::allocate(c_alloc, 1); + BOOST_TEST(c_alloc.allocate_called()); + + SAllocTraits::allocate(s_alloc, 1); + BOOST_TEST(s_alloc.allocate_called()); + + //deallocate + CAllocTraits::deallocate(c_alloc, CAllocTraits::pointer(), 1); + BOOST_TEST(c_alloc.deallocate_called()); + + SAllocTraits::deallocate(s_alloc, SAllocTraits::pointer(), 1); + BOOST_TEST(s_alloc.deallocate_called()); + + //allocate with hint + CAllocTraits::allocate(c_alloc, 1, CAllocTraits::const_void_pointer()); + BOOST_TEST(c_alloc.allocate_hint_called()); + + s_alloc.allocate_called_ = false; + SAllocTraits::allocate(s_alloc, 1, SAllocTraits::const_void_pointer()); + BOOST_TEST(s_alloc.allocate_called()); + + //destroy + float dummy; + CAllocTraits::destroy(c_alloc, &dummy); + BOOST_TEST(c_alloc.destroy_called()); + + SAllocTraits::destroy(s_alloc, &dummy); + + //max_size + CAllocTraits::max_size(c_alloc); + BOOST_TEST(c_alloc.max_size_called()); + + BOOST_TEST(SAllocTraits::size_type(-1)/sizeof(SAllocTraits::value_type) == SAllocTraits::max_size(s_alloc)); + + //select_on_container_copy_construction + CAllocTraits::select_on_container_copy_construction(c_alloc); + BOOST_TEST(c_alloc.select_on_container_copy_construction_called()); + + SAllocTraits::select_on_container_copy_construction(s_alloc); + + //construct + { + copymovable c; + c.copymoveconstructed_ = true; + c.copymoveconstructed_ = true; + CAllocTraits::construct(c_alloc, &c); + BOOST_TEST(c_alloc.construct_called() && !c.copymoveconstructed() && !c.moved()); + } + { + int i = 5; + CAllocTraits::construct(c_alloc, &i, boost::container::default_init); + BOOST_TEST(c_alloc.construct_called() && i == 5); + } + { + copymovable c; + copymovable c2; + CAllocTraits::construct(c_alloc, &c, c2); + BOOST_TEST(c_alloc.construct_called() && c.copymoveconstructed() && !c.moved()); + } + { + copymovable c; + copymovable c2; + CAllocTraits::construct(c_alloc, &c, ::boost::move(c2)); + BOOST_TEST(c_alloc.construct_called() && c.copymoveconstructed() && c.moved()); + } + { + copymovable c; + c.copymoveconstructed_ = true; + c.copymoveconstructed_ = true; + SAllocTraits::construct(s_alloc, &c); + BOOST_TEST(!c.copymoveconstructed() && !c.moved()); + } + { + int i = 4; + SAllocTraits::construct(s_alloc, &i, boost::container::default_init); + BOOST_TEST(i == 4); + } + { + copymovable c; + copymovable c2; + SAllocTraits::construct(s_alloc, &c, c2); + BOOST_TEST(c.copymoveconstructed() && !c.moved()); + } + { + copymovable c; + copymovable c2; + SAllocTraits::construct(s_alloc, &c, ::boost::move(c2)); + BOOST_TEST(c.copymoveconstructed() && c.moved()); + } + { + copymovable c; + CAllocTraits::construct(c_alloc, &c, 0, 1, 2); + BOOST_TEST(c_alloc.construct_called() && !c.copymoveconstructed() && !c.moved()); + } + { + copymovable c; + copymovable c2; + SAllocTraits::construct(s_alloc, &c, 0, 1, 2); + BOOST_TEST(!c.copymoveconstructed() && !c.moved()); + } + //storage_is_unpropagable + { + SAlloc s_alloc2; + BOOST_TEST(!SAllocTraits::storage_is_unpropagable(s_alloc, SAllocTraits::pointer())); + } + { + { + CAlloc c_alloc2; + CAlloc::value_type v; + BOOST_TEST(!CAllocTraits::storage_is_unpropagable(c_alloc, CAllocTraits::pointer(&v))); + BOOST_TEST(c_alloc.storage_is_unpropagable_called()); + } + { + CAlloc c_alloc2; + BOOST_TEST( CAllocTraits::storage_is_unpropagable(c_alloc2, CAllocTraits::pointer())); + BOOST_TEST(c_alloc2.storage_is_unpropagable_called()); + } + + } + + return ::boost::report_errors(); +} +#include diff --git a/src/boost/libs/container/test/check_equal_containers.hpp b/src/boost/libs/container/test/check_equal_containers.hpp new file mode 100644 index 00000000..758780a7 --- /dev/null +++ b/src/boost/libs/container/test/check_equal_containers.hpp @@ -0,0 +1,159 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP +#define BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost{ +namespace container { +namespace test{ + +template< class T1, class T2> +bool CheckEqual( const T1 &t1, const T2 &t2 + , typename boost::container::dtl::enable_if_c + ::value && + !boost::container::dtl::is_pair::value + >::type* = 0) +{ return t1 == t2; } + + +template +bool CheckEqualIt( const T1 &i1, const T2 &i2, const C1 &c1, const C2 &c2 ) +{ + bool c1end = i1 == c1.end(); + bool c2end = i2 == c2.end(); + if( c1end != c2end ){ + return false; + } + else if(c1end){ + return true; + } + else{ + return CheckEqual(*i1, *i2); + } +} + +template< class Pair1, class Pair2> +bool CheckEqual( const Pair1 &pair1, const Pair2 &pair2 + , typename boost::container::dtl::enable_if_c + ::value && + boost::container::dtl::is_pair::value + >::type* = 0) +{ + return CheckEqual(pair1.first, pair2.first) && CheckEqual(pair1.second, pair2.second); +} + +//Function to check if both containers are equal +template +bool CheckEqualContainers(const ContA &cont_a, const ContB &cont_b) +{ + if(cont_a.size() != cont_b.size()) + return false; + + typename ContA::const_iterator itcont_a(cont_a.begin()), itcont_a_end(cont_a.end()); + typename ContB::const_iterator itcont_b(cont_b.begin()), itcont_b_end(cont_b.end());; + typename ContB::size_type dist = (typename ContB::size_type)boost::container::iterator_distance(itcont_a, itcont_a_end); + if(dist != cont_a.size()){ + return false; + } + typename ContA::size_type dist2 = (typename ContA::size_type)boost::container::iterator_distance(itcont_b, itcont_b_end); + if(dist2 != cont_b.size()){ + return false; + } + std::size_t i = 0; + for(; itcont_a != itcont_a_end; ++itcont_a, ++itcont_b, ++i){ + if(!CheckEqual(*itcont_a, *itcont_b)) + return false; + } + return true; +} + +template +bool CheckEqualPairContainers(const MyBoostCont &boostcont, const MyStdCont &stdcont) +{ + if(boostcont.size() != stdcont.size()) + return false; + + typedef typename MyBoostCont::key_type key_type; + typedef typename MyBoostCont::mapped_type mapped_type; + + typename MyBoostCont::const_iterator itboost(boostcont.begin()), itboostend(boostcont.end()); + typename MyStdCont::const_iterator itstd(stdcont.begin()); + for(; itboost != itboostend; ++itboost, ++itstd){ + key_type k(itstd->first); + if(itboost->first != k) + return false; + + mapped_type m(itstd->second); + if(itboost->second != m) + return false; + } + return true; +} + +struct less_transparent +{ + typedef void is_transparent; + + template + bool operator()(const T &t, const U &u) const + { + return t < u; + } +}; + +struct equal_transparent +{ + typedef void is_transparent; + + template + bool operator()(const T &t, const U &u) const + { + return t == u; + } +}; + +struct move_op +{ + template + typename boost::move_detail::add_rvalue_reference::type operator()(T &t) + { + return boost::move(t); + } +}; + +struct const_ref_op +{ + template + const T & operator()(const T &t) + { + return t; + } + +}; + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_CONTAINER_TEST_CHECK_EQUAL_CONTAINER_HPP diff --git a/src/boost/libs/container/test/comparison_test.hpp b/src/boost/libs/container/test/comparison_test.hpp new file mode 100644 index 00000000..7f3f1b3a --- /dev/null +++ b/src/boost/libs/container/test/comparison_test.hpp @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_COMPARISON_TEST_HPP +#define BOOST_CONTAINER_TEST_COMPARISON_TEST_HPP + +#include +#include + +namespace boost { +namespace container { +namespace test { + + +template +bool test_container_comparisons() +{ + typedef typename Cont::value_type value_type; + + Cont cont; + cont.push_back(value_type(1)); + cont.push_back(value_type(2)); + cont.push_back(value_type(3)); + + Cont cont_equal(cont); + + Cont cont_less; + cont_less.push_back(value_type(1)); + cont_less.push_back(value_type(2)); + cont_less.push_back(value_type(2)); + + BOOST_TEST(cont == cont_equal); + BOOST_TEST(!(cont != cont_equal)); + BOOST_TEST(cont != cont_less); + BOOST_TEST(cont_less < cont); + BOOST_TEST(cont_less <= cont); + BOOST_TEST(!(cont_less > cont)); + BOOST_TEST(!(cont_less >= cont)); + BOOST_TEST(!(cont < cont_less)); + BOOST_TEST(!(cont <= cont_less)); + BOOST_TEST(cont > cont_less); + BOOST_TEST(cont >= cont_less); + + return ::boost::report_errors() == 0; +} + +} //namespace test { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_TEST_COMPARISON_TEST_HPP diff --git a/src/boost/libs/container/test/container_common_tests.hpp b/src/boost/libs/container/test/container_common_tests.hpp new file mode 100644 index 00000000..63e15477 --- /dev/null +++ b/src/boost/libs/container/test/container_common_tests.hpp @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_CONTAINER_COMMON_TESTS_HPP +#define BOOST_CONTAINER_TEST_CONTAINER_COMMON_TESTS_HPP + +#include + +namespace boost{ +namespace container { +namespace test{ + + +template +const Container &as_const(Container &c) +{ return c; } + +//nth, index_of +template +bool test_nth_index_of(Container &c) +{ + typename Container::iterator it; + typename Container::const_iterator cit; + typename Container::size_type sz, csz; + //index 0 + it = c.nth(0); + sz = c.index_of(it); + cit = (as_const)(c).nth(0); + csz = (as_const)(c).index_of(cit); + + if(it != c.begin()) + return false; + if(cit != c.cbegin()) + return false; + if(sz != 0) + return false; + if(csz != 0) + return false; + + //index size()/2 + const typename Container::size_type sz_div_2 = c.size()/2; + it = c.nth(sz_div_2); + sz = c.index_of(it); + cit = (as_const)(c).nth(sz_div_2); + csz = (as_const)(c).index_of(cit); + + if(it != (c.begin()+sz_div_2)) + return false; + if(cit != (c.cbegin()+sz_div_2)) + return false; + if(sz != sz_div_2) + return false; + if(csz != sz_div_2) + return false; + + //index size() + it = c.nth(c.size()); + sz = c.index_of(it); + cit = (as_const)(c).nth(c.size()); + csz = (as_const)(c).index_of(cit); + + if(it != c.end()) + return false; + if(cit != c.cend()) + return false; + if(sz != c.size()) + return false; + if(csz != c.size()) + return false; + return true; +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_CONTAINER_TEST_CONTAINER_COMMON_TESTS_HPP diff --git a/src/boost/libs/container/test/default_init_test.hpp b/src/boost/libs/container/test/default_init_test.hpp new file mode 100644 index 00000000..2e83a361 --- /dev/null +++ b/src/boost/libs/container/test/default_init_test.hpp @@ -0,0 +1,155 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_DEFAULT_INIT_TEST_HEADER +#define BOOST_CONTAINER_TEST_DEFAULT_INIT_TEST_HEADER + +#include +#include + +namespace boost{ +namespace container { +namespace test{ + +// +template +class default_init_allocator_base +{ + protected: + static unsigned char s_pattern; + static bool s_ascending; + + public: + static void reset_pattern(unsigned char value) + { s_pattern = value; } + + static void set_ascending(bool enable) + { s_ascending = enable; } +}; + +template +unsigned char default_init_allocator_base::s_pattern = 0u; + +template +bool default_init_allocator_base::s_ascending = true; + +template +class default_init_allocator + : public default_init_allocator_base<0> +{ + typedef default_init_allocator_base<0> base_t; + public: + typedef Integral value_type; + + default_init_allocator() + {} + + template + default_init_allocator(default_init_allocator) + {} + + Integral* allocate(std::size_t n) + { + //Initialize memory to a pattern + const std::size_t max = sizeof(Integral)*n; + unsigned char *puc_raw = ::new unsigned char[max]; + + if(base_t::s_ascending){ + for(std::size_t i = 0; i != max; ++i){ + puc_raw[i] = static_cast(s_pattern++); + } + } + else{ + for(std::size_t i = 0; i != max; ++i){ + puc_raw[i] = static_cast(s_pattern--); + } + } + return (Integral*)puc_raw;; + } + + void deallocate(Integral *p, std::size_t) + { delete[] (unsigned char*)p; } +}; + +template +inline bool check_ascending_byte_pattern(const Integral&t) +{ + const unsigned char *pch = &reinterpret_cast(t); + const std::size_t max = sizeof(Integral); + for(std::size_t i = 1; i != max; ++i){ + if( (pch[i-1] != ((unsigned char)(pch[i]-1u))) ){ + return false; + } + } + return true; +} + +template +inline bool check_descending_byte_pattern(const Integral&t) +{ + const unsigned char *pch = &reinterpret_cast(t); + const std::size_t max = sizeof(Integral); + for(std::size_t i = 1; i != max; ++i){ + if( (pch[i-1] != ((unsigned char)(pch[i]+1u))) ){ + return false; + } + } + return true; +} + +template +bool default_init_test()//Test for default initialization +{ + const std::size_t Capacity = 100; + + { + test::default_init_allocator::reset_pattern(0); + test::default_init_allocator::set_ascending(true); + IntDefaultInitAllocVector v(Capacity, default_init); + typename IntDefaultInitAllocVector::iterator it = v.begin(); + //Compare with the pattern + for(std::size_t i = 0; i != Capacity; ++i, ++it){ + if(!test::check_ascending_byte_pattern(*it)) + return false; + } + } + { + test::default_init_allocator::reset_pattern(0); + test::default_init_allocator::set_ascending(true); + IntDefaultInitAllocVector v(Capacity, default_init, typename IntDefaultInitAllocVector::allocator_type()); + typename IntDefaultInitAllocVector::iterator it = v.begin(); + //Compare with the pattern + for(std::size_t i = 0; i != Capacity; ++i, ++it){ + if(!test::check_ascending_byte_pattern(*it)) + return false; + } + } + { + test::default_init_allocator::reset_pattern(100); + test::default_init_allocator::set_ascending(false); + IntDefaultInitAllocVector v; + v.resize(Capacity, default_init); + typename IntDefaultInitAllocVector::iterator it = v.begin(); + //Compare with the pattern + for(std::size_t i = 0; i != Capacity; ++i, ++it){ + if(!test::check_descending_byte_pattern(*it)) + return false; + } + } + return true; +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //BOOST_CONTAINER_TEST_DEFAULT_INIT_TEST_HEADER diff --git a/src/boost/libs/container/test/deque_options_test.cpp b/src/boost/libs/container/test/deque_options_test.cpp new file mode 100644 index 00000000..9a7a43ae --- /dev/null +++ b/src/boost/libs/container/test/deque_options_test.cpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +using namespace boost::container; + +void test_block_bytes() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = deque_options_t< block_bytes<128u> >; + #else + typedef deque_options< block_bytes<128u> >::type options_t; + #endif + typedef deque deque_t; + BOOST_TEST(deque_t::get_block_size() == 128u/sizeof(unsigned short)); +} + +void test_block_elements() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = deque_options_t< block_size<64> >; + #else + typedef deque_options< block_size<64 > >::type options_t; + #endif + typedef deque deque_t; + BOOST_TEST(deque_t::get_block_size() == 64U); +} + +int main() +{ + test_block_bytes(); + test_block_elements(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/deque_test.cpp b/src/boost/libs/container/test/deque_test.cpp new file mode 100644 index 00000000..22b87f49 --- /dev/null +++ b/src/boost/libs/container/test/deque_test.cpp @@ -0,0 +1,446 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include "print_container.hpp" +#include "check_equal_containers.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include +#include +#include +#include +#include +#include "emplace_test.hpp" +#include "propagate_allocator_test.hpp" +#include "vector_test.hpp" +#include "default_init_test.hpp" +#include +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +//Function to check if both sets are equal +template +bool deque_copyable_only(V1 &, V2 &, dtl::false_type) +{ + return true; +} + +//Function to check if both sets are equal +template +bool deque_copyable_only(V1 &cntdeque, V2 &stddeque, dtl::true_type) +{ + typedef typename V1::value_type IntType; + std::size_t size = cntdeque.size(); + stddeque.insert(stddeque.end(), 50, 1); + cntdeque.insert(cntdeque.end(), 50, IntType(1)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + { + IntType move_me(1); + stddeque.insert(stddeque.begin()+size/2, 50, 1); + cntdeque.insert(cntdeque.begin()+size/2, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + } + { + IntType move_me(2); + cntdeque.assign(cntdeque.size()/2, boost::move(move_me)); + stddeque.assign(stddeque.size()/2, 2); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + } + { + IntType move_me(1); + stddeque.clear(); + cntdeque.clear(); + stddeque.insert(stddeque.begin(), 50, 1); + cntdeque.insert(cntdeque.begin(), 50, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + stddeque.insert(stddeque.begin()+20, 50, 1); + cntdeque.insert(cntdeque.begin()+20, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + stddeque.insert(stddeque.begin()+20, 20, 1); + cntdeque.insert(cntdeque.begin()+20, 20, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + } + { + IntType move_me(1); + stddeque.clear(); + cntdeque.clear(); + stddeque.insert(stddeque.end(), 50, 1); + cntdeque.insert(cntdeque.end(), 50, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + stddeque.insert(stddeque.end()-20, 50, 1); + cntdeque.insert(cntdeque.end()-20, 50, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + stddeque.insert(stddeque.end()-20, 20, 1); + cntdeque.insert(cntdeque.end()-20, 20, boost::move(move_me)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + } + + return true; +} + +//Test recursive structures +class recursive_deque +{ +public: + + recursive_deque & operator=(const recursive_deque &x) + { this->deque_ = x.deque_; return *this; } + + int id_; + deque deque_; + deque::iterator it_; + deque::const_iterator cit_; + deque::reverse_iterator rit_; + deque::const_reverse_iterator crit_; +}; + +template +bool do_test() +{ + //Test for recursive types + { + deque recursive_deque_deque; + } + + { + //Now test move semantics + deque original; + deque move_ctor(boost::move(original)); + deque move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + + //Alias deque types + typedef deque MyCntDeque; + typedef std::deque MyStdDeque; + const int max = 100; + { + ::boost::movelib::unique_ptr const pcntdeque = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstddeque = ::boost::movelib::make_unique(); + MyCntDeque &cntdeque = *pcntdeque; + MyStdDeque &stddeque = *pstddeque; + for(int i = 0; i < max*100; ++i){ + IntType move_me(i); + cntdeque.insert(cntdeque.end(), boost::move(move_me)); + stddeque.insert(stddeque.end(), i); + } + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + cntdeque.clear(); + stddeque.clear(); + + for(int i = 0; i < max*100; ++i){ + IntType move_me(i); + cntdeque.push_back(boost::move(move_me)); + stddeque.push_back(i); + } + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + cntdeque.clear(); + stddeque.clear(); + + for(int i = 0; i < max*100; ++i){ + IntType move_me(i); + cntdeque.push_front(boost::move(move_me)); + stddeque.push_front(i); + } + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + typename MyCntDeque::iterator it; + typename MyCntDeque::const_iterator cit = it; + (void)cit; + + cntdeque.erase(cntdeque.begin()++); + stddeque.erase(stddeque.begin()++); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + cntdeque.erase(cntdeque.begin()); + stddeque.erase(stddeque.begin()); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + { + //Initialize values + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me (-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + cntdeque.insert(cntdeque.end() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stddeque.insert(stddeque.end(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + for(int i = 0; i < 50; ++i){ + IntType move_me (i); + aux_vect[i] = boost::move(move_me); + } + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i; + } + + cntdeque.insert(cntdeque.begin()+cntdeque.size() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stddeque.insert(stddeque.begin()+stddeque.size(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + for(int i = 0, j = static_cast(cntdeque.size()); i < j; ++i){ + cntdeque.erase(cntdeque.begin()); + stddeque.erase(stddeque.begin()); + } + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + cntdeque.insert(cntdeque.begin() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stddeque.insert(stddeque.begin(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + } + + if(!deque_copyable_only(cntdeque, stddeque + ,dtl::bool_::value>())){ + return false; + } + + cntdeque.erase(cntdeque.begin()); + stddeque.erase(stddeque.begin()); + + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + for(int i = 0; i < max; ++i){ + IntType move_me(i); + cntdeque.insert(cntdeque.begin(), boost::move(move_me)); + stddeque.insert(stddeque.begin(), i); + } + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + //Test insertion from list + { + std::list l(50, int(1)); + cntdeque.insert(cntdeque.begin(), l.begin(), l.end()); + stddeque.insert(stddeque.begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; + cntdeque.assign(l.begin(), l.end()); + stddeque.assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; + } + + cntdeque.resize(100); + stddeque.resize(100); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; + + cntdeque.resize(200); + stddeque.resize(200); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; + } + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //Check Constructor Template Auto Deduction + { + auto gold = MyStdDeque{ 1, 2, 3 }; + auto test = deque(gold.begin(), gold.end()); + if(!test::CheckEqualContainers(gold, test)) return false; + } + { + auto gold = MyStdDeque{ 1, 2, 3 }; + auto test = deque(gold.begin(), gold.end(), new_allocator()); + if(!test::CheckEqualContainers(gold, test)) return false; + } +#endif + + std::cout << std::endl << "Test OK!" << std::endl; + return true; +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef deque< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + return 0; +} + +struct boost_container_deque; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::deque type; + }; +}; + +}}} //namespace boost::container::test + +int main () +{ + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + if(!do_test()) + return 1; + + //Test non-copy-move operations + { + deque d; + d.emplace_back(); + d.emplace_front(1); + d.resize(10); + d.resize(1); + } + + //////////////////////////////////// + // Allocator implementations + //////////////////////////////////// + // std:allocator + if(test_cont_variants< std::allocator >()){ + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + return 1; + } + // boost::container::allocator + if(test_cont_variants< allocator >()){ + std::cerr << "test_cont_variants< allocator > failed" << std::endl; + return 1; + } + //////////////////////////////////// + // Default init test + //////////////////////////////////// + if(!test::default_init_test< deque > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); + + if(!boost::container::test::test_emplace + < deque, Options>()) + return 1; + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Initializer lists testing + //////////////////////////////////// + if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for + < boost::container::deque >()) { + return 1; + } + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::deque cont_int; + cont_int a; a.push_back(0); a.push_back(1); a.push_back(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::deque cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::deque > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} + +#include diff --git a/src/boost/libs/container/test/derived_from_memory_resource.hpp b/src/boost/libs/container/test/derived_from_memory_resource.hpp new file mode 100644 index 00000000..a8097a78 --- /dev/null +++ b/src/boost/libs/container/test/derived_from_memory_resource.hpp @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_DERIVED_FROM_MEMORY_RESOURCE_HPP +#define BOOST_CONTAINER_TEST_DERIVED_FROM_MEMORY_RESOURCE_HPP + +#include + +class derived_from_memory_resource + : public boost::container::pmr::memory_resource +{ + public: + explicit derived_from_memory_resource(unsigned i = 0u) + : id(i) + {} + + virtual ~derived_from_memory_resource() + { destructor_called = true; } + + virtual void* do_allocate(std::size_t bytes, std::size_t alignment) + { + do_allocate_called = true; + do_allocate_bytes = bytes; + do_allocate_alignment = alignment; + return do_allocate_return; + } + + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + { + do_deallocate_called = true; + do_deallocate_p = p; + do_deallocate_bytes = bytes; + do_deallocate_alignment = alignment; + } + + virtual bool do_is_equal(const boost::container::pmr::memory_resource& other) const BOOST_NOEXCEPT + { + do_is_equal_called = true; + do_is_equal_other = &other; + return static_cast(other).id == this->id; + } + + void reset() + { + destructor_called = false; + + do_allocate_return = 0; + do_allocate_called = false; + do_allocate_bytes = 0u; + do_allocate_alignment = 0u; + + do_deallocate_called = false; + do_deallocate_p = 0; + do_deallocate_bytes = 0u; + do_deallocate_alignment = 0u; + + do_is_equal_called = false; + do_is_equal_other = 0; + } + //checkers + static bool destructor_called; + + unsigned id; + void *do_allocate_return; + mutable bool do_allocate_called; + mutable std::size_t do_allocate_bytes; + mutable std::size_t do_allocate_alignment; + + mutable bool do_deallocate_called; + mutable void *do_deallocate_p; + mutable std::size_t do_deallocate_bytes; + mutable std::size_t do_deallocate_alignment; + + mutable bool do_is_equal_called; + mutable const boost::container::pmr::memory_resource *do_is_equal_other; +}; + +bool derived_from_memory_resource::destructor_called = false; + +#endif //#ifndef BOOST_CONTAINER_TEST_DERIVED_FROM_MEMORY_RESOURCE_HPP diff --git a/src/boost/libs/container/test/dummy_test_allocator.hpp b/src/boost/libs/container/test/dummy_test_allocator.hpp new file mode 100644 index 00000000..024ab0e0 --- /dev/null +++ b/src/boost/libs/container/test/dummy_test_allocator.hpp @@ -0,0 +1,232 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DUMMY_TEST_ALLOCATOR_HPP +#define BOOST_CONTAINER_DUMMY_TEST_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace test { + +//Very simple version 1 allocator +template +class simple_allocator +{ + public: + typedef T value_type; + + simple_allocator() + {} + + template + simple_allocator(const simple_allocator &) + {} + + T* allocate(std::size_t n) + { return (T*)::new char[sizeof(T)*n]; } + + void deallocate(T*p, std::size_t) + { delete[] ((char*)p);} + + friend bool operator==(const simple_allocator &, const simple_allocator &) + { return true; } + + friend bool operator!=(const simple_allocator &, const simple_allocator &) + { return false; } +}; + +template< class T + , bool PropagateOnContCopyAssign + , bool PropagateOnContMoveAssign + , bool PropagateOnContSwap + , bool CopyOnPropagateOnContSwap + > +class propagation_test_allocator +{ + BOOST_COPYABLE_AND_MOVABLE(propagation_test_allocator) + + public: + typedef T value_type; + typedef boost::container::dtl::bool_ + propagate_on_container_copy_assignment; + typedef boost::container::dtl::bool_ + propagate_on_container_move_assignment; + typedef boost::container::dtl::bool_ + propagate_on_container_swap; + + template + struct rebind + { typedef propagation_test_allocator + < T2 + , PropagateOnContCopyAssign + , PropagateOnContMoveAssign + , PropagateOnContSwap + , CopyOnPropagateOnContSwap> other; + }; + + propagation_test_allocator select_on_container_copy_construction() const + { return CopyOnPropagateOnContSwap ? propagation_test_allocator(*this) : propagation_test_allocator(); } + + explicit propagation_test_allocator() + : id_(++unique_id_) + , ctr_copies_(0) + , ctr_moves_(0) + , assign_copies_(0) + , assign_moves_(0) + , swaps_(0) + {} + + propagation_test_allocator(const propagation_test_allocator &x) + : id_(x.id_) + , ctr_copies_(x.ctr_copies_+1) + , ctr_moves_(x.ctr_moves_) + , assign_copies_(x.assign_copies_) + , assign_moves_(x.assign_moves_) + , swaps_(x.swaps_) + {} + + template + propagation_test_allocator(const propagation_test_allocator + < U + , PropagateOnContCopyAssign + , PropagateOnContMoveAssign + , PropagateOnContSwap + , CopyOnPropagateOnContSwap> &x) + : id_(x.id_) + , ctr_copies_(x.ctr_copies_+1) + , ctr_moves_(0) + , assign_copies_(0) + , assign_moves_(0) + , swaps_(0) + {} + + propagation_test_allocator(BOOST_RV_REF(propagation_test_allocator) x) + : id_(x.id_) + , ctr_copies_(x.ctr_copies_) + , ctr_moves_(x.ctr_moves_ + 1) + , assign_copies_(x.assign_copies_) + , assign_moves_(x.assign_moves_) + , swaps_(x.swaps_) + {} + + propagation_test_allocator &operator=(BOOST_COPY_ASSIGN_REF(propagation_test_allocator) x) + { + id_ = x.id_; + ctr_copies_ = x.ctr_copies_; + ctr_moves_ = x.ctr_moves_; + assign_copies_ = x.assign_copies_+1; + assign_moves_ = x.assign_moves_; + swaps_ = x.swaps_; + return *this; + } + + propagation_test_allocator &operator=(BOOST_RV_REF(propagation_test_allocator) x) + { + id_ = x.id_; + ctr_copies_ = x.ctr_copies_; + ctr_moves_ = x.ctr_moves_; + assign_copies_ = x.assign_copies_; + assign_moves_ = x.assign_moves_+1; + swaps_ = x.swaps_; + return *this; + } + + static void reset_unique_id(unsigned id = 0) + { unique_id_ = id; } + + T* allocate(std::size_t n) + { return (T*)::new char[sizeof(T)*n]; } + + void deallocate(T*p, std::size_t) + { delete[] ((char*)p);} + + friend bool operator==(const propagation_test_allocator &, const propagation_test_allocator &) + { return true; } + + friend bool operator!=(const propagation_test_allocator &, const propagation_test_allocator &) + { return false; } + + void swap(propagation_test_allocator &r) + { + ++this->swaps_; ++r.swaps_; + boost::adl_move_swap(this->id_, r.id_); + boost::adl_move_swap(this->ctr_copies_, r.ctr_copies_); + boost::adl_move_swap(this->ctr_moves_, r.ctr_moves_); + boost::adl_move_swap(this->assign_copies_, r.assign_copies_); + boost::adl_move_swap(this->assign_moves_, r.assign_moves_); + boost::adl_move_swap(this->swaps_, r.swaps_); + } + + friend void swap(propagation_test_allocator &l, propagation_test_allocator &r) + { + l.swap(r); + } + + unsigned int id_; + unsigned int ctr_copies_; + unsigned int ctr_moves_; + unsigned int assign_copies_; + unsigned int assign_moves_; + unsigned int swaps_; + static unsigned unique_id_; +}; + +template< class T + , bool PropagateOnContCopyAssign + , bool PropagateOnContMoveAssign + , bool PropagateOnContSwap + , bool CopyOnPropagateOnContSwap + > +unsigned int propagation_test_allocator< T + , PropagateOnContCopyAssign + , PropagateOnContMoveAssign + , PropagateOnContSwap + , CopyOnPropagateOnContSwap>::unique_id_ = 0; + + +} //namespace test { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_DUMMY_TEST_ALLOCATOR_HPP + diff --git a/src/boost/libs/container/test/emplace_test.hpp b/src/boost/libs/container/test/emplace_test.hpp new file mode 100644 index 00000000..f017d955 --- /dev/null +++ b/src/boost/libs/container/test/emplace_test.hpp @@ -0,0 +1,686 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_TEST_EMPLACE_TEST_HPP +#define BOOST_CONTAINER_TEST_EMPLACE_TEST_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace container { +namespace test{ + +class EmplaceInt +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(EmplaceInt) + + public: + EmplaceInt(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0) + : a_(a), b_(b), c_(c), d_(d), e_(e) + {} + + EmplaceInt(BOOST_RV_REF(EmplaceInt) o) + : a_(o.a_), b_(o.b_), c_(o.c_), d_(o.d_), e_(o.e_) + {} + + EmplaceInt& operator=(BOOST_RV_REF(EmplaceInt) o) + { + this->a_ = o.a_; + this->b_ = o.b_; + this->c_ = o.c_; + this->d_ = o.d_; + this->e_ = o.e_; + return *this; + } + + friend bool operator==(const EmplaceInt &l, const EmplaceInt &r) + { + return l.a_ == r.a_ && + l.b_ == r.b_ && + l.c_ == r.c_ && + l.d_ == r.d_ && + l.e_ == r.e_; + } + + friend bool operator<(const EmplaceInt &l, const EmplaceInt &r) + { return l.sum() < r.sum(); } + + friend bool operator>(const EmplaceInt &l, const EmplaceInt &r) + { return l.sum() > r.sum(); } + + friend bool operator!=(const EmplaceInt &l, const EmplaceInt &r) + { return !(l == r); } + + friend std::size_t hash_value(const EmplaceInt &v) + { return std::size_t(v.a_); } + + friend std::ostream &operator <<(std::ostream &os, const EmplaceInt &v) + { + os << "EmplaceInt: " << v.a_ << ' ' << v.b_ << ' ' << v.c_ << ' ' << v.d_ << ' ' << v.e_; + return os; + } + + ~EmplaceInt() + { a_ = b_ = c_ = d_ = e_ = 0; } + + //private: + int sum() const + { return this->a_ + this->b_ + this->c_ + this->d_ + this->e_; } + + int a_, b_, c_, d_, e_; + int padding[6]; +}; + + +} //namespace test { + +namespace test { + +enum EmplaceOptions{ + EMPLACE_BACK = 1 << 0, + EMPLACE_FRONT = 1 << 1, + EMPLACE_BEFORE = 1 << 2, + EMPLACE_AFTER = 1 << 3, + EMPLACE_ASSOC = 1 << 4, + EMPLACE_HINT = 1 << 5, + EMPLACE_ASSOC_PAIR = 1 << 6, + EMPLACE_HINT_PAIR = 1 << 7 +}; + +template +bool test_expected_container(const Container &ec, const EmplaceInt *Expected, unsigned int only_first_n, unsigned int cont_offset = 0) +{ + typedef typename Container::const_iterator const_iterator; + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + if(cont_offset > ec.size()){ + return false; + } + if(only_first_n > (ec.size() - cont_offset)){ + return false; + } + while(cont_offset--){ + ++itb; + } + for(; itb != ite && only_first_n--; ++itb, ++cur){ + const EmplaceInt & cr = *itb; + if(cr != Expected[cur]){ + return false; + } + } + return true; +} + +template +bool test_expected_container(const Container &ec, const std::pair *Expected, unsigned int only_first_n) +{ + typedef typename Container::const_iterator const_iterator; + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + if(only_first_n > ec.size()){ + return false; + } + for(; itb != ite && only_first_n--; ++itb, ++cur){ + if(itb->first != Expected[cur].first){ + std::cout << "Error in first: " << itb->first << ' ' << Expected[cur].first << std::endl; + return false; + + } + else if(itb->second != Expected[cur].second){ + std::cout << "Error in second: " << itb->second << ' ' << Expected[cur].second << std::endl; + return false; + } + } + return true; +} + +typedef std::pair EmplaceIntPair; +static boost::container::dtl::aligned_storage::type pair_storage; + +static EmplaceIntPair* initialize_emplace_int_pair() +{ + EmplaceIntPair* ret = reinterpret_cast(&pair_storage); + for(unsigned int i = 0; i != 10; ++i){ + new(&ret->first)EmplaceInt(); + new(&ret->second)EmplaceInt(); + } + return ret; +} + +static EmplaceIntPair * expected_pair = initialize_emplace_int_pair(); + + +template +bool test_emplace_back(dtl::true_) +{ + std::cout << "Starting test_emplace_back." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + static EmplaceInt expected [10]; + + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + Container c; + typedef typename Container::reference reference; + { + reference r = c.emplace_back(); + if(&r != &c.back() && !test_expected_container(c, &expected[0], 1)){ + return false; + } + } + { + reference r = c.emplace_back(1); + if(&r != &c.back() && !test_expected_container(c, &expected[0], 2)){ + return false; + } + } + c.emplace_back(1, 2); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + c.emplace_back(1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)){ + return false; + } + c.emplace_back(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)){ + return false; + } + c.emplace_back(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + } + std::cout << "...OK" << std::endl; + return true; +} + +template +bool test_emplace_back(dtl::false_) +{ return true; } + +template +bool test_emplace_front(dtl::true_) +{ + std::cout << "Starting test_emplace_front." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + static EmplaceInt expected [10]; + { + new(&expected [0]) EmplaceInt(1, 2, 3, 4, 5); + new(&expected [1]) EmplaceInt(1, 2, 3, 4); + new(&expected [2]) EmplaceInt(1, 2, 3); + new(&expected [3]) EmplaceInt(1, 2); + new(&expected [4]) EmplaceInt(1); + new(&expected [5]) EmplaceInt(); + Container c; + typedef typename Container::reference reference; + { + reference r = c.emplace_front(); + if(&r != &c.front() && !test_expected_container(c, &expected[0] + 5, 1)){ + return false; + } + } + { + reference r = c.emplace_front(1); + if(&r != &c.front() && !test_expected_container(c, &expected[0] + 4, 2)){ + return false; + } + } + c.emplace_front(1, 2); + if(!test_expected_container(c, &expected[0] + 3, 3)){ + return false; + } + c.emplace_front(1, 2, 3); + if(!test_expected_container(c, &expected[0] + 2, 4)){ + return false; + } + c.emplace_front(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0] + 1, 5)){ + return false; + } + c.emplace_front(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0] + 0, 6)){ + return false; + } + } + std::cout << "...OK" << std::endl; + return true; +} + +template +bool test_emplace_front(dtl::false_) +{ return true; } + +template +bool test_emplace_before(dtl::true_) +{ + std::cout << "Starting test_emplace_before." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + static EmplaceInt expected [10]; + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(); + Container c; + c.emplace(c.cend(), 1); + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 2)){ + return false; + } + c.emplace(c.cend()); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + } + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + //emplace_front-like + Container c; + c.emplace(c.cbegin(), 1, 2, 3, 4, 5); + c.emplace(c.cbegin(), 1, 2, 3, 4); + c.emplace(c.cbegin(), 1, 2, 3); + c.emplace(c.cbegin(), 1, 2); + c.emplace(c.cbegin(), 1); + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + c.clear(); + //emplace_back-like + typename Container::const_iterator i = c.emplace(c.cend()); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + i = c.emplace(++i, 1); + if(!test_expected_container(c, &expected[0], 2)){ + return false; + } + i = c.emplace(++i, 1, 2); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + i = c.emplace(++i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)){ + return false; + } + i = c.emplace(++i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)){ + return false; + } + i = c.emplace(++i, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + c.clear(); + //emplace in the middle + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + i = c.emplace(c.cend(), 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + if(!test_expected_container(c, &expected[5], 1, 1)){ + return false; + } + i = c.emplace(i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + if(!test_expected_container(c, &expected[4], 2, 1)){ + return false; + } + i = c.emplace(i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + if(!test_expected_container(c, &expected[3], 3, 1)){ + return false; + } + i = c.emplace(i, 1, 2); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + if(!test_expected_container(c, &expected[2], 4, 1)){ + return false; + } + i = c.emplace(i, 1); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + std::cout << "...OK" << std::endl; + } + return true; +} + +template +bool test_emplace_before(dtl::false_) +{ return true; } + +template +bool test_emplace_after(dtl::true_) +{ + std::cout << "Starting test_emplace_after." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + static EmplaceInt expected [10]; + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(); + Container c; + typename Container::const_iterator i = c.emplace_after(c.cbefore_begin(), 1); + c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 2)){ + return false; + } + c.emplace_after(i); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + } + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + //emplace_front-like + Container c; + c.emplace_after(c.cbefore_begin(), 1, 2, 3, 4, 5); + c.emplace_after(c.cbefore_begin(), 1, 2, 3, 4); + c.emplace_after(c.cbefore_begin(), 1, 2, 3); + c.emplace_after(c.cbefore_begin(), 1, 2); + c.emplace_after(c.cbefore_begin(), 1); + c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + c.clear(); + //emplace_back-like + typename Container::const_iterator i = c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + i = c.emplace_after(i, 1); + if(!test_expected_container(c, &expected[0], 2)){ + return false; + } + i = c.emplace_after(i, 1, 2); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + i = c.emplace_after(i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)){ + return false; + } + i = c.emplace_after(i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)){ + return false; + } + i = c.emplace_after(i, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + c.clear(); + //emplace_after in the middle + i = c.emplace_after(c.cbefore_begin()); + c.emplace_after(i, 1, 2, 3, 4, 5); + c.emplace_after(i, 1, 2, 3, 4); + c.emplace_after(i, 1, 2, 3); + c.emplace_after(i, 1, 2); + c.emplace_after(i, 1); + + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + std::cout << "...OK" << std::endl; + } + return true; +} + +template +bool test_emplace_after(dtl::false_) +{ return true; } + +template +bool test_emplace_assoc(dtl::true_) +{ + std::cout << "Starting test_emplace_assoc." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + static EmplaceInt expected [10]; + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + { + Container c; + c.emplace(); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + c.emplace(1); + if(!test_expected_container(c, &expected[0], 2)){ + return false; + } + c.emplace(1, 2); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + c.emplace(1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)){ + return false; + } + c.emplace(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)){ + return false; + } + c.emplace(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + std::cout << "...OK" << std::endl; + } + return true; +} + +template +bool test_emplace_assoc(dtl::false_) +{ return true; } + +template +bool test_emplace_hint(dtl::true_) +{ + std::cout << "Starting test_emplace_hint." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + static EmplaceInt expected [10]; + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + + { + Container c; + typename Container::const_iterator it; + it = c.emplace_hint(c.begin()); + if(!test_expected_container(c, &expected[0], 1)){ + return false; + } + it = c.emplace_hint(it, 1); + if(!test_expected_container(c, &expected[0], 2)){ + return false; + } + it = c.emplace_hint(it, 1, 2); + if(!test_expected_container(c, &expected[0], 3)){ + return false; + } + it = c.emplace_hint(it, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)){ + return false; + } + it = c.emplace_hint(it, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)){ + return false; + } + it = c.emplace_hint(it, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)){ + return false; + } + std::cout << "...OK" << std::endl; + } + + return true; +} + +template +bool test_emplace_hint(dtl::false_) +{ return true; } + +template +bool test_emplace_assoc_pair(dtl::true_) +{ + std::cout << "Starting test_emplace_assoc_pair." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected_pair[0].first) EmplaceInt(); + new(&expected_pair[0].second) EmplaceInt(); + new(&expected_pair[1].first) EmplaceInt(1); + new(&expected_pair[1].second) EmplaceInt(1); + new(&expected_pair[2].first) EmplaceInt(2); + new(&expected_pair[2].second) EmplaceInt(2); + { + Container c; + c.emplace(); + if(!test_expected_container(c, &expected_pair[0], 1)){ + std::cout << "Error after c.emplace();\n"; + return false; + } + c.emplace(1, 1); + if(!test_expected_container(c, &expected_pair[0], 2)){ + std::cout << "Error after c.emplace(1);\n"; + return false; + } + c.emplace(2, 2); + if(!test_expected_container(c, &expected_pair[0], 3)){ + std::cout << "Error after c.emplace(2, 2);\n"; + return false; + } + std::cout << "...OK" << std::endl; + } + return true; +} + +template +bool test_emplace_assoc_pair(dtl::false_) +{ return true; } + +template +bool test_emplace_hint_pair(dtl::true_) +{ + std::cout << "Starting test_emplace_hint_pair." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected_pair[0].first) EmplaceInt(); + new(&expected_pair[0].second) EmplaceInt(); + new(&expected_pair[1].first) EmplaceInt(1); + new(&expected_pair[1].second) EmplaceInt(1); + new(&expected_pair[2].first) EmplaceInt(2); + new(&expected_pair[2].second) EmplaceInt(2); + { + Container c; + typename Container::const_iterator it; + it = c.emplace_hint(c.begin()); + if(!test_expected_container(c, &expected_pair[0], 1)){ + std::cout << "Error after c.emplace(1);\n"; + return false; + } + it = c.emplace_hint(it, 1, 1); + if(!test_expected_container(c, &expected_pair[0], 2)){ + std::cout << "Error after c.emplace(it, 1);\n"; + return false; + } + it = c.emplace_hint(it, 2, 2); + if(!test_expected_container(c, &expected_pair[0], 3)){ + std::cout << "Error after c.emplace(it, 2, 2);\n"; + return false; + } + std::cout << "...OK" << std::endl; + } + return true; +} + +template +bool test_emplace_hint_pair(dtl::false_) +{ return true; } + +template +struct emplace_active +{ + static const bool value = (0 != (O & Mask)); + typedef dtl::bool_ type; + operator type() const{ return type(); } +}; + +template +bool test_emplace() +{ + if(!test_emplace_back(emplace_active())){ + return false; + } + if(!test_emplace_front(emplace_active())){ + return false; + } + if(!test_emplace_before(emplace_active())){ + return false; + } + if(!test_emplace_after(emplace_active())){ + return false; + } + if(!test_emplace_assoc(emplace_active())){ + return false; + } + if(!test_emplace_hint(emplace_active())){ + return false; + } + if(!test_emplace_assoc_pair(emplace_active())){ + return false; + } + if(!test_emplace_hint_pair(emplace_active())){ + return false; + } + return true; +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_CONTAINER_TEST_EMPLACE_TEST_HPP diff --git a/src/boost/libs/container/test/expand_bwd_test_allocator.hpp b/src/boost/libs/container/test/expand_bwd_test_allocator.hpp new file mode 100644 index 00000000..60b32839 --- /dev/null +++ b/src/boost/libs/container/test/expand_bwd_test_allocator.hpp @@ -0,0 +1,200 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_EXPAND_BWD_TEST_ALLOCATOR_HPP +#define BOOST_CONTAINER_EXPAND_BWD_TEST_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace test { + +//This allocator just allows two allocations. The first one will return +//mp_buffer + m_offset configured in the constructor. The second one +//will return mp_buffer. +template +class expand_bwd_test_allocator +{ + private: + typedef expand_bwd_test_allocator self_t; + typedef void * aux_pointer_t; + typedef const void * cvoid_ptr; + + template + expand_bwd_test_allocator& operator=(const expand_bwd_test_allocator&); + + expand_bwd_test_allocator& operator=(const expand_bwd_test_allocator&); + + public: + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef typename dtl::add_reference + ::type reference; + typedef typename dtl::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::container::dtl::version_type version; + + //Dummy multiallocation chain + struct multiallocation_chain{}; + + template + struct rebind + { typedef expand_bwd_test_allocator other; }; + + //!Constructor from the segment manager. Never throws + expand_bwd_test_allocator(T *buffer, size_type sz, difference_type offset) + : mp_buffer(buffer), m_size(sz) + , m_offset(offset), m_allocations(0){ } + + //!Constructor from other expand_bwd_test_allocator. Never throws + expand_bwd_test_allocator(const expand_bwd_test_allocator &other) + : mp_buffer(other.mp_buffer), m_size(other.m_size) + , m_offset(other.m_offset), m_allocations(0){ } + + //!Constructor from related expand_bwd_test_allocator. Never throws + template + expand_bwd_test_allocator(const expand_bwd_test_allocator &other) + : mp_buffer(other.mp_buffer), m_size(other.m_size) + , m_offset(other.m_offset), m_allocations(0){ } + + pointer address(reference value) + { return pointer(dtl::addressof(value)); } + + const_pointer address(const_reference value) const + { return const_pointer(dtl::addressof(value)); } + + pointer allocate(size_type , cvoid_ptr hint = 0) + { (void)hint; return 0; } + + void deallocate(const pointer &, size_type) + {} + + template + void construct(pointer ptr, const Convertible &value) + { new((void*)ptr) value_type(value); } + + void destroy(pointer ptr) + { (*ptr).~value_type(); } + + size_type max_size() const + { return m_size; } + + friend void swap(self_t &alloc1, self_t &alloc2) + { + boost::adl_move_swap(alloc1.mp_buffer, alloc2.mp_buffer); + boost::adl_move_swap(alloc1.m_size, alloc2.m_size); + boost::adl_move_swap(alloc1.m_offset, alloc2.m_offset); + } + + //Experimental version 2 expand_bwd_test_allocator functions + + pointer allocation_command(boost::container::allocation_type command, + size_type limit_size,size_type &prefer_in_recvd_out_size,pointer &reuse) + { + (void)reuse; (void)command; + //This allocator only expands backwards! + assert(m_allocations == 0 || (command & boost::container::expand_bwd)); + + prefer_in_recvd_out_size = limit_size; + + if(m_allocations == 0){ + if((m_offset + limit_size) > m_size){ + assert(0); + } + ++m_allocations; + reuse = 0; + return (mp_buffer + m_offset); + } + else if(m_allocations == 1){ + if(limit_size > m_size){ + assert(0); + } + ++m_allocations; + return mp_buffer; + } + else{ + throw_bad_alloc(); + return mp_buffer; + } + } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. + size_type size(const pointer &p) const + { (void)p; return m_size; } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::container::bad_alloc if there is no enough memory + pointer allocate_one() + { return this->allocate(1); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { return this->deallocate(p, 1); } + + pointer mp_buffer; + size_type m_size; + difference_type m_offset; + char m_allocations; +}; + +//!Equality test for same type of expand_bwd_test_allocator +template inline +bool operator==(const expand_bwd_test_allocator &, + const expand_bwd_test_allocator &) +{ return false; } + +//!Inequality test for same type of expand_bwd_test_allocator +template inline +bool operator!=(const expand_bwd_test_allocator &, + const expand_bwd_test_allocator &) +{ return true; } + +} //namespace test { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_EXPAND_BWD_TEST_ALLOCATOR_HPP + diff --git a/src/boost/libs/container/test/expand_bwd_test_template.hpp b/src/boost/libs/container/test/expand_bwd_test_template.hpp new file mode 100644 index 00000000..1c193ac6 --- /dev/null +++ b/src/boost/libs/container/test/expand_bwd_test_template.hpp @@ -0,0 +1,218 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_ALLOCATION_TEST_TEMPLATE_HEADER +#define BOOST_CONTAINER_TEST_ALLOCATION_TEST_TEMPLATE_HEADER + +#include +#include +#include +#include +#include "expand_bwd_test_allocator.hpp" +#include //equal() +#include "movable_int.hpp" +#include + +namespace boost { namespace container { namespace test { + +//Function to check if both sets are equal +template +bool CheckEqualVector(const Vector1 &vector1, const Vector2 &vector2) +{ + if(vector1.size() != vector2.size()) + return false; + return boost::container::algo_equal(vector1.begin(), vector1.end(), vector2.begin()); +} + +template +bool CheckUninitializedIsZero(const Vector & v) +{ + typedef typename Vector::value_type value_type; + typename Vector::size_type sz = v.size(); + typename Vector::size_type extra = v.capacity() - v.size(); + value_type comp(0); + + const value_type *holder = &v[0] + sz; + + while(extra--){ + if(*holder++ != comp) + return false; + } + return true; +} + + +//This function tests all the possible combinations when +//inserting data in a vector and expanding backwards +template +bool test_insert_with_expand_bwd() +{ + typedef typename VectorWithExpandBwdAllocator::value_type value_type; + typedef std::vector Vect; + const unsigned int MemorySize = 1000; + + //Distance old and new buffer + const unsigned int Offset[] = + { 350, 300, 250, 200, 150, 100, 150, 100, + 150, 50, 50, 50 }; + //Initial vector size + const unsigned int InitialSize[] = + { 200, 200, 200, 200, 200, 200, 200, 200, + 200, 200, 200, 200 }; + //Size of the data to insert + const unsigned int InsertSize[] = + { 100, 100, 100, 100, 100, 100, 200, 200, + 300, 25, 100, 200 }; + //Number of tests + const unsigned int Iterations = sizeof(InsertSize)/sizeof(int); + + //Insert position + const int Position[] = + { 0, 100, 200 }; + + for(unsigned int pos = 0; pos < sizeof(Position)/sizeof(Position[0]); ++pos){ + if(!life_count::check(0)) + return false; + + for(unsigned int iteration = 0; iteration < Iterations; ++iteration) + { + boost::movelib::unique_ptr memptr = + boost::movelib::make_unique_definit(MemorySize*sizeof(value_type)); + value_type *memory = (value_type*)memptr.get(); + std::vector initial_data; + initial_data.resize(InitialSize[iteration]); + for(unsigned int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } + + if(!life_count::check(InitialSize[iteration])) + return false; + Vect data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(unsigned int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } + + if(!life_count::check(InitialSize[iteration]+InsertSize[iteration])) + return false; + + expand_bwd_test_allocator alloc + (memory, MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + vector.insert( vector.begin() + Position[pos] + , data_to_insert.begin(), data_to_insert.end()); + + if(!life_count::check(InitialSize[iteration]*2+InsertSize[iteration]*2)) + return false; + + initial_data.insert(initial_data.begin() + Position[pos] + , data_to_insert.begin(), data_to_insert.end()); + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } + } + if(!life_count::check(0)) + return false; + } + + return true; +} + +//This function tests all the possible combinations when +//inserting data in a vector and expanding backwards +template +bool test_assign_with_expand_bwd() +{ + typedef typename VectorWithExpandBwdAllocator::value_type value_type; + const unsigned int MemorySize = 200; + + const unsigned int Offset[] = { 50, 50, 50}; + const unsigned int InitialSize[] = { 25, 25, 25}; + const unsigned int InsertSize[] = { 15, 35, 55}; + const unsigned int Iterations = sizeof(InsertSize)/sizeof(int); + + for(unsigned int iteration = 0; iteration memptr = + boost::movelib::make_unique_definit(MemorySize*sizeof(value_type)); + value_type *memory = (value_type*)memptr.get(); + //Create initial data + std::vector initial_data; + initial_data.resize(InitialSize[iteration]); + for(unsigned int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } + + //Create data to assign + std::vector data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(unsigned int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } + + //Insert initial data to the vector to test + expand_bwd_test_allocator alloc + (memory, MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + + //Assign data + vector.insert(vector.cbegin(), data_to_insert.begin(), data_to_insert.end()); + initial_data.insert(initial_data.begin(), data_to_insert.begin(), data_to_insert.end()); + + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } + } + + return true; +} + +//This function calls all tests +template +bool test_all_expand_bwd() +{ + std::cout << "Starting test_insert_with_expand_bwd." << std::endl << " Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + + if(!test_insert_with_expand_bwd()){ + std::cout << "test_allocation_direct_deallocation failed. Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + return false; + } + + std::cout << "Starting test_assign_with_expand_bwd." << std::endl << " Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + + if(!test_assign_with_expand_bwd()){ + std::cout << "test_allocation_direct_deallocation failed. Class: " + << typeid(VectorWithExpandBwdAllocator).name() << std::endl; + return false; + } + + return true; +} + +}}} //namespace boost { namespace container { namespace test { + +#include + +#endif //BOOST_CONTAINER_TEST_ALLOCATION_TEST_TEMPLATE_HEADER diff --git a/src/boost/libs/container/test/explicit_inst_deque_test.cpp b/src/boost/libs/container/test/explicit_inst_deque_test.cpp new file mode 100644 index 00000000..6fec8116 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_deque_test.cpp @@ -0,0 +1,46 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::deque; + +volatile ::boost::container::deque dummy; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::deque + < test::movable_and_copyable_int + , test::simple_allocator >; + +template class boost::container::deque + < test::movable_and_copyable_int + , allocator >; + +} //namespace boost { +} //namespace container { + +int main() +{ + return 0; +} + diff --git a/src/boost/libs/container/test/explicit_inst_flat_map_test.cpp b/src/boost/libs/container/test/explicit_inst_flat_map_test.cpp new file mode 100644 index 00000000..3a8ff6fa --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_flat_map_test.cpp @@ -0,0 +1,94 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" +#include +#include +#include +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::flat_map; +template class ::boost::container::flat_multimap; + +volatile ::boost::container::flat_map dummy; +volatile ::boost::container::flat_multimap dummy2; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +//flat_map +typedef std::pair test_pair_t; + +template class flat_map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , small_vector< test_pair_t, 10, std::allocator< test_pair_t > > + >; + +//flat_multimap +template class flat_multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , stable_vector< test_pair_t, allocator< test_pair_t > > + >; + +template class flat_multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , deque > + >; + +template class flat_multimap + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , static_vector + >; + +//As flat container iterators are typedefs for vector::[const_]iterator, +//no need to explicit instantiate them + +}} //boost::container + +#if (__cplusplus > 201103L) +#include + +namespace boost{ +namespace container{ + +template class flat_map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , std::vector +>; + +}} //boost::container + +#endif + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_flat_set_test.cpp b/src/boost/libs/container/test/explicit_inst_flat_set_test.cpp new file mode 100644 index 00000000..eeb8366e --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_flat_set_test.cpp @@ -0,0 +1,88 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::flat_set; +template class ::boost::container::flat_multiset; + +volatile ::boost::container::flat_set dummy; +volatile ::boost::container::flat_multiset dummy2; + +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" +#include +#include +#include +#include + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +//flat_set +template class flat_set + < test::movable_and_copyable_int + , std::less + , small_vector > + >; + +//flat_multiset +template class flat_multiset + < test::movable_and_copyable_int + , std::less + , stable_vector > + >; + +template class flat_multiset + < test::movable_and_copyable_int + , std::less + , deque > + >; + +template class flat_multiset + < test::movable_and_copyable_int + , std::less + , static_vector + >; + +//As flat container iterators are typedefs for vector::[const_]iterator, +//no need to explicit instantiate them + +}} //boost::container + +#if (__cplusplus > 201103L) +#include + +namespace boost{ +namespace container{ + +template class flat_set + < test::movable_and_copyable_int + , std::less + , std::vector +>; + +}} //boost::container + +#endif + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_list_test.cpp b/src/boost/libs/container/test/explicit_inst_list_test.cpp new file mode 100644 index 00000000..4faeaeba --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_list_test.cpp @@ -0,0 +1,25 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::list; + +int main() +{ + ::boost::container::list dummy; + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_map_test.cpp b/src/boost/libs/container/test/explicit_inst_map_test.cpp new file mode 100644 index 00000000..5a4a2b40 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_map_test.cpp @@ -0,0 +1,56 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::map; +template class ::boost::container::multimap; + +volatile ::boost::container::map dummy; +volatile ::boost::container::multimap dummy2; + +#include +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +typedef std::pair pair_t; + +//Explicit instantiation to detect compilation errors + +//map +template class map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , test::simple_allocator< pair_t > + >; + +template class map + < test::movable_and_copyable_int + , test::movable_and_copyable_int + , std::less + , adaptive_pool< pair_t > + >; +}} //boost::container + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_set_test.cpp b/src/boost/libs/container/test/explicit_inst_set_test.cpp new file mode 100644 index 00000000..fa031235 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_set_test.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::set; +template class ::boost::container::multiset; + +volatile ::boost::container::set dummy; +volatile ::boost::container::multiset dummy2; + +#include +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +//set +template class set + < test::movable_and_copyable_int + , std::less + , test::simple_allocator + >; + +//multiset +template class multiset + < test::movable_and_copyable_int + , std::less + , adaptive_pool + >; + +}} //boost::container + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_slist_test.cpp b/src/boost/libs/container/test/explicit_inst_slist_test.cpp new file mode 100644 index 00000000..f825c10c --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_slist_test.cpp @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::slist; +volatile ::boost::container::slist dummy; + +#include +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::slist + < test::movable_and_copyable_int + , test::simple_allocator >; + +template class boost::container::slist + < test::movable_and_copyable_int + , node_allocator >; + +}} + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_small_vector_test.cpp b/src/boost/libs/container/test/explicit_inst_small_vector_test.cpp new file mode 100644 index 00000000..6259aae8 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_small_vector_test.cpp @@ -0,0 +1,56 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::small_vector; +volatile ::boost::container::small_vector dummy; + +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +template class small_vector; +template class small_vector; +template class small_vector; +template class small_vector; + +template class small_vector; +template class small_vector; +template class small_vector; +template class small_vector; + +//Explicit instantiation to detect compilation errors +template class boost::container::small_vector + < test::movable_and_copyable_int + , 10 + , test::simple_allocator >; + +template class boost::container::small_vector + < test::movable_and_copyable_int + , 10 + , allocator >; + +}} + + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_stable_vector_test.cpp b/src/boost/libs/container/test/explicit_inst_stable_vector_test.cpp new file mode 100644 index 00000000..b11b4c65 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_stable_vector_test.cpp @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::stable_vector; +volatile ::boost::container::stable_vector dummy; + +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class stable_vector >; + +template class stable_vector + < test::movable_and_copyable_int + , node_allocator >; + +template class stable_vector_iterator; +template class stable_vector_iterator; + +}} + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_static_vector_test.cpp b/src/boost/libs/container/test/explicit_inst_static_vector_test.cpp new file mode 100644 index 00000000..081775df --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_static_vector_test.cpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::static_vector; +volatile ::boost::container::static_vector dummy; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::static_vector; + +}} + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_string_test.cpp b/src/boost/libs/container/test/explicit_inst_string_test.cpp new file mode 100644 index 00000000..fd769692 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_string_test.cpp @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +template class ::boost::container::basic_string; +volatile ::boost::container::basic_string dummy; + +#include +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +typedef test::simple_allocator SimpleCharAllocator; +typedef basic_string, SimpleCharAllocator> SimpleString; +typedef test::simple_allocator SimpleStringAllocator; +typedef test::simple_allocator SimpleWCharAllocator; +typedef basic_string, SimpleWCharAllocator> SimpleWString; +typedef test::simple_allocator SimpleWStringAllocator; + +//Explicit instantiations of container::basic_string +template class basic_string, SimpleCharAllocator>; +template class basic_string, SimpleWCharAllocator>; +template class basic_string, std::allocator >; +template class basic_string, std::allocator >; + +//Explicit instantiation of container::vectors of container::strings +template class vector; +template class vector; + +}} + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/explicit_inst_vector_test.cpp b/src/boost/libs/container/test/explicit_inst_vector_test.cpp new file mode 100644 index 00000000..619dfc95 --- /dev/null +++ b/src/boost/libs/container/test/explicit_inst_vector_test.cpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::vector; +volatile ::boost::container::vector dummy; + +#include +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::vector + < test::movable_and_copyable_int + , test::simple_allocator >; + +template class boost::container::vector + < test::movable_and_copyable_int + , allocator >; + +template class vec_iterator; +template class vec_iterator; + +} //namespace boost { +} //namespace container { + +int main() +{ + return 0; +} diff --git a/src/boost/libs/container/test/flat_map_adaptor_test.cpp b/src/boost/libs/container/test/flat_map_adaptor_test.cpp new file mode 100644 index 00000000..520ef3c1 --- /dev/null +++ b/src/boost/libs/container/test/flat_map_adaptor_test.cpp @@ -0,0 +1,104 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2019. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include + +#include "map_test.hpp" +#include + +using namespace boost::container; + +template +struct GetMapContainer +{ + template + struct apply + { + typedef std::pair type_t; + typedef flat_map< ValueType + , ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > map_type; + + typedef flat_multimap< ValueType + , ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > multimap_type; + }; +}; + +int main() +{ + using namespace boost::container::test; + + //////////////////////////////////// + // Testing sequence container implementations + //////////////////////////////////// + { + typedef std::map MyStdMap; + typedef std::multimap MyStdMultiMap; + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer, 7> >::apply::map_type + , MyStdMap + , GetMapContainer, 7> >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, 7> >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer, MaxElem * 10> >::apply::map_type + , MyStdMap + , GetMapContainer, MaxElem * 10> >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, MaxElem * 10> >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } + + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/boost/libs/container/test/flat_map_test.cpp b/src/boost/libs/container/test/flat_map_test.cpp new file mode 100644 index 00000000..f5caff7a --- /dev/null +++ b/src/boost/libs/container/test/flat_map_test.cpp @@ -0,0 +1,838 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include + +#include + +#include +#include +#include + +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "map_test.hpp" +#include "propagate_allocator_test.hpp" +#include "container_common_tests.hpp" +#include "emplace_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +#include +#include + + +using namespace boost::container; + +class recursive_flat_map +{ + public: + recursive_flat_map(const recursive_flat_map &c) + : id_(c.id_), map_(c.map_) + {} + + recursive_flat_map & operator =(const recursive_flat_map &c) + { + id_ = c.id_; + map_= c.map_; + return *this; + } + + int id_; + flat_map map_; + flat_map::iterator it_; + flat_map::const_iterator cit_; + flat_map::reverse_iterator rit_; + flat_map::const_reverse_iterator crit_; + + friend bool operator< (const recursive_flat_map &a, const recursive_flat_map &b) + { return a.id_ < b.id_; } +}; + + +class recursive_flat_multimap +{ +public: + recursive_flat_multimap(const recursive_flat_multimap &c) + : id_(c.id_), map_(c.map_) + {} + + recursive_flat_multimap & operator =(const recursive_flat_multimap &c) + { + id_ = c.id_; + map_= c.map_; + return *this; + } + int id_; + flat_multimap map_; + flat_multimap::iterator it_; + flat_multimap::const_iterator cit_; + flat_multimap::reverse_iterator rit_; + flat_multimap::const_reverse_iterator crit_; + + friend bool operator< (const recursive_flat_multimap &a, const recursive_flat_multimap &b) + { return a.id_ < b.id_; } +}; + +template +void test_move() +{ + //Now test move semantics + C original; + C move_ctor(boost::move(original)); + C move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); +} + + +namespace boost{ +namespace container { +namespace test{ + +bool flat_tree_ordered_insertion_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //Ordered insertion multimap + { + std::multimap int_mmap; + for(std::size_t i = 0; i != NumElements; ++i){ + int_mmap.insert(std::multimap::value_type(static_cast(i), static_cast(i))); + } + //Construction insertion + flat_multimap fmmap(ordered_range, int_mmap.begin(), int_mmap.end()); + if(!CheckEqualContainers(int_mmap, fmmap)) + return false; + //Insertion when empty + fmmap.clear(); + fmmap.insert(ordered_range, int_mmap.begin(), int_mmap.end()); + if(!CheckEqualContainers(int_mmap, fmmap)) + return false; + //Re-insertion + fmmap.insert(ordered_range, int_mmap.begin(), int_mmap.end()); + std::multimap int_mmap2(int_mmap); + int_mmap2.insert(int_mmap.begin(), int_mmap.end()); + if(!CheckEqualContainers(int_mmap2, fmmap)) + return false; + //Re-re-insertion + fmmap.insert(ordered_range, int_mmap2.begin(), int_mmap2.end()); + std::multimap int_mmap4(int_mmap2); + int_mmap4.insert(int_mmap2.begin(), int_mmap2.end()); + if(!CheckEqualContainers(int_mmap4, fmmap)) + return false; + //Re-re-insertion of even + std::multimap int_even_mmap; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_mmap.insert(std::multimap::value_type(static_cast(i), static_cast(i))); + } + fmmap.insert(ordered_range, int_even_mmap.begin(), int_even_mmap.end()); + int_mmap4.insert(int_even_mmap.begin(), int_even_mmap.end()); + if(!CheckEqualContainers(int_mmap4, fmmap)) + return false; + } + + //Ordered insertion map + { + std::map int_map; + for(std::size_t i = 0; i != NumElements; ++i){ + int_map.insert(std::map::value_type(static_cast(i), static_cast(i))); + } + //Construction insertion + flat_map fmap(ordered_unique_range, int_map.begin(), int_map.end()); + if(!CheckEqualContainers(int_map, fmap)) + return false; + //Insertion when empty + fmap.clear(); + fmap.insert(ordered_unique_range, int_map.begin(), int_map.end()); + if(!CheckEqualContainers(int_map, fmap)) + return false; + //Re-insertion + fmap.insert(ordered_unique_range, int_map.begin(), int_map.end()); + std::map int_map2(int_map); + int_map2.insert(int_map.begin(), int_map.end()); + if(!CheckEqualContainers(int_map2, fmap)) + return false; + //Re-re-insertion + fmap.insert(ordered_unique_range, int_map2.begin(), int_map2.end()); + std::map int_map4(int_map2); + int_map4.insert(int_map2.begin(), int_map2.end()); + if(!CheckEqualContainers(int_map4, fmap)) + return false; + //Re-re-insertion of even + std::map int_even_map; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_map.insert(std::map::value_type(static_cast(i), static_cast(i))); + } + fmap.insert(ordered_unique_range, int_even_map.begin(), int_even_map.end()); + int_map4.insert(int_even_map.begin(), int_even_map.end()); + if(!CheckEqualContainers(int_map4, fmap)) + return false; + } + + return true; +} + +bool constructor_template_auto_deduction_test() +{ + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + using namespace boost::container; + const std::size_t NumElements = 100; + { + std::map int_map; + for(std::size_t i = 0; i != NumElements; ++i){ + int_map.insert(std::map::value_type(static_cast(i), static_cast(i))); + } + std::multimap int_mmap; + for (std::size_t i = 0; i != NumElements; ++i) { + int_mmap.insert(std::multimap::value_type(static_cast(i), static_cast(i))); + } + + typedef std::less comp_int_t; + typedef std::allocator > alloc_pair_int_t; + + //range + { + auto fmap = flat_map(int_map.begin(), int_map.end()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(int_mmap.begin(), int_mmap.end()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp + { + auto fmap = flat_map(int_map.begin(), int_map.end(), comp_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(int_mmap.begin(), int_mmap.end(), comp_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp+alloc + { + auto fmap = flat_map(int_map.begin(), int_map.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(int_mmap.begin(), int_mmap.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+alloc + { + auto fmap = flat_map(int_map.begin(), int_map.end(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(int_mmap.begin(), int_mmap.end(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + + //ordered_unique_range / ordered_range + + //range + { + auto fmap = flat_map(ordered_unique_range, int_map.begin(), int_map.end()); + if(!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(ordered_range, int_mmap.begin(), int_mmap.end()); + if(!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp + { + auto fmap = flat_map(ordered_unique_range, int_map.begin(), int_map.end(), comp_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(ordered_range, int_mmap.begin(), int_mmap.end(), comp_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp+alloc + { + auto fmap = flat_map(ordered_unique_range, int_map.begin(), int_map.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(ordered_range, int_mmap.begin(), int_mmap.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+alloc + { + auto fmap = flat_map(ordered_unique_range, int_map.begin(), int_map.end(),alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = flat_multimap(ordered_range, int_mmap.begin(), int_mmap.end(),alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + } +#endif + + return true; +} + +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +bool flat_tree_extract_adopt_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //extract/adopt map + { + //Construction insertion + flat_map fmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_map fmap_copy(fmap); + flat_map::sequence_type seq(fmap.extract_sequence()); + if(!fmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmap_copy)) + return false; + + seq.insert(seq.end(), fmap_copy.begin(), fmap_copy.end()); + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmap.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmap, fmap_copy)) + return false; + } + + //extract/adopt map, ordered_unique_range + { + //Construction insertion + flat_map fmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_map fmap_copy(fmap); + flat_map::sequence_type seq(fmap.extract_sequence()); + if(!fmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmap_copy)) + return false; + + fmap.adopt_sequence(ordered_unique_range, boost::move(seq)); + if(!CheckEqualContainers(fmap, fmap_copy)) + return false; + } + + //extract/adopt multimap + { + //Construction insertion + flat_multimap fmmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmmap.emplace(static_cast(i), -static_cast(i)); + fmmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_multimap fmmap_copy(fmmap); + flat_multimap::sequence_type seq(fmmap.extract_sequence()); + if(!fmmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmmap_copy)) + return false; + + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmmap.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmmap, fmmap_copy)) + return false; + } + + //extract/adopt multimap, ordered_range + { + //Construction insertion + flat_multimap fmmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmmap.emplace(static_cast(i), -static_cast(i)); + fmmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_multimap fmmap_copy(fmmap); + flat_multimap::sequence_type seq(fmmap.extract_sequence()); + if(!fmmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmmap_copy)) + return false; + + fmmap.adopt_sequence(ordered_range, boost::move(seq)); + if(!CheckEqualContainers(fmmap, fmmap_copy)) + return false; + } + + return true; +} + +}}} + +template +struct GetMapContainer +{ + template + struct apply + { + typedef std::pair type_t; + typedef flat_map< ValueType + , ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > map_type; + + typedef flat_multimap< ValueType + , ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > multimap_type; + }; +}; + +struct boost_container_flat_map; +struct boost_container_flat_multimap; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef typename boost::container::allocator_traits:: + template portable_rebind_alloc >::type TypeAllocator; + typedef boost::container::flat_map, TypeAllocator> type; + }; +}; + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef typename boost::container::allocator_traits:: + template portable_rebind_alloc >::type TypeAllocator; + typedef boost::container::flat_multimap, TypeAllocator> type; + }; +}; + +template +struct get_real_stored_allocator > +{ + typedef typename flat_map::impl_stored_allocator_type type; +}; + +template +struct get_real_stored_allocator > +{ + typedef typename flat_multimap::impl_stored_allocator_type type; +}; + +bool test_heterogeneous_lookups() +{ + BOOST_STATIC_ASSERT((dtl::is_transparent::value)); + BOOST_STATIC_ASSERT(!(dtl::is_transparent >::value)); + typedef flat_map map_t; + typedef flat_multimap mmap_t; + typedef map_t::value_type value_type; + + map_t map1; + mmap_t mmap1; + + const map_t &cmap1 = map1; + const mmap_t &cmmap1 = mmap1; + + if(!map1.insert_or_assign(1, 'a').second) + return false; + if( map1.insert_or_assign(1, 'b').second) + return false; + if(!map1.insert_or_assign(2, 'c').second) + return false; + if( map1.insert_or_assign(2, 'd').second) + return false; + if(!map1.insert_or_assign(3, 'e').second) + return false; + + if(map1.insert_or_assign(1, 'a').second) + return false; + if(map1.insert_or_assign(1, 'b').second) + return false; + if(map1.insert_or_assign(2, 'c').second) + return false; + if(map1.insert_or_assign(2, 'd').second) + return false; + if(map1.insert_or_assign(3, 'e').second) + return false; + + mmap1.insert(value_type(1, 'a')); + mmap1.insert(value_type(1, 'b')); + mmap1.insert(value_type(2, 'c')); + mmap1.insert(value_type(2, 'd')); + mmap1.insert(value_type(3, 'e')); + + const test::non_copymovable_int find_me(2); + + //find + if(map1.find(find_me)->second != 'd') + return false; + if(cmap1.find(find_me)->second != 'd') + return false; + if(mmap1.find(find_me)->second != 'c') + return false; + if(cmmap1.find(find_me)->second != 'c') + return false; + + //count + if(map1.count(find_me) != 1) + return false; + if(cmap1.count(find_me) != 1) + return false; + if(mmap1.count(find_me) != 2) + return false; + if(cmmap1.count(find_me) != 2) + return false; + + //contains + if(!map1.contains(find_me)) + return false; + if(!cmap1.contains(find_me)) + return false; + if(!mmap1.contains(find_me)) + return false; + if(!cmmap1.contains(find_me)) + return false; + + //lower_bound + if(map1.lower_bound(find_me)->second != 'd') + return false; + if(cmap1.lower_bound(find_me)->second != 'd') + return false; + if(mmap1.lower_bound(find_me)->second != 'c') + return false; + if(cmmap1.lower_bound(find_me)->second != 'c') + return false; + + //upper_bound + if(map1.upper_bound(find_me)->second != 'e') + return false; + if(cmap1.upper_bound(find_me)->second != 'e') + return false; + if(mmap1.upper_bound(find_me)->second != 'e') + return false; + if(cmmap1.upper_bound(find_me)->second != 'e') + return false; + + //equal_range + if(map1.equal_range(find_me).first->second != 'd') + return false; + if(cmap1.equal_range(find_me).second->second != 'e') + return false; + if(mmap1.equal_range(find_me).first->second != 'c') + return false; + if(cmmap1.equal_range(find_me).second->second != 'e') + return false; + + return true; +} + +// An ordered sequence of std:pair is also ordered by std::pair::first. +struct with_lookup_by_first +{ + typedef void is_transparent; + inline bool operator()(std::pair a, std::pair b) const + { + return a < b; + } + inline bool operator()(std::pair a, int first) const + { + return a.first < first; + } + inline bool operator()(int first, std::pair b) const + { + return first < b.first; + } +}; + +bool test_heterogeneous_lookup_by_partial_key() +{ + typedef flat_map,int, with_lookup_by_first> map_t; + + map_t map1; + map1[std::pair(0, 1)] = 3; + map1[std::pair(0, 2)] = 3; + + std::pair const first_0_range = map1.equal_range(0); + + if(2 != (first_0_range.second - first_0_range.first)) + return false; + + if(2 != map1.count(0)) + return false; + return true; +} + +}}} //namespace boost::container::test + +int main() +{ + using namespace boost::container::test; + + //Allocator argument container + { + flat_map map_((flat_map::allocator_type())); + flat_multimap multimap_((flat_multimap::allocator_type())); + } + //Now test move semantics + { + test_move >(); + test_move >(); + } + //Now test nth/index_of + { + flat_map map; + flat_multimap mmap; + + map.insert(std::pair(0, 0)); + map.insert(std::pair(1, 0)); + map.insert(std::pair(2, 0)); + mmap.insert(std::pair(0, 0)); + mmap.insert(std::pair(1, 0)); + mmap.insert(std::pair(2, 0)); + if(!boost::container::test::test_nth_index_of(map)) + return 1; + if(!boost::container::test::test_nth_index_of(mmap)) + return 1; + } + + //////////////////////////////////// + // Ordered insertion test + //////////////////////////////////// + if(!flat_tree_ordered_insertion_test()){ + return 1; + } + + //////////////////////////////////// + // Constructor Template Auto Deduction test + //////////////////////////////////// + if(!constructor_template_auto_deduction_test()){ + return 1; + } + + //////////////////////////////////// + // Extract/Adopt test + //////////////////////////////////// + if(!flat_tree_extract_adopt_test()){ + return 1; + } + + if (!boost::container::test::instantiate_constructors, flat_multimap >()) + return 1; + + if (!test_heterogeneous_lookups()) + return 1; + + if (!test_heterogeneous_lookup_by_partial_key()) + return 1; + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + { + typedef std::map MyStdMap; + typedef std::multimap MyStdMultiMap; + + if (0 != test::map_test + < GetMapContainer >::apply::map_type + , MyStdMap + , GetMapContainer >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer >::apply::map_type + , MyStdMap + , GetMapContainer >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer >::apply::map_type + , MyStdMap + , GetMapContainer >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer >::apply::map_type + , MyStdMap + , GetMapContainer >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test >" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetMapContainer >::apply::map_type + , MyStdMap + , GetMapContainer >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test >" << std::endl; + return 1; + } + } + + if(!boost::container::test::test_map_support_for_initialization_list_for >()) + return 1; + + if (!boost::container::test::test_map_support_for_initialization_list_for >()) + return 1; + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR); + + if(!boost::container::test::test_emplace, MapOptions>()) + return 1; + if(!boost::container::test::test_emplace, MapOptions>()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::flat_map cont_int; + cont_int a; a.insert(cont_int::value_type(0, 9)); a.insert(cont_int::value_type(1, 9)); a.insert(cont_int::value_type(2, 9)); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + { + typedef boost::container::flat_multimap cont_int; + cont_int a; a.insert(cont_int::value_type(0, 9)); a.insert(cont_int::value_type(1, 9)); a.insert(cont_int::value_type(2, 9)); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + { + typedef boost::container::dtl::pair value_t; + typedef boost::container::dtl::select1st key_of_value_t; + // flat_map, default + { + typedef boost::container::new_allocator alloc_or_cont_t; + typedef boost::container::flat_map cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_map, default) test failed" << std::endl; + return 1; + } + } + // flat_map, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_map, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_map, vector) test failed" << std::endl; + return 1; + } + } + // flat_map, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_map, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_map, std::vector) test failed" << std::endl; + return 1; + } + } + // flat_multimap, default + { + typedef boost::container::new_allocator alloc_or_cont_t; + typedef boost::container::flat_multimap cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multimap, default) test failed" << std::endl; + return 1; + } + } + // flat_multimap, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_multimap, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multimap, vector) test failed" << std::endl; + return 1; + } + } + // flat_multimap, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_multimap, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multimap, std::vector) test failed" << std::endl; + return 1; + } + } + } + + return 0; +} + +#include diff --git a/src/boost/libs/container/test/flat_set_adaptor_test.cpp b/src/boost/libs/container/test/flat_set_adaptor_test.cpp new file mode 100644 index 00000000..b59ab179 --- /dev/null +++ b/src/boost/libs/container/test/flat_set_adaptor_test.cpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2019. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + +#include + +#include "set_test.hpp" +#include + +using namespace boost::container; + +template +struct GetSetContainer +{ + template + struct apply + { + typedef flat_set < ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > set_type; + + typedef flat_multiset < ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > multiset_type; + }; +}; + +int main() +{ + using namespace boost::container::test; + + //////////////////////////////////// + // Testing sequence container implementations + //////////////////////////////////// + { + typedef std::set MyStdSet; + typedef std::multiset MyStdMultiSet; + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/boost/libs/container/test/flat_set_test.cpp b/src/boost/libs/container/test/flat_set_test.cpp new file mode 100644 index 00000000..7927b99a --- /dev/null +++ b/src/boost/libs/container/test/flat_set_test.cpp @@ -0,0 +1,933 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include + +#include +#include + +#include "print_container.hpp" +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "set_test.hpp" +#include "propagate_allocator_test.hpp" +#include "emplace_test.hpp" +#include "container_common_tests.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +//Test recursive structures +class recursive_flat_set +{ + public: + recursive_flat_set(const recursive_flat_set &c) + : id_(c.id_), flat_set_(c.flat_set_) + {} + + recursive_flat_set & operator =(const recursive_flat_set &c) + { + id_ = c.id_; + flat_set_= c.flat_set_; + return *this; + } + int id_; + flat_set flat_set_; + flat_set::iterator it_; + flat_set::const_iterator cit_; + flat_set::reverse_iterator rit_; + flat_set::const_reverse_iterator crit_; + + friend bool operator< (const recursive_flat_set &a, const recursive_flat_set &b) + { return a.id_ < b.id_; } +}; + + +//Test recursive structures +class recursive_flat_multiset +{ + public: + recursive_flat_multiset(const recursive_flat_multiset &c) + : id_(c.id_), flat_multiset_(c.flat_multiset_) + {} + + recursive_flat_multiset & operator =(const recursive_flat_multiset &c) + { + id_ = c.id_; + flat_multiset_= c.flat_multiset_; + return *this; + } + int id_; + flat_multiset flat_multiset_; + flat_multiset::iterator it_; + flat_multiset::const_iterator cit_; + flat_multiset::reverse_iterator rit_; + flat_multiset::const_reverse_iterator crit_; + + friend bool operator< (const recursive_flat_multiset &a, const recursive_flat_multiset &b) + { return a.id_ < b.id_; } +}; + + +template +void test_move() +{ + //Now test move semantics + C original; + C move_ctor(boost::move(original)); + C move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); +} + +namespace boost{ +namespace container { +namespace test{ + +bool flat_tree_ordered_insertion_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //Ordered insertion multiset + { + std::multiset int_mset; + for(std::size_t i = 0; i != NumElements; ++i){ + int_mset.insert(static_cast(i)); + } + //Construction insertion + flat_multiset fmset(ordered_range, int_mset.begin(), int_mset.end()); + if(!CheckEqualContainers(int_mset, fmset)) + return false; + //Insertion when empty + fmset.clear(); + fmset.insert(ordered_range, int_mset.begin(), int_mset.end()); + if(!CheckEqualContainers(int_mset, fmset)) + return false; + //Re-insertion + fmset.insert(ordered_range, int_mset.begin(), int_mset.end()); + std::multiset int_mset2(int_mset); + int_mset2.insert(int_mset.begin(), int_mset.end()); + if(!CheckEqualContainers(int_mset2, fmset)) + return false; + //Re-re-insertion + fmset.insert(ordered_range, int_mset2.begin(), int_mset2.end()); + std::multiset int_mset4(int_mset2); + int_mset4.insert(int_mset2.begin(), int_mset2.end()); + if(!CheckEqualContainers(int_mset4, fmset)) + return false; + //Re-re-insertion of even + std::multiset int_even_mset; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_mset.insert(static_cast(i)); + } + fmset.insert(ordered_range, int_even_mset.begin(), int_even_mset.end()); + int_mset4.insert(int_even_mset.begin(), int_even_mset.end()); + if(!CheckEqualContainers(int_mset4, fmset)) + return false; + + //Re-re-insertion using in-place merge + fmset.reserve(fmset.size() + int_mset2.size()); + fmset.insert(ordered_range, int_mset2.begin(), int_mset2.end()); + std::multiset int_mset5(int_mset2); + int_mset4.insert(int_mset5.begin(), int_mset5.end()); + if(!CheckEqualContainers(int_mset4, fmset)) + return false; + //Re-re-insertion of even + std::multiset int_even_mset2; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_even_mset2.insert(static_cast(i)); + } + fmset.reserve(fmset.size() + int_even_mset2.size()); + fmset.insert(ordered_range, int_even_mset2.begin(), int_even_mset2.end()); + int_mset4.insert(int_even_mset2.begin(), int_even_mset2.end()); + if(!CheckEqualContainers(int_mset4, fmset)) + return false; + } + + //Ordered insertion set + { + std::set int_set; + for(std::size_t i = 0; i != NumElements; ++i){ + int_set.insert(static_cast(i)); + } + //Construction insertion + flat_set fset(ordered_unique_range, int_set.begin(), int_set.end()); + if(!CheckEqualContainers(int_set, fset)) + return false; + //Insertion when empty + fset.clear(); + fset.insert(ordered_unique_range, int_set.begin(), int_set.end()); + if(!CheckEqualContainers(int_set, fset)) + return false; + //Re-insertion + fset.insert(ordered_unique_range, int_set.begin(), int_set.end()); + std::set int_set2(int_set); + int_set2.insert(int_set.begin(), int_set.end()); + if(!CheckEqualContainers(int_set2, fset)) + return false; + //Re-re-insertion + fset.insert(ordered_unique_range, int_set2.begin(), int_set2.end()); + std::set int_set4(int_set2); + int_set4.insert(int_set2.begin(), int_set2.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + //Re-re-insertion of even + std::set int_even_set; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_even_set.insert(static_cast(i)); + } + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + //Partial Re-re-insertion of even + int_even_set.clear(); + for(std::size_t i = 0; i < NumElements; i+=4){ + int_even_set.insert(static_cast(i)); + } + fset.clear(); + int_set4.clear(); + //insert 0,4,8,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + for(std::size_t i = 2; i < NumElements; i+=4){ + int_even_set.insert(static_cast(i)); + } + //insert 0,2,4,6,8,10,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + int_even_set.clear(); + for(std::size_t i = 0; i < NumElements; i+=8){ + int_even_set.insert(static_cast(i)); + } + fset.clear(); + int_set4.clear(); + //insert 0,8,16... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_even_set.insert(static_cast(i)); + } + //insert 0,2,4,6,8,10,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + + + int_even_set.clear(); + for(std::size_t i = 0; i < NumElements; i+=8){ + int_even_set.insert(static_cast(i)); + int_even_set.insert(static_cast(i+2)); + } + int_even_set.insert(static_cast(NumElements-2)); + fset.clear(); + int_set4.clear(); + //insert 0,2,8,10... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + for(std::size_t i = 0; i < NumElements; i+=2){ + int_even_set.insert(static_cast(i)); + } + //insert 0,2,4,6,8,10,12... + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + + //add even/odd values with not enough capacity + flat_set().swap(fset); + int_set4.clear(); + int_set.clear(); + + fset.reserve(int_even_set.size()); + fset.insert(ordered_unique_range, int_even_set.begin(), int_even_set.end()); + int_set4.insert(int_even_set.begin(), int_even_set.end()); + + for(std::size_t i = 0; i < NumElements*2; i+=2){ + int_set.insert(static_cast(i)); + int_set.insert(static_cast(i+1)); + } + + fset.insert(ordered_unique_range, int_set.begin(), int_set.end()); + int_set4.insert(int_set.begin(), int_set.end()); + if(!CheckEqualContainers(int_set4, fset)) + return false; + } + + return true; +} + +bool constructor_template_auto_deduction_test() +{ + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + using namespace boost::container; + const std::size_t NumElements = 100; + { + std::set int_set; + for (std::size_t i = 0; i != NumElements; ++i) { + int_set.insert(static_cast(i)); + } + std::multiset int_mset; + for (std::size_t i = 0; i != NumElements; ++i) { + int_mset.insert(static_cast(i)); + } + + typedef std::less comp_int_t; + typedef std::allocator alloc_int_t; + + //range + { + auto fset = flat_set(int_set.begin(), int_set.end()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(int_mset.begin(), int_mset.end()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp + { + auto fset = flat_set(int_set.begin(), int_set.end(), comp_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(int_mset.begin(), int_mset.end(), comp_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp+alloc + { + auto fset = flat_set(int_set.begin(), int_set.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(int_mset.begin(), int_mset.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+alloc + { + auto fset = flat_set(int_set.begin(), int_set.end(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(int_mset.begin(), int_mset.end(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + + //ordered_unique_range / ordered_range + + //range + { + auto fset = flat_set(ordered_unique_range, int_set.begin(), int_set.end()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(ordered_range, int_mset.begin(), int_mset.end()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp + { + auto fset = flat_set(ordered_unique_range, int_set.begin(), int_set.end(), comp_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(ordered_range, int_mset.begin(), int_mset.end(), comp_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp+alloc + { + auto fset = flat_set(ordered_unique_range, int_set.begin(), int_set.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(ordered_range, int_mset.begin(), int_mset.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+alloc + { + auto fset = flat_set(ordered_unique_range, int_set.begin(), int_set.end(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = flat_multiset(ordered_range, int_mset.begin(), int_mset.end(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + } +#endif + + return true; +} + +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +bool flat_tree_extract_adopt_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //extract/adopt set + { + //Construction insertion + flat_set fset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fset.insert(static_cast(i)); + } + + flat_set fset_copy(fset); + flat_set::sequence_type seq(fset.extract_sequence()); + if(!fset.empty()) + return false; + if(!CheckEqualContainers(seq, fset_copy)) + return false; + + seq.insert(seq.end(), fset_copy.begin(), fset_copy.end()); + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fset.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fset, fset_copy)) + return false; + } + + //extract/adopt set, ordered_unique_range + { + //Construction insertion + flat_set fset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fset.insert(static_cast(i)); + } + + flat_set fset_copy(fset); + flat_set::sequence_type seq(fset.extract_sequence()); + if(!fset.empty()) + return false; + if(!CheckEqualContainers(seq, fset_copy)) + return false; + + fset.adopt_sequence(ordered_unique_range, boost::move(seq)); + if(!CheckEqualContainers(fset, fset_copy)) + return false; + } + + //extract/adopt multiset + { + //Construction insertion + flat_multiset fmset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmset.insert(static_cast(i)); + fmset.insert(static_cast(i)); + } + + flat_multiset fmset_copy(fmset); + flat_multiset::sequence_type seq(fmset.extract_sequence()); + if(!fmset.empty()) + return false; + if(!CheckEqualContainers(seq, fmset_copy)) + return false; + + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmset.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmset, fmset_copy)) + return false; + } + + //extract/adopt multiset, ordered_range + { + //Construction insertion + flat_multiset fmset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmset.insert(static_cast(i)); + fmset.insert(static_cast(i)); + } + + flat_multiset fmset_copy(fmset); + flat_multiset::sequence_type seq(fmset.extract_sequence()); + if(!fmset.empty()) + return false; + if(!CheckEqualContainers(seq, fmset_copy)) + return false; + + fmset.adopt_sequence(ordered_range, boost::move(seq)); + if(!CheckEqualContainers(fmset, fmset_copy)) + return false; + } + + return true; +} + +bool test_heterogeneous_lookups() +{ + typedef flat_set set_t; + typedef flat_multiset mset_t; + + set_t set1; + mset_t mset1; + + const set_t &cset1 = set1; + const mset_t &cmset1 = mset1; + + set1.insert(1); + set1.insert(1); + set1.insert(2); + set1.insert(2); + set1.insert(3); + + mset1.insert(1); + mset1.insert(1); + mset1.insert(2); + mset1.insert(2); + mset1.insert(3); + + const test::non_copymovable_int find_me(2); + + //find + if(*set1.find(find_me) != 2) + return false; + if(*cset1.find(find_me) != 2) + return false; + if(*mset1.find(find_me) != 2) + return false; + if(*cmset1.find(find_me) != 2) + return false; + + //count + if(set1.count(find_me) != 1) + return false; + if(cset1.count(find_me) != 1) + return false; + if(mset1.count(find_me) != 2) + return false; + if(cmset1.count(find_me) != 2) + return false; + + //contains + if(!set1.contains(find_me)) + return false; + if(!cset1.contains(find_me)) + return false; + if(!mset1.contains(find_me)) + return false; + if(!cmset1.contains(find_me)) + return false; + + //lower_bound + if(*set1.lower_bound(find_me) != 2) + return false; + if(*cset1.lower_bound(find_me) != 2) + return false; + if(*mset1.lower_bound(find_me) != 2) + return false; + if(*cmset1.lower_bound(find_me) != 2) + return false; + + //upper_bound + if(*set1.upper_bound(find_me) != 3) + return false; + if(*cset1.upper_bound(find_me) != 3) + return false; + if(*mset1.upper_bound(find_me) != 3) + return false; + if(*cmset1.upper_bound(find_me) != 3) + return false; + + //equal_range + if(*set1.equal_range(find_me).first != 2) + return false; + if(*cset1.equal_range(find_me).second != 3) + return false; + if(*mset1.equal_range(find_me).first != 2) + return false; + if(*cmset1.equal_range(find_me).second != 3) + return false; + + return true; +} + +// An ordered sequence of std:pair is also ordered by std::pair::first. +struct with_lookup_by_first +{ + typedef void is_transparent; + inline bool operator()(std::pair a, std::pair b) const + { + return a < b; + } + inline bool operator()(std::pair a, int first) const + { + return a.first < first; + } + inline bool operator()(int first, std::pair b) const + { + return first < b.first; + } +}; + +bool test_heterogeneous_lookup_by_partial_key() +{ + typedef flat_set, with_lookup_by_first> set_t; + + set_t set1; + set1.insert(std::pair(0, 1)); + set1.insert(std::pair(0, 2)); + + std::pair const first_0_range = set1.equal_range(0); + if(2 != (first_0_range.second - first_0_range.first)) + return false; + + if(2 != set1.count(0)) + return false; + return true; +} + +}}} + +template +struct GetSetContainer +{ + template + struct apply + { + typedef flat_set < ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > set_type; + + typedef flat_multiset < ValueType + , std::less + , typename boost::container::dtl::container_or_allocator_rebind::type + > multiset_type; + }; +}; + +template +bool test_support_for_initialization_list_for() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + const std::initializer_list il + = {1, 2}; + + const FlatSetType expected(il.begin(), il.end()); + { + const FlatSetType sil = il; + if (sil != expected) + return false; + + const FlatSetType sil_ordered(ordered_unique_range, il); + if(sil_ordered != expected) + return false; + + FlatSetType sil_assign = {99}; + sil_assign = il; + if(sil_assign != expected) + return false; + } + { + FlatSetType sil; + sil.insert(il); + if(sil != expected) + return false; + } + return true; +#endif + return true; +} + +struct boost_container_flat_set; +struct boost_container_flat_multiset; + +namespace boost { +namespace container { +namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::flat_set, Allocator> type; + }; +}; + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::flat_multiset, Allocator> type; + }; +}; + +}}} //boost::container::test + +int main() +{ + using namespace boost::container::test; + + //Allocator argument container + { + flat_set set_((flat_set::allocator_type())); + flat_multiset multiset_((flat_multiset::allocator_type())); + } + //Now test move semantics + { + test_move >(); + test_move >(); + } + //Now test nth/index_of + { + flat_set set; + flat_multiset mset; + + set.insert(0); + set.insert(1); + set.insert(2); + mset.insert(0); + mset.insert(1); + mset.insert(2); + if(!boost::container::test::test_nth_index_of(set)) + return 1; + if(!boost::container::test::test_nth_index_of(mset)) + return 1; + } + + //////////////////////////////////// + // Ordered insertion test + //////////////////////////////////// + if(!flat_tree_ordered_insertion_test()){ + return 1; + } + + //////////////////////////////////// + // Constructor Template Auto Deduction test + //////////////////////////////////// + if (!constructor_template_auto_deduction_test()) { + return 1; + } + + //////////////////////////////////// + // Extract/Adopt test + //////////////////////////////////// + if(!flat_tree_extract_adopt_test()){ + return 1; + } + + if (!boost::container::test::instantiate_constructors, flat_multiset >()) + return 1; + + if(!test_heterogeneous_lookups()){ + return 1; + } + + if(!test_heterogeneous_lookup_by_partial_key()){ + return 1; + } + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + { + typedef std::set MyStdSet; + typedef std::multiset MyStdMultiSet; + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC); + + if(!boost::container::test::test_emplace, SetOptions>()) + return 1; + if(!boost::container::test::test_emplace, SetOptions>()) + return 1; + + if (!boost::container::test::test_set_methods_with_initializer_list_as_argument_for >()) + return 1; + + if (!boost::container::test::test_set_methods_with_initializer_list_as_argument_for >()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::flat_set cont_int; + cont_int a; a.insert(0); a.insert(1); a.insert(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + { + typedef boost::container::flat_multiset cont_int; + cont_int a; a.insert(0); a.insert(1); a.insert(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + { + typedef boost::container::dtl::identity key_of_value_t; + // flat_set, default + { + typedef boost::container::flat_set cont; + typedef boost::container::dtl::flat_tree, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_set, default) test failed" << std::endl; + return 1; + } + } + // flat_set, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_set, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_set, vector) test failed" << std::endl; + return 1; + } + } + // flat_set, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_set, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_set, std::vector) test failed" << std::endl; + return 1; + } + } + // flat_multiset, default + { + typedef boost::container::flat_multiset cont; + typedef boost::container::dtl::flat_tree, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multiset, default) test failed" << std::endl; + return 1; + } + } + // flat_multiset, vector + { + typedef boost::container::vector alloc_or_cont_t; + typedef boost::container::flat_multiset, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multiset, vector) test failed" << std::endl; + return 1; + } + } + // flat_multiset, std::vector + { + typedef std::vector alloc_or_cont_t; + typedef boost::container::flat_multiset, alloc_or_cont_t> cont; + typedef boost::container::dtl::flat_tree, alloc_or_cont_t> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(flat_multiset, std::vector) test failed" << std::endl; + return 1; + } + } + } + + return 0; +} + +#include + diff --git a/src/boost/libs/container/test/flat_tree_test.cpp b/src/boost/libs/container/test/flat_tree_test.cpp new file mode 100644 index 00000000..e94c0892 --- /dev/null +++ b/src/boost/libs/container/test/flat_tree_test.cpp @@ -0,0 +1,156 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include + +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +using namespace boost::container; + +typedef boost::container::dtl::pair pair_t; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +namespace dtl { + +template class flat_tree + < pair_t + , select1st + , std::less + , test::simple_allocator + >; + +template class flat_tree + < pair_t + , select1st + , std::less + , std::allocator + >; + +template class flat_tree + < pair_t + , select1st + , std::less + , small_vector + >; + +template class flat_tree + < pair_t + , select1st + , std::less + , stable_vector + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , test::simple_allocator + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , std::allocator + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , small_vector + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , stable_vector + >; + +template class flat_tree +< test::movable_and_copyable_int + , identity + , std::less + , static_vector +>; + +} //dtl { +}} //boost::container + +#if (__cplusplus > 201103L) +#include + +namespace boost{ +namespace container{ +namespace dtl{ + +template class flat_tree +< test::movable_and_copyable_int + , identity + , std::less + , std::vector +>; + +template class flat_tree +< pair_t + , select1st + , std::less + , std::vector +>; + +} //dtl { +}} //boost::container + +#endif + +int main () +{ + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default + { + typedef boost::container::dtl::flat_tree, + std::less, void> tree; + typedef tree::container_type container_type; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::dtl::flat_tree, + std::less, std::allocator > tree; + typedef tree::container_type container_type; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/boost/libs/container/test/global_resource_test.cpp b/src/boost/libs/container/test/global_resource_test.cpp new file mode 100644 index 00000000..bb6e9683 --- /dev/null +++ b/src/boost/libs/container/test/global_resource_test.cpp @@ -0,0 +1,127 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include "derived_from_memory_resource.hpp" + +#include +#include + +using namespace boost::container; +using namespace boost::container::pmr; + +#ifdef BOOST_MSVC +#pragma warning (push) +#pragma warning (disable : 4290) +#endif + +#if __cplusplus >= 201103L +#define BOOST_CONTAINER_NEW_EXCEPTION_SPECIFIER +#define BOOST_CONTAINER_DELETE_EXCEPTION_SPECIFIER noexcept +#else +#define BOOST_CONTAINER_NEW_EXCEPTION_SPECIFIER throw(std::bad_alloc) +#define BOOST_CONTAINER_DELETE_EXCEPTION_SPECIFIER throw() +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC >= 50000) +#pragma GCC diagnostic ignored "-Wsized-deallocation" +#endif + +//ASAN does not support operator new overloading +#ifndef BOOST_CONTAINER_ASAN + +std::size_t allocation_count = 0; + +void* operator new[](std::size_t count) BOOST_CONTAINER_NEW_EXCEPTION_SPECIFIER +{ + ++allocation_count; + return std::malloc(count); +} + +void operator delete[](void *p) BOOST_CONTAINER_DELETE_EXCEPTION_SPECIFIER +{ + --allocation_count; + return std::free(p); +} + +#endif //BOOST_CONTAINER_ASAN + +#ifdef BOOST_MSVC +#pragma warning (pop) +#endif + +#ifndef BOOST_CONTAINER_ASAN + +void test_new_delete_resource() +{ + //Make sure new_delete_resource calls new[]/delete[] + std::size_t memcount = allocation_count; + memory_resource *mr = new_delete_resource(); + //each time should return the same pointer + BOOST_TEST(mr == new_delete_resource()); + #if !defined(BOOST_CONTAINER_DYNAMIC_LINKING) //No new delete replacement possible new_delete is a DLL + BOOST_TEST(memcount == allocation_count); + #endif + void *addr = mr->allocate(16, 1); + #if !defined(BOOST_CONTAINER_DYNAMIC_LINKING) //No new delete replacement possible new_delete is a DLL + BOOST_TEST((allocation_count - memcount) == 1); + #endif + mr->deallocate(addr, 16, 1); + BOOST_TEST(memcount == allocation_count); +} + +#endif //BOOST_CONTAINER_ASAN + +void test_null_memory_resource() +{ + //Make sure it throw or returns null + memory_resource *mr = null_memory_resource(); + #if !defined(BOOST_NO_EXCEPTIONS) + bool bad_allocexception_thrown = false; + try{ + mr->allocate(1, 1); + } + catch(std::bad_alloc&) { + bad_allocexception_thrown = true; + } + catch(...) { + } + BOOST_TEST(bad_allocexception_thrown == true); + #else + BOOST_TEST(0 == mr->allocate(1, 1)); + #endif +} + +void test_default_resource() +{ + //Default resource must be new/delete before set_default_resource + BOOST_TEST(get_default_resource() == new_delete_resource()); + //Set default resource and obtain previous + derived_from_memory_resource d; + memory_resource *prev_default = set_default_resource(&d); + BOOST_TEST(get_default_resource() == &d); + //Set default resource with null, which should be new/delete + prev_default = set_default_resource(0); + BOOST_TEST(prev_default == &d); + BOOST_TEST(get_default_resource() == new_delete_resource()); +} + +int main() +{ + #ifndef BOOST_CONTAINER_ASAN + test_new_delete_resource(); + #endif + test_null_memory_resource(); + test_default_resource(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/hash_table_test.cppx b/src/boost/libs/container/test/hash_table_test.cppx new file mode 100644 index 00000000..e69de29b diff --git a/src/boost/libs/container/test/input_from_forward_iterator.hpp b/src/boost/libs/container/test/input_from_forward_iterator.hpp new file mode 100644 index 00000000..9436ceff --- /dev/null +++ b/src/boost/libs/container/test/input_from_forward_iterator.hpp @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP +#define BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP + +#include + +namespace boost{ +namespace container { +namespace test{ + +template +class input_iterator_wrapper + : public boost::container::iterator< std::input_iterator_tag + , typename boost::container::iterator_traits::value_type + , typename boost::container::iterator_traits::difference_type + , typename boost::container::iterator_traits::pointer + , typename boost::container::iterator_traits::reference + > +{ + FwdIterator m_it; + + public: + input_iterator_wrapper() + : m_it(0) + {} + + explicit input_iterator_wrapper(FwdIterator it) + : m_it(it) + {} + + //Default copy constructor... + //input_iterator_wrapper(const input_iterator_wrapper&); + + //Default assignment... + //input_iterator_wrapper &operator=(const input_iterator_wrapper&); + + //Default destructor... + //~input_iterator_wrapper(); + + typename boost::container::iterator_traits::reference operator*() const + { return *m_it; } + + typename boost::container::iterator_traits::pointer operator->() const + { return m_it.operator->(); } + + input_iterator_wrapper& operator++() + { ++m_it; return *this; } + + input_iterator_wrapper operator++(int ) + { + input_iterator_wrapper tmp(m_it); + ++m_it; + return tmp; + } + + friend bool operator==(const input_iterator_wrapper &left, const input_iterator_wrapper &right) + { return left.m_it == right.m_it; } + + friend bool operator!=(const input_iterator_wrapper &left, const input_iterator_wrapper &right) + { return left.m_it != right.m_it; } +}; + +template +input_iterator_wrapper make_input_from_forward_iterator(const FwdIterator &it) +{ return input_iterator_wrapper(it); } + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#endif //BOOST_CONTAINER_TEST_FORWARD_TO_INPUT_ITERATOR_HPP diff --git a/src/boost/libs/container/test/insert_test.hpp b/src/boost/libs/container/test/insert_test.hpp new file mode 100644 index 00000000..cb862f3c --- /dev/null +++ b/src/boost/libs/container/test/insert_test.hpp @@ -0,0 +1,75 @@ +#ifndef BOOST_CONTAINER_TEST_INSERT_TEST_HPP +#define BOOST_CONTAINER_TEST_INSERT_TEST_HPP + +// Copyright (C) 2013 Cromwell D. Enage +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include "check_equal_containers.hpp" + +namespace boost { +namespace container { +namespace test { + +template +void + test_insert_range( + std::deque &std_deque + , SeqContainer &seq_container + , std::deque const& input_deque + , std::size_t index + ) +{ + BOOST_TEST(CheckEqualContainers(std_deque, seq_container)); + + std_deque.insert( + std_deque.begin() + index + , input_deque.begin() + , input_deque.end() + ); + + seq_container.insert( + seq_container.begin() + index + , input_deque.begin() + , input_deque.end() + ); + BOOST_TEST(CheckEqualContainers(std_deque, seq_container)); +} + +template +bool test_range_insertion() +{ + int err_count = boost::report_errors(); + typedef typename SeqContainer::value_type value_type; + std::deque input_deque; + for (int element = -10; element < 10; ++element) + { + input_deque.push_back(element + 20); + } + + for (std::size_t i = 0; i <= input_deque.size(); ++i) + { + std::deque std_deque; + ::boost::movelib::unique_ptr const pseqcontainer = ::boost::movelib::make_unique(); + SeqContainer &seq_container = *pseqcontainer; + + for (int element = -10; element < 10; ++element) + { + std_deque.push_back(element); + seq_container.push_back(value_type(element)); + } + test_insert_range(std_deque, seq_container, input_deque, i); + } + + return err_count == boost::report_errors(); +} + + +} //namespace test { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_TEST_INSERT_TEST_HPP diff --git a/src/boost/libs/container/test/insert_vs_emplace_test.cpp b/src/boost/libs/container/test/insert_vs_emplace_test.cpp new file mode 100644 index 00000000..b91a693c --- /dev/null +++ b/src/boost/libs/container/test/insert_vs_emplace_test.cpp @@ -0,0 +1,498 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Howard Hinnant 2014. +// (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This testcase is based on H. Hinnant's article "Insert vs. Emplace", +// (http://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html) +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +class X +{ + int i_; + int* p_; + + BOOST_COPYABLE_AND_MOVABLE(X) + +public: + struct special + { + unsigned c; + unsigned dt; + unsigned cc; + unsigned ca; + unsigned mc; + unsigned ma; + + friend bool operator==(const special &l, const special &r) + { return l.c == r.c && l.dt == r.dt && l.cc == r.cc && l.ca == r.ca && l.mc == r.mc && l.ma == r.ma; } + }; + static special sp; + + X(int i, int* p) + : i_(i) + , p_(p) + { +// std::cout << "X(int i, int* p)\n"; + sp.c++; + } + + ~X() + { +// std::cout << "~X()\n"; + sp.dt++; + } + + X(const X& x) + : i_(x.i_) + , p_(x.p_) + { +// std::cout << "X(const X& x)\n"; + sp.cc++; + } + + X& operator=(BOOST_COPY_ASSIGN_REF(X) x) + { + + i_ = x.i_; + p_ = x.p_; +// std::cout << "X& operator=(const X& x)\n"; + sp.ca++; + return *this; + } + + X(BOOST_RV_REF(X) x) BOOST_NOEXCEPT_OR_NOTHROW + : i_(x.i_) + , p_(x.p_) + { +// std::cout << "X(X&& x)\n"; + sp.mc++; + } + + X& operator=(BOOST_RV_REF(X) x) BOOST_NOEXCEPT_OR_NOTHROW + { + + i_ = x.i_; + p_ = x.p_; +// std::cout << "X& operator=(X&& x)\n"; + sp.ma++; + return *this; + } + +}; + +std::ostream& +operator<<(std::ostream& os, X::special const& sp) +{ + os << "Const: " << sp.c << '\n'; + os << "Destr: " << sp.dt << '\n'; + os << "CopyC: " << sp.cc << '\n'; + os << "CopyA: " << sp.ca << '\n'; + os << "MoveC: " << sp.mc << '\n'; + os << "MoveA: " << sp.ma << '\n'; + os << "Total: " << (sp.c + sp.dt + sp.cc + sp.ca + sp.mc + sp.ma) << '\n'; + return os; +} + +X::special X::sp = X::special(); + +const X produce_const_prvalue() +{ return X(0, 0); } + +int main() +{ + X::special insert_results; + X::special emplace_results; + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--insert lvalue no reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), x); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace lvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), x); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--insert xvalue no reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace xvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace const prvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), produce_const_prvalue()); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace const prvalue no reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), produce_const_prvalue()); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--insert rvalue no reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--emplace rvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + //With emulated move semantics an extra copy is unavoidable + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST_EQ(insert_results == emplace_results, true); + #endif + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--insert lvalue reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), x); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace lvalue reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), x); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--insert xvalue reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace xvalue reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--insert rvalue reallocation--\n"; + X::sp = X::special(); + v.insert(v.begin(), X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--emplace rvalue reallocation--\n"; + X::sp = X::special(); + v.emplace(v.begin(), X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + //With emulated move semantics an extra copy is unavoidable + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST_EQ(insert_results == emplace_results, true); + #endif + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--push_back lvalue no reallocation--\n"; + X::sp = X::special(); + v.push_back(x); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace_back lvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace_back(x); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--push_back xvalue no reallocation--\n"; + X::sp = X::special(); + v.push_back(boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace_back xvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace_back(boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--push_back rvalue no reallocation--\n"; + X::sp = X::special(); + v.push_back(X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(4); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--emplace_back rvalue no reallocation--\n"; + X::sp = X::special(); + v.emplace_back(X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + //With emulated move semantics an extra copy is unavoidable + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST_EQ(insert_results == emplace_results, true); + #endif + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--push_back lvalue reallocation--\n"; + X::sp = X::special(); + v.push_back(x); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace_back lvalue reallocation--\n"; + X::sp = X::special(); + v.emplace_back(x); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--push_back xvalue reallocation--\n"; + X::sp = X::special(); + v.push_back(boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + X x(0,0); + std::cout << "--emplace_back xvalue reallocation--\n"; + X::sp = X::special(); + v.emplace_back(boost::move(x)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + BOOST_TEST_EQ(insert_results == emplace_results, true); + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--push_back rvalue reallocation--\n"; + X::sp = X::special(); + v.push_back(X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + insert_results = X::sp; + } + { + boost::container::vector v; + v.reserve(3); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + v.push_back(X(0,0)); + std::cout << "--emplace_back rvalue reallocation--\n"; + X::sp = X::special(); + v.emplace_back(X(0,0)); + std::cout << X::sp; + std::cout << "----\n"; + emplace_results = X::sp; + } + //With emulated move semantics an extra copy is unavoidable + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST_EQ(insert_results == emplace_results, true); + #endif + return boost::report_errors(); +} diff --git a/src/boost/libs/container/test/list_test.cpp b/src/boost/libs/container/test/list_test.cpp new file mode 100644 index 00000000..c4f9f41d --- /dev/null +++ b/src/boost/libs/container/test/list_test.cpp @@ -0,0 +1,286 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "dummy_test_allocator.hpp" +#include +#include "movable_int.hpp" +#include "list_test.hpp" +#include "propagate_allocator_test.hpp" +#include "emplace_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors +template class boost::container::list + < test::movable_and_copyable_int + , test::simple_allocator >; + +template class boost::container::list + < test::movable_and_copyable_int + , adaptive_pool >; + +namespace dtl { + +template class iterator_from_iiterator + >::container_type::iterator, true >; +template class iterator_from_iiterator + >::container_type::iterator, false>; + +} + +}} + +class recursive_list +{ +public: + int id_; + list list_; + list::iterator it_; + list::const_iterator cit_; + list::reverse_iterator rit_; + list::const_reverse_iterator crit_; + + recursive_list &operator=(const recursive_list &o) + { list_ = o.list_; return *this; } +}; + +void recursive_list_test()//Test for recursive types +{ + list recursive, copy; + //Test to test both move emulations + if(!copy.size()){ + copy = recursive; + } +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef list< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + if(test::list_test()) + return 1; + + return 0; +} + +bool test_support_for_initializer_list() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + const std::initializer_list il = {1, 10}; + const list expectedList(il.begin(), il.end()); + + const list testConstructor((il)); + if(testConstructor != expectedList) + return false; + + const list testConstructorAllocator(il, list::allocator_type()); + if (testConstructorAllocator != expectedList) + return false; + + list testAssignOperator = {10, 11}; + testAssignOperator = il; + if(testAssignOperator != expectedList) + return false; + + list testAssignMethod = {99}; + testAssignMethod = il; + if(testAssignMethod != expectedList) + return false; + + list testInsertMethod; + testInsertMethod.insert(testInsertMethod.cbegin(), il); + if(testInsertMethod != testInsertMethod) + return false; + + return true; +#endif + return true; +} + +struct boost_container_list; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::list type; + }; +}; + +}}} //namespace boost::container::test + +int main () +{ + recursive_list_test(); + { + //Now test move semantics + list original; + list move_ctor(boost::move(original)); + list move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + // int variants + if (test::list_test >, true>()) + return 1; + if (test::list_test, true>()) + return 1; + if (test::list_test >, true>()) + return 1; + if (test::list_test, true>()) + return 1; + if (test::list_test, true>()) + return 1; + if (test::list_test, true>()) + return 1; + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); + + if(!boost::container::test::test_emplace, Options>()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Initializer lists + //////////////////////////////////// + if(!test_support_for_initializer_list()) + return 1; + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::list cont_int; + cont_int a; a.push_back(0); a.push_back(1); a.push_back(2); + boost::intrusive::test::test_iterator_bidirectional< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //////////////////////////////////// + // Constructor Template Auto Deduction Tests + //////////////////////////////////// + { + auto gold = std::list{ 1, 2, 3 }; + auto test = boost::container::list(gold.begin(), gold.end()); + if (test.size() != 3) { + return 1; + } + if (test.front() != 1) + return 1; + test.pop_front(); + if (test.front() != 2) + return 1; + test.pop_front(); + if (test.front() != 3) + return 1; + test.pop_front(); + } + { + auto gold = std::list{ 1, 2, 3 }; + auto test = boost::container::list(gold.begin(), gold.end(), new_allocator()); + if (test.size() != 3) { + return 1; + } + if (test.front() != 1) + return 1; + test.pop_front(); + if (test.front() != 2) + return 1; + test.pop_front(); + if (test.front() != 3) + return 1; + test.pop_front(); + } +#endif + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::list cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::list > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} + +#include diff --git a/src/boost/libs/container/test/list_test.hpp b/src/boost/libs/container/test/list_test.hpp new file mode 100644 index 00000000..9640ec09 --- /dev/null +++ b/src/boost/libs/container/test/list_test.hpp @@ -0,0 +1,469 @@ +//////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +//////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_LIST_TEST_HEADER +#define BOOST_CONTAINER_TEST_LIST_TEST_HEADER + +#include +#include +#include "check_equal_containers.hpp" +#include "print_container.hpp" +#include "input_from_forward_iterator.hpp" +#include +#include +#include + +#include +#include //std::greater + +namespace boost{ +namespace container { +namespace test{ + +template +bool list_copyable_only(V1 &, V2 &, boost::container::dtl::false_type) +{ + return true; +} + +//Function to check if both sets are equal +template +bool list_copyable_only(V1 &boostlist, V2 &stdlist, boost::container::dtl::true_type) +{ + typedef typename V1::value_type IntType; + boostlist.insert(boostlist.end(), 50, IntType(1)); + stdlist.insert(stdlist.end(), 50, 1); + if(!test::CheckEqualContainers(boostlist, stdlist)) return false; + + { + IntType move_me(1); + boostlist.insert(boostlist.begin(), 50, boost::move(move_me)); + stdlist.insert(stdlist.begin(), 50, 1); + if(!test::CheckEqualContainers(boostlist, stdlist)) return false; + } + { + IntType move_me(2); + boostlist.assign(boostlist.size()/2, boost::move(move_me)); + stdlist.assign(stdlist.size()/2, 2); + if(!test::CheckEqualContainers(boostlist, stdlist)) return false; + } + { + IntType move_me(3); + boostlist.assign(boostlist.size()*3-1, boost::move(move_me)); + stdlist.assign(stdlist.size()*3-1, 3); + if(!test::CheckEqualContainers(boostlist, stdlist)) return false; + } + + { + IntType copy_me(3); + const IntType ccopy_me(3); + boostlist.push_front(copy_me); + stdlist.push_front(int(3)); + boostlist.push_front(ccopy_me); + stdlist.push_front(int(3)); + if(!test::CheckEqualContainers(boostlist, stdlist)) return false; + } + { //List(const List &) + ::boost::movelib::unique_ptr const pv1 = ::boost::movelib::make_unique(boostlist); + ::boost::movelib::unique_ptr const pv2 = ::boost::movelib::make_unique(stdlist); + + V1 &v1 = *pv1; + V2 &v2 = *pv2; + + boostlist.clear(); + stdlist.clear(); + boostlist.assign(v1.begin(), v1.end()); + stdlist.assign(v2.begin(), v2.end()); + if(!test::CheckEqualContainers(boostlist, stdlist)) return 1; + } + { //List(const List &, alloc) + ::boost::movelib::unique_ptr const pv1 = ::boost::movelib::make_unique(boostlist, typename V1::allocator_type()); + ::boost::movelib::unique_ptr const pv2 = ::boost::movelib::make_unique(stdlist); + + V1 &v1 = *pv1; + V2 &v2 = *pv2; + + boostlist.clear(); + stdlist.clear(); + boostlist.assign(v1.begin(), v1.end()); + stdlist.assign(v2.begin(), v2.end()); + if(!test::CheckEqualContainers(boostlist, stdlist)) return 1; + } + + return true; +} + +template +struct list_push_data_function +{ + template + static int execute(int max, MyBoostList &boostlist, MyStdList &stdlist) + { + typedef typename MyBoostList::value_type IntType; + for(int i = 0; i < max; ++i){ + IntType move_me(i); + boostlist.push_back(boost::move(move_me)); + stdlist.push_back(i); + boostlist.push_front(IntType(i)); + stdlist.push_front(int(i)); + } + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + return 0; + } +}; + +template<> +struct list_push_data_function +{ + template + static int execute(int max, MyBoostList &boostlist, MyStdList &stdlist) + { + typedef typename MyBoostList::value_type IntType; + for(int i = 0; i < max; ++i){ + IntType move_me(i); + boostlist.push_front(boost::move(move_me)); + stdlist.push_front(i); + boostlist.push_front(IntType(i)); + stdlist.push_front(int(i)); + } + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + return 0; + } +}; + +template +struct list_pop_back_function +{ + template + static int execute(MyBoostList &boostlist, MyStdList &stdlist) + { + boostlist.pop_back(); + stdlist.pop_back(); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + return 0; + } +}; + +template<> +struct list_pop_back_function +{ + template + static int execute(MyBoostList &boostlist, MyStdList &stdlist) + { + (void)boostlist; (void)stdlist; + return 0; + } +}; + +template +int list_test (bool copied_allocators_equal = true) +{ + typedef std::list MyStdList; + typedef typename MyBoostList::value_type IntType; + const int max = 100; + typedef list_push_data_function push_data_t; + + { //List(n) + ::boost::movelib::unique_ptr const pboostlist = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const pstdlist = ::boost::movelib::make_unique(100); + if(!test::CheckEqualContainers(*pboostlist, *pstdlist)) return 1; + } + { //List(n, alloc) + ::boost::movelib::unique_ptr const pboostlist = ::boost::movelib::make_unique(100, typename MyBoostList::allocator_type()); + ::boost::movelib::unique_ptr const pstdlist = ::boost::movelib::make_unique(100); + if(!test::CheckEqualContainers(*pboostlist, *pstdlist)) return 1; + } + { //List(List &&) + ::boost::movelib::unique_ptr const stdlistp = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostlistp2 = ::boost::movelib::make_unique(::boost::move(*boostlistp)); + if(!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; + } + { //List(List &&, alloc) + ::boost::movelib::unique_ptr const stdlistp = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostlistp2 = ::boost::movelib::make_unique + (::boost::move(*boostlistp), typename MyBoostList::allocator_type()); + if(!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; + } + { //List operator=(List &&) + ::boost::movelib::unique_ptr const stdlistp = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostlistp = ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostlistp2 = ::boost::movelib::make_unique(); + *boostlistp2 = ::boost::move(*boostlistp); + if(!test::CheckEqualContainers(*boostlistp2, *stdlistp)) return 1; + } + + ::boost::movelib::unique_ptr const pboostlist = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdlist = ::boost::movelib::make_unique(); + + MyBoostList &boostlist = *pboostlist; + MyStdList &stdlist = *pstdlist; + + if(push_data_t::execute(max, boostlist, stdlist)){ + return 1; + } + + boostlist.erase(boostlist.begin()++); + stdlist.erase(stdlist.begin()++); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + if(list_pop_back_function::execute(boostlist, stdlist)){ + return 1; + } + + boostlist.pop_front(); + stdlist.pop_front(); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(&aux_vect[50])); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + boostlist.assign(boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + stdlist.assign(&aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + } + + if(copied_allocators_equal){ + boostlist.sort(); + stdlist.sort(); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + } + + boostlist.reverse(); + stdlist.reverse(); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + boostlist.reverse(); + stdlist.reverse(); + if(!CheckEqualContainers(boostlist, stdlist)) return 1; + + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + typename MyBoostList::iterator old_begin = boostlist.begin(); + typename MyBoostList::iterator it_insert = + boostlist.insert(boostlist.begin() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(&aux_vect[50])); + if(it_insert != boostlist.begin() || boost::container::iterator_distance(it_insert, old_begin) != 50) + return 1; + + stdlist.insert(stdlist.begin(), &aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + old_begin = boostlist.begin(); + it_insert = boostlist.insert(boostlist.end() + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[50]))); + if(boost::container::iterator_distance(it_insert, boostlist.end()) != 50) + return 1; + stdlist.insert(stdlist.end(), &aux_vect2[0], &aux_vect2[50]); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + } + + boostlist.unique(); + stdlist.unique(); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + + if(copied_allocators_equal){ + boostlist.sort(std::greater()); + stdlist.sort(std::greater()); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + } + + for(int i = 0; i < max; ++i){ + IntType new_int(i); + boostlist.insert(boostlist.end(), boost::move(new_int)); + stdlist.insert(stdlist.end(), i); + if(!test::CheckEqualContainers(boostlist, stdlist)) return 1; + } + if(!test::CheckEqualContainers(boostlist, stdlist)) return 1; + + boostlist.resize(25); + stdlist.resize(25); + boostlist.resize(50); + stdlist.resize(50); + boostlist.resize(0); + stdlist.resize(0); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + + //some comparison operators + if(!(boostlist == boostlist)) + return 1; + if(boostlist != boostlist) + return 1; + if(boostlist < boostlist) + return 1; + if(boostlist > boostlist) + return 1; + if(!(boostlist <= boostlist)) + return 1; + if(!(boostlist >= boostlist)) + return 1; + + if(push_data_t::execute(max, boostlist, stdlist)){ + return 1; + } + { + MyBoostList otherboostlist(boostlist.get_allocator()); + MyStdList otherstdlist; + + int listsize = (int)boostlist.size(); + + if(push_data_t::execute(listsize, boostlist, stdlist)){ + return 1; + } + + if(copied_allocators_equal){ + boostlist.splice(boostlist.begin(), otherboostlist); + stdlist.splice(stdlist.begin(), otherstdlist); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + } + + listsize = (int)boostlist.size(); + + if(push_data_t::execute(listsize, boostlist, stdlist)){ + return 1; + } + + if(push_data_t::execute(listsize, otherboostlist, otherstdlist)){ + return 1; + } + + if(copied_allocators_equal){ + boostlist.sort(std::greater()); + stdlist.sort(std::greater()); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + + otherboostlist.sort(std::greater()); + otherstdlist.sort(std::greater()); + if(!CheckEqualContainers(otherboostlist, otherstdlist)) + return 1; + + boostlist.merge(otherboostlist, std::greater()); + stdlist.merge(otherstdlist, std::greater()); + if(!CheckEqualContainers(boostlist, stdlist)) + return 1; + } + + if(!list_copyable_only(boostlist, stdlist + ,dtl::bool_::value>())){ + return 1; + } + } + return 0; +} + +template +bool test_list_methods_with_initializer_list_as_argument_for() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + const std::initializer_list il = {5, 10, 15}; + const List expected_list(il.begin(), il.end()); + { + List sl = il; + if(sl != expected_list) + return false; + } + + { + List sl = {1, 2}; + sl = il; + if(sl != expected_list) + return false; + } + { + List sl({ 1, 2 }, typename List::allocator_type()); + sl = il; + if (sl != expected_list) + return false; + } + { + List sl = {4, 5}; + sl.assign(il); + if(sl != expected_list) + return false; + } + + { + List sl = {15}; + sl.insert(sl.cbegin(), {5, 10}); + if(sl != expected_list) + return false; + } + + { + List sl = {5}; + sl.insert_after(sl.cbegin(), {10, 15}); + if(sl != expected_list) + return false; + } + return true; +#endif + return true; +} + + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif diff --git a/src/boost/libs/container/test/map_test.cpp b/src/boost/libs/container/test/map_test.cpp new file mode 100644 index 00000000..74483037 --- /dev/null +++ b/src/boost/libs/container/test/map_test.cpp @@ -0,0 +1,693 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include + +#include "print_container.hpp" +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" +#include "map_test.hpp" +#include "propagate_allocator_test.hpp" +#include "emplace_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +typedef std::pair pair_t; + +class recursive_map +{ + public: + recursive_map & operator=(const recursive_map &x) + { id_ = x.id_; map_ = x.map_; return *this; } + + int id_; + map map_; + map::iterator it_; + map::const_iterator cit_; + map::reverse_iterator rit_; + map::const_reverse_iterator crit_; + + friend bool operator< (const recursive_map &a, const recursive_map &b) + { return a.id_ < b.id_; } +}; + +class recursive_multimap +{ + public: + recursive_multimap & operator=(const recursive_multimap &x) + { id_ = x.id_; multimap_ = x.multimap_; return *this; } + + int id_; + multimap multimap_; + multimap::iterator it_; + multimap::const_iterator cit_; + multimap::reverse_iterator rit_; + multimap::const_reverse_iterator crit_; + + friend bool operator< (const recursive_multimap &a, const recursive_multimap &b) + { return a.id_ < b.id_; } +}; + +template +void test_move() +{ + //Now test move semantics + C original; + original.emplace(); + C move_ctor(boost::move(original)); + C move_assign; + move_assign.emplace(); + move_assign = boost::move(move_ctor); + move_assign.swap(original); +} + +bool node_type_test() +{ + using namespace boost::container; + { + typedef map map_type; + map_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_11(11), mv_12(12), mv_13(13); + src.try_emplace(boost::move(mv_1), boost::move(mv_11)); + src.try_emplace(boost::move(mv_2), boost::move(mv_12)); + src.try_emplace(boost::move(mv_3), boost::move(mv_13)); + } + if(src.size() != 3) + return false; + + map_type dst; + { + test::movable_int mv_3(3), mv_33(33); + dst.try_emplace(boost::move(mv_3), boost::move(mv_33)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_33(33); + const test::movable_int mv_13(13); + map_type::insert_return_type r; + + r = dst.insert(src.extract(mv_33)); // Key version, try to insert empty node + if(! (r.position == dst.end() && r.inserted == false && r.node.empty()) ) + return false; + r = dst.insert(src.extract(src.find(mv_1))); // Iterator version, successful + if(! (r.position == dst.find(mv_1) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(dst.begin(), src.extract(mv_2)); // Key type version, successful + if(! (r.position == dst.find(mv_2) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(src.extract(mv_3)); // Key type version, unsuccessful + + if(!src.empty()) + return false; + if(dst.size() != 3) + return false; + if(! (r.position == dst.find(mv_3) && r.inserted == false && r.node.key() == mv_3 && r.node.mapped() == mv_13) ) + return false; + } + + { + typedef multimap multimap_type; + multimap_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_3bis(3), mv_11(11), mv_12(12), mv_13(13), mv_23(23); + src.emplace(boost::move(mv_1), boost::move(mv_11)); + src.emplace(boost::move(mv_2), boost::move(mv_12)); + src.emplace(boost::move(mv_3), boost::move(mv_13)); + src.emplace_hint(src.begin(), boost::move(mv_3bis), boost::move(mv_23)); + } + if(src.size() != 4) + return false; + + multimap_type dst; + { + test::movable_int mv_3(3), mv_33(33); + dst.emplace(boost::move(mv_3), boost::move(mv_33)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_4(4); + const test::movable_int mv_33(33); + const test::movable_int mv_13(13); + const test::movable_int mv_23(23); + multimap_type::iterator r; + + multimap_type::node_type nt(src.extract(mv_3)); + r = dst.insert(dst.begin(), boost::move(nt)); + if(! (r->first == mv_3 && r->second == mv_23 && dst.find(mv_3) == r && nt.empty()) ) + return false; + + nt = src.extract(src.find(mv_1)); + r = dst.insert(boost::move(nt)); // Iterator version, successful + if(! (r->first == mv_1 && nt.empty()) ) + return false; + + nt = src.extract(mv_2); + r = dst.insert(boost::move(nt)); // Key type version, successful + if(! (r->first == mv_2 && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_3)); // Key type version, successful + if(! (r->first == mv_3 && r->second == mv_13 && r == --multimap_type::iterator(dst.upper_bound(mv_3)) && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_4)); // Key type version, unsuccessful + if(! (r == dst.end()) ) + return false; + + if(!src.empty()) + return false; + if(dst.size() != 5) + return false; + } + return true; +} + +template +struct GetAllocatorMap +{ + template + struct apply + { + typedef map< ValueType + , ValueType + , std::less + , typename allocator_traits + ::template portable_rebind_alloc< std::pair >::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type + > map_type; + + typedef multimap< ValueType + , ValueType + , std::less + , typename allocator_traits + ::template portable_rebind_alloc< std::pair >::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type + > multimap_type; + }; +}; + +struct boost_container_map; +struct boost_container_multimap; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef typename boost::container::allocator_traits:: + template portable_rebind_alloc >::type TypeAllocator; + typedef boost::container::map, TypeAllocator> type; + }; +}; + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef typename boost::container::allocator_traits:: + template portable_rebind_alloc >::type TypeAllocator; + typedef boost::container::multimap, TypeAllocator> type; + }; +}; + +void test_merge_from_different_comparison() +{ + map map1; + map > map2; + map1.merge(map2); +} + +bool test_heterogeneous_lookups() +{ + typedef map map_t; + typedef multimap mmap_t; + typedef map_t::value_type value_type; + + map_t map1; + mmap_t mmap1; + + const map_t &cmap1 = map1; + const mmap_t &cmmap1 = mmap1; + + if(!map1.insert_or_assign(1, 'a').second) + return false; + if( map1.insert_or_assign(1, 'b').second) + return false; + if(!map1.insert_or_assign(2, 'c').second) + return false; + if( map1.insert_or_assign(2, 'd').second) + return false; + if(!map1.insert_or_assign(3, 'e').second) + return false; + + if(map1.insert_or_assign(1, 'a').second) + return false; + if(map1.insert_or_assign(1, 'b').second) + return false; + if(map1.insert_or_assign(2, 'c').second) + return false; + if(map1.insert_or_assign(2, 'd').second) + return false; + if(map1.insert_or_assign(3, 'e').second) + return false; + + mmap1.insert(value_type(1, 'a')); + mmap1.insert(value_type(1, 'b')); + mmap1.insert(value_type(2, 'c')); + mmap1.insert(value_type(2, 'd')); + mmap1.insert(value_type(3, 'e')); + + const test::non_copymovable_int find_me(2); + + //find + if(map1.find(find_me)->second != 'd') + return false; + if(cmap1.find(find_me)->second != 'd') + return false; + if(mmap1.find(find_me)->second != 'c') + return false; + if(cmmap1.find(find_me)->second != 'c') + return false; + + //count + if(map1.count(find_me) != 1) + return false; + if(cmap1.count(find_me) != 1) + return false; + if(mmap1.count(find_me) != 2) + return false; + if(cmmap1.count(find_me) != 2) + return false; + + //contains + if(!map1.contains(find_me)) + return false; + if(!cmap1.contains(find_me)) + return false; + if(!mmap1.contains(find_me)) + return false; + if(!cmmap1.contains(find_me)) + return false; + + //lower_bound + if(map1.lower_bound(find_me)->second != 'd') + return false; + if(cmap1.lower_bound(find_me)->second != 'd') + return false; + if(mmap1.lower_bound(find_me)->second != 'c') + return false; + if(cmmap1.lower_bound(find_me)->second != 'c') + return false; + + //upper_bound + if(map1.upper_bound(find_me)->second != 'e') + return false; + if(cmap1.upper_bound(find_me)->second != 'e') + return false; + if(mmap1.upper_bound(find_me)->second != 'e') + return false; + if(cmmap1.upper_bound(find_me)->second != 'e') + return false; + + //equal_range + if(map1.equal_range(find_me).first->second != 'd') + return false; + if(cmap1.equal_range(find_me).second->second != 'e') + return false; + if(mmap1.equal_range(find_me).first->second != 'c') + return false; + if(cmmap1.equal_range(find_me).second->second != 'e') + return false; + + return true; +} + +bool constructor_template_auto_deduction_test() +{ + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + using namespace boost::container; + const std::size_t NumElements = 100; + { + std::map int_map; + for(std::size_t i = 0; i != NumElements; ++i){ + int_map.insert(std::map::value_type(static_cast(i), static_cast(i))); + } + std::multimap int_mmap; + for (std::size_t i = 0; i != NumElements; ++i) { + int_mmap.insert(std::multimap::value_type(static_cast(i), static_cast(i))); + } + + typedef std::less comp_int_t; + typedef std::allocator > alloc_pair_int_t; + + //range + { + auto fmap = map(int_map.begin(), int_map.end()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(int_mmap.begin(), int_mmap.end()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp + { + auto fmap = map(int_map.begin(), int_map.end(), comp_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(int_mmap.begin(), int_mmap.end(), comp_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp+alloc + { + auto fmap = map(int_map.begin(), int_map.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(int_mmap.begin(), int_mmap.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+alloc + { + auto fmap = map(int_map.begin(), int_map.end(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(int_mmap.begin(), int_mmap.end(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + + //ordered_unique_range / ordered_range + + //range + { + auto fmap = map(ordered_unique_range, int_map.begin(), int_map.end()); + if(!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(ordered_range, int_mmap.begin(), int_mmap.end()); + if(!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp + { + auto fmap = map(ordered_unique_range, int_map.begin(), int_map.end(), comp_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(ordered_range, int_mmap.begin(), int_mmap.end(), comp_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+comp+alloc + { + auto fmap = map(ordered_unique_range, int_map.begin(), int_map.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(ordered_range, int_mmap.begin(), int_mmap.end(), comp_int_t(), alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + //range+alloc + { + auto fmap = map(ordered_unique_range, int_map.begin(), int_map.end(),alloc_pair_int_t()); + if (!CheckEqualContainers(int_map, fmap)) + return false; + auto fmmap = multimap(ordered_range, int_mmap.begin(), int_mmap.end(),alloc_pair_int_t()); + if (!CheckEqualContainers(int_mmap, fmmap)) + return false; + } + } +#endif + + return true; +} + +}}} //namespace boost::container::test + +int main () +{ + //Recursive container instantiation + { + map map_; + multimap multimap_; + } + //Allocator argument container + { + map map_((map::allocator_type())); + multimap multimap_((multimap::allocator_type())); + } + //Now test move semantics + { + test_move >(); + test_move >(); + } + + //Test std::pair value type as tree has workarounds to make old std::pair + //implementations movable that can break things + { + boost::container::map s; + std::pair p; + s.insert(p); + s.emplace(p); + } + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + { + typedef std::map MyStdMap; + typedef std::multimap MyStdMultiMap; + + if (0 != test::map_test + < GetAllocatorMap, red_black_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, red_black_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, red_black_tree>" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetAllocatorMap, avl_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, avl_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, avl_tree>" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetAllocatorMap, scapegoat_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, scapegoat_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, scapegoat_tree>" << std::endl; + return 1; + } + + /////////// + + if (0 != test::map_test + < GetAllocatorMap, splay_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, splay_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, splay_tree>" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetAllocatorMap, red_black_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, red_black_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, red_black_tree>" << std::endl; + return 1; + } + + if (0 != test::map_test + < GetAllocatorMap, red_black_tree>::apply::map_type + , MyStdMap + , GetAllocatorMap, red_black_tree>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, red_black_tree>" << std::endl; + return 1; + } + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR); + if(!boost::container::test::test_emplace, MapOptions>()) + return 1; + if(!boost::container::test::test_emplace, MapOptions>()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + if(!boost::container::test::test_propagate_allocator()) + return 1; + + if (!boost::container::test::test_map_support_for_initialization_list_for >()) + return 1; + + if (!boost::container::test::test_map_support_for_initialization_list_for >()) + return 1; + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::map cont_int; + cont_int a; a.insert(cont_int::value_type(0, 9)); a.insert(cont_int::value_type(1, 9)); a.insert(cont_int::value_type(2, 9)); + boost::intrusive::test::test_iterator_bidirectional< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + { + typedef boost::container::multimap cont_int; + cont_int a; a.insert(cont_int::value_type(0, 9)); a.insert(cont_int::value_type(1, 9)); a.insert(cont_int::value_type(2, 9)); + boost::intrusive::test::test_iterator_bidirectional< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + + //////////////////////////////////// + // Node extraction/insertion testing functions + //////////////////////////////////// + if(!node_type_test()) + return 1; + + //////////////////////////////////// + // Constructor Template Auto Deduction test + //////////////////////////////////// + if (!test::constructor_template_auto_deduction_test()) { + return 1; + } + + if (!boost::container::test::instantiate_constructors, multimap >()) + return 1; + + test::test_merge_from_different_comparison(); + + if(!test::test_heterogeneous_lookups()) + return 1; + + //////////////////////////////////// + // Test optimize_size option + //////////////////////////////////// + // + // map + // + typedef map< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > rbmap_size_optimized_no; + + typedef map< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > avlmap_size_optimized_yes; + // + // multimap + // + typedef multimap< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > rbmmap_size_optimized_yes; + typedef multimap< int*, int*, std::less, std::allocator< std::pair > + , tree_assoc_options< optimize_size, tree_type >::type > avlmmap_size_optimized_no; + + BOOST_STATIC_ASSERT(sizeof(rbmmap_size_optimized_yes) < sizeof(rbmap_size_optimized_no)); + BOOST_STATIC_ASSERT(sizeof(avlmap_size_optimized_yes) < sizeof(avlmmap_size_optimized_no)); + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + { + typedef std::pair value_type; + // + // map + // + // default allocator + { + typedef boost::container::map cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(map, default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::map, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(map, std::allocator) test failed" << std::endl; + return 1; + } + } + // + // multimap + // + // default allocator + { + // default allocator + typedef boost::container::multimap cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multimap, default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::multimap, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multimap, std::allocator) test failed" << std::endl; + return 1; + } + } + } + + return 0; +} + +#include diff --git a/src/boost/libs/container/test/map_test.hpp b/src/boost/libs/container/test/map_test.hpp new file mode 100644 index 00000000..160c46ad --- /dev/null +++ b/src/boost/libs/container/test/map_test.hpp @@ -0,0 +1,1264 @@ +//////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +//////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_MAP_TEST_HEADER +#define BOOST_CONTAINER_TEST_MAP_TEST_HEADER + +#include +#include "check_equal_containers.hpp" +#include "print_container.hpp" +#include "movable_int.hpp" +#include +#include +#include +#include + +#include //pair +#include +#include + +#include + +namespace boost { namespace container { namespace test { + +BOOST_INTRUSIVE_HAS_MEMBER_FUNC_CALLED(has_member_rebalance, rebalance) + +}}} + +const int MaxElem = 50; + +template +bool operator ==(std::pair &p1, std::pair &p2) +{ + return p1.first == p2.first && p1.second == p2.second; +} + +namespace boost{ +namespace container { +namespace test{ + +template +void map_test_rebalanceable(C &, boost::container::dtl::false_type) +{} + +template +void map_test_rebalanceable(C &c, boost::container::dtl::true_type) +{ + c.rebalance(); +} + +template +int map_test_copyable(boost::container::dtl::false_type) +{ return 0; } + +template +int map_test_copyable(boost::container::dtl::true_type) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyStdMap::value_type StdPairType; + + ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultimap = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdmultimap = ::boost::movelib::make_unique(); + MyBoostMap &boostmap = *pboostmap; + MyStdMap &stdmap = *pstdmap; + MyBoostMultiMap &boostmultimap = *pboostmultimap; + MyStdMultiMap &stdmultimap = *pstdmultimap; + + //Just to test move aware catch conversions + boostmap.insert(boostmap.cbegin(), boostmap.cend()); + boostmultimap.insert(boostmultimap.cbegin(), boostmultimap.cend()); + boostmap.insert(boostmap.begin(), boostmap.end()); + boostmultimap.insert(boostmultimap.begin(), boostmultimap.end()); + + int i; + for(i = 0; i < MaxElem; ++i){ + { + IntType i1(i), i2(i); + IntPairType intpair1(boost::move(i1), boost::move(i2)); + boostmap.insert(boost::move(intpair1)); + stdmap.insert(StdPairType(i, i)); + } + { + IntType i1(i), i2(i); + IntPairType intpair2(boost::move(i1), boost::move(i2)); + boostmultimap.insert(boost::move(intpair2)); + stdmultimap.insert(StdPairType(i, i)); + } + } + if(!CheckEqualContainers(boostmap, stdmap)) return 1; + if(!CheckEqualContainers(boostmultimap, stdmultimap)) return 1; + { + //Now, test copy constructor + MyBoostMap boostmapcopy(boostmap); + MyStdMap stdmapcopy(stdmap); + MyBoostMultiMap boostmmapcopy(boostmultimap); + MyStdMultiMap stdmmapcopy(stdmultimap); + + if(!CheckEqualContainers(boostmapcopy, stdmapcopy)) + return 1; + if(!CheckEqualContainers(boostmmapcopy, stdmmapcopy)) + return 1; + + //And now assignment + boostmapcopy = boostmap; + stdmapcopy = stdmap; + boostmmapcopy = boostmultimap; + stdmmapcopy = stdmultimap; + + if(!CheckEqualContainers(boostmapcopy, stdmapcopy)) + return 1; + if(!CheckEqualContainers(boostmmapcopy, stdmmapcopy)) + return 1; + } + + return 0; +} + +template +int map_test_range() +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyStdMap::value_type StdValueType; + typedef typename MyStdMap::key_type StdKeyType; + typedef typename MyStdMap::mapped_type StdMappedType; + + //Test construction from a range + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + StdValueType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); + } + + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + MaxElem), typename MyBoostMap::key_compare()); + ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); + if(!CheckEqualContainers(*pboostmap, *pstdmap)) return 1; + + ::boost::movelib::unique_ptr const pboostmultimap = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(&aux_vect3[0] + MaxElem), typename MyBoostMap::key_compare()); + ::boost::movelib::unique_ptr const pstdmultimap = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); + if(!CheckEqualContainers(*pboostmultimap, *pstdmultimap)) return 1; + } + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + StdValueType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); + } + + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + MaxElem), typename MyBoostMap::allocator_type()); + ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); + if(!CheckEqualContainers(*pboostmap, *pstdmap)) return 1; + + ::boost::movelib::unique_ptr const pboostmultimap = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(&aux_vect3[0] + MaxElem), typename MyBoostMap::allocator_type()); + ::boost::movelib::unique_ptr const pstdmultimap = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); + if(!CheckEqualContainers(*pboostmultimap, *pstdmultimap)) return 1; + } + return 0; +} + + +template +int map_test_step(MyBoostMap &, MyStdMap &, MyBoostMultiMap &, MyStdMultiMap &) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + typedef typename MyStdMap::value_type StdValueType; + typedef typename MyStdMap::key_type StdKeyType; + typedef typename MyStdMap::mapped_type StdMappedType; + StdValueType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); + } + + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmap2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmultimap2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + MyBoostMap &boostmap2 = *pboostmap2; + MyStdMap &stdmap2 = *pstdmap2; + MyBoostMultiMap &boostmultimap2 = *pboostmultimap2; + MyStdMultiMap &stdmultimap2 = *pstdmultimap2; + + if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; + if(!CheckEqualContainers(boostmultimap2, stdmultimap2)) return 1; + + + + //ordered range insertion + //This is really nasty, but we have no other simple choice + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < MaxElem; ++i){ + new(&aux_vect2[i])StdValueType(StdKeyType(i), StdMappedType(i)); + } + + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; + if(!CheckEqualContainers(boostmultimap2, stdmultimap2)) return 1; + + //some comparison operators + if(!(boostmap2 == boostmap2)) + return 1; + if(boostmap2 != boostmap2) + return 1; + if(boostmap2 < boostmap2) + return 1; + if(boostmap2 > boostmap2) + return 1; + if(!(boostmap2 <= boostmap2)) + return 1; + if(!(boostmap2 >= boostmap2)) + return 1; + + ::boost::movelib::unique_ptr const pboostmap3 = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmap3 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + ::boost::movelib::unique_ptr const pboostmultimap3 = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + ::boost::movelib::unique_ptr const pstdmultimap3 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + MaxElem); + MyBoostMap &boostmap3 = *pboostmap3; + MyStdMap &stdmap3 = *pstdmap3; + MyBoostMultiMap &boostmultimap3 = *pboostmultimap3; + MyStdMultiMap &stdmultimap3 = *pstdmultimap3; + + if(!CheckEqualContainers(boostmap3, stdmap3)){ + std::cout << "Error in construct(MyBoostMap3)" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultimap3, stdmultimap3)){ + std::cout << "Error in construct(MyBoostMultiMap3)" << std::endl; + return 1; + } + + { + IntType i0(0); + boostmap2.erase(i0); + boostmultimap2.erase(i0); + stdmap2.erase(0); + stdmultimap2.erase(0); + } + { + IntType i0(0); + IntType i1(1); + boostmap2[::boost::move(i0)] = ::boost::move(i1); + } + { + IntType i1(1); + boostmap2[IntType(0)] = ::boost::move(i1); + } + stdmap2[0] = 1; + if(!CheckEqualContainers(boostmap2, stdmap2)) return 1; + } + return 0; +} + +template +int map_test_insert(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyStdMap::value_type StdPairType; + + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < MaxElem; ++i){ + boostmap.insert(boost::move(aux_vect[i])); + stdmap.insert(StdPairType(i, i)); + boostmultimap.insert(boost::move(aux_vect3[i])); + stdmultimap.insert(StdPairType(i, i)); + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + typename MyBoostMap::iterator it = boostmap.begin(); + typename MyBoostMap::const_iterator cit = it; + (void)cit; + + boostmap.erase(boostmap.begin()); + stdmap.erase(stdmap.begin()); + boostmultimap.erase(boostmultimap.begin()); + stdmultimap.erase(stdmultimap.begin()); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + boostmap.erase(boostmap.begin()); + stdmap.erase(stdmap.begin()); + boostmultimap.erase(boostmultimap.begin()); + stdmultimap.erase(stdmultimap.begin()); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + //Swapping test + MyBoostMap tmpboostemap2; + MyStdMap tmpstdmap2; + MyBoostMultiMap tmpboostemultimap2; + MyStdMultiMap tmpstdmultimap2; + boostmap.swap(tmpboostemap2); + stdmap.swap(tmpstdmap2); + boostmultimap.swap(tmpboostemultimap2); + stdmultimap.swap(tmpstdmultimap2); + boostmap.swap(tmpboostemap2); + stdmap.swap(tmpstdmap2); + boostmultimap.swap(tmpboostemultimap2); + stdmultimap.swap(tmpstdmultimap2); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + return 0; +} + +template +int map_test_erase(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyStdMap::value_type StdPairType; + + //Insertion from other container + //Initialize values + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmultimap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + for(int i = 0; i != MaxElem; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap.insert(stdpairtype); + stdmultimap.insert(stdpairtype); + } + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0, j = static_cast(boostmap.size()); i < j; ++i){ + IntType k(i); + boostmap.erase(k); + stdmap.erase(i); + boostmultimap.erase(k); + stdmultimap.erase(i); + } + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect4[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect4[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect5[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(-1); + IntType i2(-1); + new(&aux_vect5[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + boostmultimap.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(aux_vect4 + MaxElem)); + boostmultimap.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(aux_vect5 + MaxElem)); + + for(int i = 0; i != MaxElem; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap.insert(stdpairtype); + stdmultimap.insert(stdpairtype); + stdmap.insert(stdpairtype); + stdmultimap.insert(stdpairtype); + } + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + boostmap.erase(boostmap.begin()->first); + stdmap.erase(stdmap.begin()->first); + boostmultimap.erase(boostmultimap.begin()->first); + stdmultimap.erase(stdmultimap.begin()->first); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + return 0; +} + +template +int map_test_insert2(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyStdMap::value_type StdPairType; + + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < MaxElem; ++i){ + boostmap.insert(boost::move(aux_vect[i])); + stdmap.insert(StdPairType(i, i)); + boostmultimap.insert(boost::move(aux_vect3[i])); + stdmultimap.insert(StdPairType(i, i)); + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + IntPairType intpair; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + boostmap.insert(boostmap.begin(), boost::move(intpair)); + stdmap.insert(stdmap.begin(), StdPairType(i, i)); + //PrintContainers(boostmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + boostmultimap.insert(boostmultimap.begin(), boost::move(intpair)); + stdmultimap.insert(stdmultimap.begin(), StdPairType(i, i)); + //PrintContainers(boostmultimap, stdmultimap); + if(!CheckEqualPairContainers(boostmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + boostmap.insert(boostmap.end(), boost::move(intpair)); + stdmap.insert(stdmap.end(), StdPairType(i, i)); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + boostmultimap.insert(boostmultimap.end(), boost::move(intpair)); + stdmultimap.insert(stdmultimap.end(), StdPairType(i, i)); + if(!CheckEqualPairContainers(boostmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + IntType k(i); + boostmap.insert(boostmap.lower_bound(k), boost::move(intpair)); + stdmap.insert(stdmap.lower_bound(i), StdPairType(i, i)); + //PrintContainers(boostmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + { + IntType i1(i); + boostmultimap.insert(boostmultimap.lower_bound(boost::move(i1)), boost::move(intpair)); + stdmultimap.insert(stdmultimap.lower_bound(i), StdPairType(i, i)); + } + + //PrintContainers(boostmultimap, stdmultimap); + if(!CheckEqualPairContainers(boostmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) + return 1; + { //Check equal_range + std::pair bret = + boostmultimap.equal_range(boostmultimap.begin()->first); + + std::pair sret = + stdmultimap.equal_range(stdmultimap.begin()->first); + + if( boost::container::iterator_distance(bret.first, bret.second) != + boost::container::iterator_distance(sret.first, sret.second) ){ + return 1; + } + } + { + IntType i1(i); + boostmap.insert(boostmap.upper_bound(boost::move(i1)), boost::move(intpair)); + stdmap.insert(stdmap.upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(boostmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + { + IntType i1(i); + boostmultimap.insert(boostmultimap.upper_bound(boost::move(i1)), boost::move(intpair)); + stdmultimap.insert(stdmultimap.upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(boostmultimap, stdmultimap); + if(!CheckEqualPairContainers(boostmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) + return 1; + + map_test_rebalanceable(boostmap + , dtl::bool_::value>()); + if(!CheckEqualContainers(boostmap, stdmap)){ + std::cout << "Error in boostmap.rebalance()" << std::endl; + return 1; + } + map_test_rebalanceable(boostmultimap + , dtl::bool_::value>()); + if(!CheckEqualContainers(boostmultimap, stdmultimap)){ + std::cout << "Error in boostmultimap.rebalance()" << std::endl; + return 1; + } + } + return 0; +} + + +template +int map_test_search(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + + //Compare count/contains with std containers + for(int i = 0; i < MaxElem; ++i){ + IntType k(i); + if(boostmap.count(k) != stdmap.count(i)){ + return -1; + } + + if(boostmap.contains(k) != (stdmap.find(i) != stdmap.end())){ + return -1; + } + + if(boostmultimap.count(k) != stdmultimap.count(i)){ + return -1; + } + + if(boostmultimap.contains(k) != (stdmultimap.find(i) != stdmultimap.end())){ + return -1; + } + } + + { + //Now do count exercise + boostmap.erase(boostmap.begin(), boostmap.end()); + boostmultimap.erase(boostmultimap.begin(), boostmultimap.end()); + boostmap.clear(); + boostmultimap.clear(); + + for(int j = 0; j < 3; ++j) + for(int i = 0; i < 100; ++i){ + IntPairType intpair; + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + boostmap.insert(boost::move(intpair)); + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::move(i1), boost::move(i2)); + } + boostmultimap.insert(boost::move(intpair)); + IntType k(i); + if(boostmap.count(k) != typename MyBoostMultiMap::size_type(1)) + return 1; + if(boostmultimap.count(k) != typename MyBoostMultiMap::size_type(j+1)) + return 1; + } + } + + return 0; +} + +template +int map_test_indexing(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + + { //operator[] test + boostmap.clear(); + boostmultimap.clear(); + stdmap.clear(); + stdmultimap.clear(); + + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < MaxElem; ++i){ + boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second); + stdmap[i] = i; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + return 0; +} + +template< class MyBoostMap, class StdMap, class MaybeMove> +int map_test_insert_or_assign_impl() +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyBoostMap::iterator Biterator; + typedef std::pair Bpair; + + MaybeMove maybe_move; + + { //insert_or_assign test + MyBoostMap boostmap; + StdMap stdmap; + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(MaxElem-i); + new(&aux_vect[i])IntPairType(maybe_move(i1), maybe_move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect2[i])IntPairType(maybe_move(i1), maybe_move(i2)); + } + + for(int i = 0; i < MaxElem; ++i){ + Bpair r = boostmap.insert_or_assign(maybe_move(aux_vect[i].first), maybe_move(aux_vect[i].second)); + stdmap[i] = MaxElem-i; + if(!r.second) + return 1; + const IntType key(i); + if(r.first->first != key) + return 1; + const IntType mapped(MaxElem-i); + if(r.first->second != mapped) + return 1; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + Bpair r = boostmap.insert_or_assign(maybe_move(aux_vect2[i].first), maybe_move(aux_vect2[i].second)); + stdmap[i] = i; + if(r.second) + return 1; + const IntType key(i); + if(r.first->first != key) + return 1; + const IntType mapped(i); + if(r.first->second != mapped) + return 1; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + } + { //insert_or_assign test with hint + MyBoostMap boostmap; + StdMap stdmap; + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(MaxElem-i); + new(&aux_vect[i])IntPairType(maybe_move(i1), maybe_move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect2[i])IntPairType(maybe_move(i1), maybe_move(i2)); + } + + for(int i = 0; i < MaxElem; ++i){ + Biterator r = boostmap.insert_or_assign(boostmap.end(), maybe_move(aux_vect[i].first), maybe_move(aux_vect[i].second)); + stdmap[i] = MaxElem-i; + const IntType key(i); + if(r->first != key) + return 1; + const IntType mapped(MaxElem-i); + if(r->second != mapped) + return 1; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + Biterator r = boostmap.insert_or_assign(boostmap.end(), maybe_move(aux_vect2[i].first), maybe_move(aux_vect2[i].second)); + stdmap[i] = i; + const IntType key(i); + if(r->first != key) + return 1; + const IntType mapped(i); + if(r->second != mapped) + return 1; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + } + return 0; +} + +template< class MyBoostMap, class StdMap> +int map_test_insert_or_assign(dtl::bool_ )//noncopyable +{ + return map_test_insert_or_assign_impl(); +} + +template< class MyBoostMap, class StdMap> +int map_test_insert_or_assign(dtl::bool_ )//copyable +{ + int r = map_test_insert_or_assign_impl(); + if (r) + r = map_test_insert_or_assign_impl(); + return r; +} + +template< class MyBoostMap + , class MyStdMap + , class MyBoostMultiMap + , class MyStdMultiMap> +int map_test_try_emplace(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + + { //try_emplace + boostmap.clear(); + boostmultimap.clear(); + stdmap.clear(); + stdmultimap.clear(); + + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(MaxElem-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + typedef typename MyBoostMap::iterator iterator; + for(int i = 0; i < MaxElem; ++i){ + iterator it; + if(i&1){ + std::pair ret = + boostmap.try_emplace(boost::move(aux_vect[i].first), boost::move(aux_vect[i].second)); + if(!ret.second) + return 1; + it = ret.first; + } + else{ + it = boostmap.try_emplace + (boostmap.upper_bound(aux_vect[i].first), boost::move(aux_vect[i].first), boost::move(aux_vect[i].second)); + } + if(boostmap.end() == it || it->first != aux_vect2[i].first || it->second != aux_vect2[i].first){ + return 1; + } + stdmap[i] = i; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + iterator it; + iterator itex = boostmap.find(aux_vect2[i].first); + if(itex == boostmap.end()) + return 1; + if(i&1){ + std::pair ret = + boostmap.try_emplace(boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second)); + if(ret.second) + return 1; + it = ret.first; + } + else{ + it = boostmap.try_emplace + (boostmap.upper_bound(aux_vect2[i].first), boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second)); + } + const IntType test_int(i); + if(boostmap.end() == it || it != itex || it->second != test_int){ + return 1; + } + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + return 0; +} + + +template< class MyBoostMap + , class MyStdMap + , class MyBoostMultiMap + , class MyStdMultiMap> +int map_test_merge(MyBoostMap &boostmap, MyStdMap &stdmap, MyBoostMultiMap &boostmultimap, MyStdMultiMap &stdmultimap) +{ + typedef typename MyBoostMap::key_type IntType; + typedef dtl::pair IntPairType; + typedef typename MyStdMap::value_type StdPairType; + + { //merge + ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique(); + + MyBoostMap &boostmap2 = *pboostmap2; + MyBoostMultiMap &boostmultimap2 = *pboostmultimap2; + + boostmap.clear(); + boostmap2.clear(); + boostmultimap.clear(); + boostmultimap2.clear(); + stdmap.clear(); + stdmultimap.clear(); + + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem/2+i); + IntType i2(MaxElem-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem*2/2+i); + IntType i2(MaxElem*2+i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmap2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostmultimap2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmap.insert(StdPairType(i, i)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmap.insert(StdPairType(MaxElem/2+i, MaxElem-i)); + } + + boostmap.merge(boost::move(boostmap2)); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdmap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i)); + } + + boostmap.merge(boost::move(boostmultimap2)); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + + boostmap.clear(); + boostmap2.clear(); + boostmultimap.clear(); + boostmultimap2.clear(); + stdmap.clear(); + stdmultimap.clear(); + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem/2+i); + IntType i2(MaxElem-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem*2/2+i); + IntType i2(MaxElem*2+i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + boostmultimap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmultimap2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostmap2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultimap.insert(StdPairType(i, i)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultimap.insert(StdPairType(MaxElem/2+i, MaxElem-i)); + } + boostmultimap.merge(boostmultimap2); + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdmultimap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i)); + } + + boostmultimap.merge(boostmap2); + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + return 0; +} + + +template +int map_test() +{ + typedef typename MyBoostMap::key_type IntType; + + if(map_test_range()) + return 1; + + ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultimap = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdmultimap = ::boost::movelib::make_unique(); + MyBoostMap &boostmap = *pboostmap; + MyStdMap &stdmap = *pstdmap; + MyBoostMultiMap &boostmultimap = *pboostmultimap; + MyStdMultiMap &stdmultimap = *pstdmultimap; + typedef dtl::bool_::value> copyable_t; + + if (map_test_step(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_insert(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_erase(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_insert2(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_search(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_indexing(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_try_emplace(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_merge(boostmap, stdmap, boostmultimap, stdmultimap)) + return 1; + + if (map_test_insert_or_assign(copyable_t())) + return 1; + + if(map_test_copyable(copyable_t())) + return 1; + return 0; +} + +template +bool test_map_support_for_initialization_list_for() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + const std::initializer_list> il + = { std::make_pair(1, 2), std::make_pair(3, 4) }; + + const MapType expected_map(il.begin(), il.end()); + { + const MapType sil = il; + if (sil != expected_map) + return false; + + MapType sila(il, typename MapType::allocator_type()); + if (sila != expected_map) + return false; + + MapType silca(il, typename MapType::key_compare(), typename MapType::allocator_type()); + if (silca != expected_map) + return false; + + const MapType sil_ordered(ordered_unique_range, il); + if (sil_ordered != expected_map) + return false; + + MapType sil_assign = { std::make_pair(99, 100) }; + sil_assign = il; + if (sil_assign != expected_map) + return false; + } + { + MapType sil; + sil.insert(il); + if (sil != expected_map) + return false; + } + return true; +#endif + return true; +} + +template +bool instantiate_constructors() +{ + { + typedef typename MapType::value_type value_type; + typename MapType::key_compare comp; + typename MapType::allocator_type a; + value_type value; + { + MapType s0; + MapType s1(comp); + MapType s2(a); + MapType s3(comp, a); + } + { + MapType s0(&value, &value); + MapType s1(&value, &value ,comp); + MapType s2(&value, &value ,a); + MapType s3(&value, &value ,comp, a); + } + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + { + std::initializer_list il; + MapType s0(il); + MapType s1(il, comp); + MapType s2(il, a); + MapType s3(il, comp, a); + } + { + std::initializer_list il; + MapType s0(ordered_unique_range, il); + MapType s1(ordered_unique_range, il, comp); + MapType s3(ordered_unique_range, il, comp, a); + } + #endif + { + MapType s0(ordered_unique_range, &value, &value); + MapType s1(ordered_unique_range, &value, &value ,comp); + MapType s2(ordered_unique_range, &value, &value ,comp, a); + } + } + + { + typedef typename MultimapType::value_type value_type; + typename MultimapType::key_compare comp; + typename MultimapType::allocator_type a; + value_type value; + { + MultimapType s0; + MultimapType s1(comp); + MultimapType s2(a); + MultimapType s3(comp, a); + } + { + MultimapType s0(&value, &value); + MultimapType s1(&value, &value ,comp); + MultimapType s2(&value, &value ,a); + MultimapType s3(&value, &value ,comp, a); + } + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + { + std::initializer_list il; + MultimapType s0(il); + MultimapType s1(il, comp); + MultimapType s2(il, a); + MultimapType s3(il, comp, a); + } + { + std::initializer_list il; + MultimapType s0(ordered_range, il); + MultimapType s1(ordered_range, il, comp); + MultimapType s3(ordered_range, il, comp, a); + } + #endif + { + MultimapType s0(ordered_range, &value, &value); + MultimapType s1(ordered_range, &value, &value ,comp); + MultimapType s2(ordered_range, &value, &value ,comp, a); + } + } + return true; +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_CONTAINER_TEST_MAP_TEST_HEADER diff --git a/src/boost/libs/container/test/memory_resource_logger.hpp b/src/boost/libs/container/test/memory_resource_logger.hpp new file mode 100644 index 00000000..e8bc405b --- /dev/null +++ b/src/boost/libs/container/test/memory_resource_logger.hpp @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_MEMORY_RESOURCE_TESTER_HPP +#define BOOST_CONTAINER_TEST_MEMORY_RESOURCE_TESTER_HPP + +#include +#include +#include + +class memory_resource_logger + : public boost::container::pmr::memory_resource +{ + public: + struct allocation_info + { + char *address; + std::size_t bytes; + std::size_t alignment; + }; + + boost::container::vector m_info; + unsigned m_mismatches; + + explicit memory_resource_logger() + : m_info() + , m_mismatches() + {} + + virtual ~memory_resource_logger() + { this->reset(); } + + virtual void* do_allocate(std::size_t bytes, std::size_t alignment) + { + char *addr =(char*)std::malloc(bytes); + if(!addr){ + throw std::bad_alloc(); + } + allocation_info info; + info.address = addr; + info.bytes = bytes; + info.alignment = alignment; + m_info.push_back(info); + return addr; + } + + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + { + std::size_t i = 0, max = m_info.size(); + while(i != max && m_info[i].address != p){ + ++i; + } + if(i == max){ + ++m_mismatches; + } + else{ + const allocation_info &info = m_info[i]; + m_mismatches += info.bytes != bytes || info.alignment != alignment; + std::free(p); + m_info.erase(m_info.nth(i)); + } + } + + virtual bool do_is_equal(const boost::container::pmr::memory_resource& other) const BOOST_NOEXCEPT + { + return static_cast(this) == &other; + } + + void reset() + { + while(!m_info.empty()){ + std::free(m_info.back().address); + m_info.pop_back(); + } + m_mismatches = 0u; + } +}; + +#endif //#ifndef BOOST_CONTAINER_TEST_MEMORY_RESOURCE_TESTER_HPP diff --git a/src/boost/libs/container/test/memory_resource_test.cpp b/src/boost/libs/container/test/memory_resource_test.cpp new file mode 100644 index 00000000..4c4cb511 --- /dev/null +++ b/src/boost/libs/container/test/memory_resource_test.cpp @@ -0,0 +1,135 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include "derived_from_memory_resource.hpp" + +#include + +using namespace boost::container; +using namespace boost::container::pmr; + +void test_allocate() +{ + derived_from_memory_resource d; + memory_resource &mr = d; + + d.reset(); + BOOST_TEST(d.do_allocate_called == false); + BOOST_TEST(d.do_allocate_bytes == 0); + BOOST_TEST(d.do_allocate_alignment == 0); + + mr.allocate(2, 4); + BOOST_TEST(d.do_allocate_called == true); + BOOST_TEST(d.do_allocate_bytes == 2); + BOOST_TEST(d.do_allocate_alignment == 4); +} + +void test_deallocate() +{ + derived_from_memory_resource d; + memory_resource &mr = d; + + d.reset(); + BOOST_TEST(d.do_deallocate_called == false); + BOOST_TEST(d.do_deallocate_p == 0); + BOOST_TEST(d.do_allocate_bytes == 0); + BOOST_TEST(d.do_allocate_alignment == 0); + + mr.deallocate(&d, 2, 4); + BOOST_TEST(d.do_deallocate_called == true); + BOOST_TEST(d.do_deallocate_p == &d); + BOOST_TEST(d.do_deallocate_bytes == 2); + BOOST_TEST(d.do_deallocate_alignment == 4); +} + +void test_destructor() +{ + { + derived_from_memory_resource d; + d.reset(); + BOOST_TEST(derived_from_memory_resource::destructor_called == false); + } + BOOST_TEST(derived_from_memory_resource::destructor_called == true); +} + +void test_is_equal() +{ + derived_from_memory_resource d; + memory_resource &mr = d; + + d.reset(); + BOOST_TEST(d.do_is_equal_called == false); + BOOST_TEST(d.do_is_equal_other == 0); + + mr.is_equal(d); + BOOST_TEST(d.do_is_equal_called == true); + BOOST_TEST(d.do_is_equal_other == &d); +} + +void test_equality_operator() +{ + derived_from_memory_resource d; + memory_resource &mr = d; + + d.reset(); + BOOST_TEST(d.do_is_equal_called == false); + BOOST_TEST(d.do_is_equal_other == 0); + + //equal addresses are shorcircuited + BOOST_TEST((mr == mr) == true); + BOOST_TEST(d.do_is_equal_called == false); + BOOST_TEST(d.do_is_equal_other == 0); + + //unequal addresses are dispatched to is_equal which in turn calls do_is_equal + derived_from_memory_resource d2(1); + d.reset(); + d2.reset(); + memory_resource &mr2 = d2; + BOOST_TEST((mr == mr2) == false); + BOOST_TEST(d.do_is_equal_called == true); + BOOST_TEST(d.do_is_equal_other == &d2); +} + +void test_inequality_operator() +{ + derived_from_memory_resource d; + memory_resource &mr = d; + + d.reset(); + BOOST_TEST(d.do_is_equal_called == false); + BOOST_TEST(d.do_is_equal_other == 0); + + //equal addresses are shorcircuited + BOOST_TEST((mr != mr) == false); + BOOST_TEST(d.do_is_equal_called == false); + BOOST_TEST(d.do_is_equal_other == 0); + + //unequal addresses are dispatched to is_equal which in turn calls do_is_equal + derived_from_memory_resource d2(1); + d.reset(); + d2.reset(); + memory_resource &mr2 = d2; + BOOST_TEST((mr != mr2) == true); + BOOST_TEST(d.do_is_equal_called == true); + BOOST_TEST(d.do_is_equal_other == &d2); +} + +int main() +{ + test_destructor(); + test_allocate(); + test_deallocate(); + test_is_equal(); + test_equality_operator(); + test_inequality_operator(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/monotonic_buffer_resource_test.cpp b/src/boost/libs/container/test/monotonic_buffer_resource_test.cpp new file mode 100644 index 00000000..4923e246 --- /dev/null +++ b/src/boost/libs/container/test/monotonic_buffer_resource_test.cpp @@ -0,0 +1,483 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "derived_from_memory_resource.hpp" +#include "memory_resource_logger.hpp" + +using namespace boost::container::pmr; + +static const std::size_t AllocCount = 32u; + +namespace test_block_chain{ + +//explicit block_slist(memory_resource &upstream_rsrc) +void test_constructor() +{ + memory_resource_logger mrl; + block_slist bc(mrl); + //Resource stored + BOOST_TEST(&bc.upstream_resource() == &mrl); + //No allocation performed + BOOST_TEST(mrl.m_info.size() == 0u); +} + +//void *allocate(std::size_t size) +void test_allocate() +{ + memory_resource_logger mrl; + block_slist bc(mrl); + + for(unsigned i = 0; i != unsigned(AllocCount); ++i){ + //Allocate and trace data + const std::size_t alloc = i+1; + char *const addr = (char*)bc.allocate(alloc); + //Should have allocated a new entry + BOOST_TEST(mrl.m_info.size() == (i+1)); + //Requested size must be bigger to include metadata + BOOST_TEST(mrl.m_info[i].bytes > alloc); + BOOST_TEST(mrl.m_info[i].alignment == memory_resource::max_align); + //Returned address should be between the allocated buffer + BOOST_TEST(mrl.m_info[i].address < addr); + BOOST_TEST(addr < (mrl.m_info[i].address + mrl.m_info[i].bytes)); + //Allocate size should include all requested size + BOOST_TEST((addr + alloc) <= (mrl.m_info[i].address + mrl.m_info[i].bytes)); + //Allocation must be max-aligned + BOOST_TEST((std::size_t(addr) % memory_resource::max_align) == 0); + } +} + +//void release() BOOST_NOEXCEPT +void test_release() +{ + memory_resource_logger mrl; + block_slist bc(mrl); + + //Allocate and trace data + char *bufs[AllocCount]; + for(unsigned i = 0; i != unsigned(AllocCount); ++i){ + bufs[i] = (char*)bc.allocate(i+1); + } + (void)bufs; + //Should have allocated a new entry + BOOST_TEST(mrl.m_info.size() == AllocCount); + + //Now release and check all allocations match deallocations + bc.release(); + BOOST_TEST(mrl.m_mismatches == 0); + BOOST_TEST(mrl.m_info.size() == 0u); +} + +//memory_resource* upstream_resource() +void test_memory_resource() +{ + derived_from_memory_resource d; + block_slist bc(d); + //Resource stored + BOOST_TEST(&bc.upstream_resource() == &d); +} + +//~block_slist() { this->release(); } +void test_destructor() +{ + memory_resource_logger mrl; + { + block_slist bc(mrl); + + //Allocate and trace data + char *bufs[AllocCount]; + for(unsigned i = 0; i != unsigned(AllocCount); ++i){ + bufs[i] = (char*)bc.allocate(i+1); + } + (void)bufs; + //Should have allocated a new entry + BOOST_TEST(mrl.m_info.size() == AllocCount); + + //Destructor should release all memory + } + BOOST_TEST(mrl.m_mismatches == 0); + BOOST_TEST(mrl.m_info.size() == 0u); +} + +} //namespace test_block_chain { + +void test_resource_constructor() +{ + //First constructor, null resource + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + monotonic_buffer_resource m; + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(0); + } + //First constructor, non-null resource + { + derived_from_memory_resource dmr; + dmr.reset(); + monotonic_buffer_resource m(&dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.next_buffer_size() == monotonic_buffer_resource::initial_next_buffer_size); + BOOST_TEST(m.current_buffer() == 0); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } +} + +void test_initial_size_constructor() +{ + //Second constructor, null resource + const std::size_t initial_size = monotonic_buffer_resource::initial_next_buffer_size*2; + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + monotonic_buffer_resource m(initial_size); + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.next_buffer_size() >= initial_size); + BOOST_TEST(m.current_buffer() == 0); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(0); + } + //Second constructor, non-null resource + { + derived_from_memory_resource dmr; + dmr.reset(); + monotonic_buffer_resource m(initial_size, &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.next_buffer_size() >= initial_size); + BOOST_TEST(m.current_buffer() == 0); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } +} + +void test_buffer_constructor() +{ + const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size*2; + unsigned char buf[BufSz]; + //Third constructor, null resource + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + monotonic_buffer_resource m(buf, BufSz); + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.next_buffer_size() >= BufSz*2); + BOOST_TEST(m.current_buffer() == buf); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(0); + } + //Third constructor, non-null resource + { + derived_from_memory_resource dmr; + dmr.reset(); + monotonic_buffer_resource m(buf, sizeof(buf), &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.next_buffer_size() >= sizeof(buf)*2); + BOOST_TEST(m.current_buffer() == buf); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } + //Check for empty buffers + { + monotonic_buffer_resource m(buf, 0); + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.next_buffer_size() > 1); + BOOST_TEST(m.current_buffer() == buf); + } +} + +struct derived_from_monotonic_buffer_resource + : public monotonic_buffer_resource +{ + explicit derived_from_monotonic_buffer_resource(memory_resource *p) + : monotonic_buffer_resource(p) + {} + + explicit derived_from_monotonic_buffer_resource(std::size_t initial_size, memory_resource* upstream) + : monotonic_buffer_resource(initial_size, upstream) + {} + + explicit derived_from_monotonic_buffer_resource(void* buffer, std::size_t buffer_size, memory_resource* upstream) + : monotonic_buffer_resource(buffer, buffer_size, upstream) + {} + + using monotonic_buffer_resource::do_allocate; + using monotonic_buffer_resource::do_deallocate; + using monotonic_buffer_resource::do_is_equal; +}; + +void test_upstream_resource() +{ + //Allocate buffer first to avoid stack-use-after-scope in monotonic_buffer_resource's destructor + const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size; + boost::move_detail::aligned_storage::type buf; + //Test stores the resource and uses it to allocate memory + derived_from_memory_resource dmr; + dmr.reset(); + derived_from_monotonic_buffer_resource dmbr(&dmr); + //Resource must be stored and initial values given (no current buffer) + BOOST_TEST(dmbr.upstream_resource() == &dmr); + BOOST_TEST(dmbr.next_buffer_size() == monotonic_buffer_resource::initial_next_buffer_size); + BOOST_TEST(dmbr.current_buffer() == 0); + //Test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + //Now stub buffer storage it as the return buffer + //for "derived_from_memory_resource": + dmr.do_allocate_return = &buf; + //Test that allocation uses the upstream_resource() + void *addr = dmbr.do_allocate(1u, 1u); + //Test returns stubbed memory with the internal initial size plus metadata size + BOOST_TEST(addr > (char*)&buf); + BOOST_TEST(addr < (char*)(&buf+1)); + BOOST_TEST(dmr.do_allocate_called == true); + BOOST_TEST(dmr.do_allocate_bytes > BufSz); + //Alignment for the resource must be max_align + BOOST_TEST(dmr.do_allocate_alignment == memory_resource::max_align); +} + +void test_do_allocate() +{ + memory_resource_logger mrl; + { + std::size_t remaining_storage = 0u; + derived_from_monotonic_buffer_resource dmbr(&mrl); + //First test, no buffer + { + dmbr.do_allocate(1, 1); + //It should allocate initial size + BOOST_TEST(mrl.m_info.size() == 1u); + //... which requests the initial size plus the header size to the allcoator + BOOST_TEST(mrl.m_info[0].bytes == monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size); + std::size_t remaining = dmbr.remaining_storage(1u); + //Remaining storage should be one less than initial, as we requested 1 byte with minimal alignment + BOOST_TEST(remaining == monotonic_buffer_resource::initial_next_buffer_size-1u); + remaining_storage = remaining; + } + //Now ask for more internal storage with misaligned current buffer + { + //Test wasted space + std::size_t wasted_due_to_alignment; + dmbr.remaining_storage(4u, wasted_due_to_alignment); + BOOST_TEST(wasted_due_to_alignment == 3u); + dmbr.do_allocate(4, 4); + //It should not have allocated + BOOST_TEST(mrl.m_info.size() == 1u); + std::size_t remaining = dmbr.remaining_storage(1u); + //We wasted some bytes due to alignment plus 4 bytes of real storage + BOOST_TEST(remaining == remaining_storage - 4 - wasted_due_to_alignment); + remaining_storage = remaining; + } + //Now request the same alignment to test no storage is wasted + { + std::size_t wasted_due_to_alignment; + std::size_t remaining = dmbr.remaining_storage(1u, wasted_due_to_alignment); + BOOST_TEST(mrl.m_info.size() == 1u); + dmbr.do_allocate(4, 4); + //It should not have allocated + BOOST_TEST(mrl.m_info.size() == 1u); + remaining = dmbr.remaining_storage(1u); + //We wasted no bytes due to alignment plus 4 bytes of real storage + BOOST_TEST(remaining == remaining_storage - 4u); + remaining_storage = remaining; + } + //Now exhaust the remaining storage with 2 byte alignment (the last allocation + //was 4 bytes with 4 byte alignment) so it should be already 2-byte aligned. + { + dmbr.do_allocate(remaining_storage, 2); + std::size_t wasted_due_to_alignment; + std::size_t remaining = dmbr.remaining_storage(1u, wasted_due_to_alignment); + BOOST_TEST(wasted_due_to_alignment == 0u); + BOOST_TEST(remaining == 0u); + //It should not have allocated + BOOST_TEST(mrl.m_info.size() == 1u); + remaining_storage = 0u; + } + //The next allocation should trigger the upstream resource, even with a 1 byte + //allocation. + { + dmbr.do_allocate(1u, 1u); + BOOST_TEST(mrl.m_info.size() == 2u); + //The next allocation should be geometrically bigger. + BOOST_TEST(mrl.m_info[1].bytes == 2*monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size); + std::size_t wasted_due_to_alignment; + //For a 2 byte alignment one byte will be wasted from the previous 1 byte allocation + std::size_t remaining = dmbr.remaining_storage(2u, wasted_due_to_alignment); + BOOST_TEST(wasted_due_to_alignment == 1u); + BOOST_TEST(remaining == (mrl.m_info[1].bytes - 1u - wasted_due_to_alignment - block_slist::header_size)); + //It should not have allocated + remaining_storage = dmbr.remaining_storage(1u); + } + //Now try a bigger than next allocation and see if next_buffer_size is doubled. + { + std::size_t next_alloc = 5*monotonic_buffer_resource::initial_next_buffer_size; + dmbr.do_allocate(next_alloc, 1u); + BOOST_TEST(mrl.m_info.size() == 3u); + //The next allocation should be geometrically bigger. + BOOST_TEST(mrl.m_info[2].bytes == 8*monotonic_buffer_resource::initial_next_buffer_size+block_slist::header_size); + remaining_storage = dmbr.remaining_storage(1u); + } + } + //derived_from_monotonic_buffer_resource dmbr(&mrl) is destroyed + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); + + //Now use a local buffer + { + boost::move_detail::aligned_storage + ::type buf; + //Supply an external buffer + derived_from_monotonic_buffer_resource dmbr(&buf, sizeof(buf), &mrl); + BOOST_TEST(dmbr.remaining_storage(1u) == sizeof(buf)); + //Allocate all remaining storage + dmbr.do_allocate(dmbr.remaining_storage(1u), 1u); + //No new allocation should have occurred + BOOST_TEST(mrl.m_info.size() == 0u); + BOOST_TEST(dmbr.remaining_storage(1u) == 0u); + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); +} + +void test_do_deallocate() +{ + memory_resource_logger mrl; + const std::size_t initial_size = 1u; + { + derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl); + //First test, no buffer + const unsigned iterations = 8; + char *bufs[iterations]; + std::size_t sizes[iterations]; + //Test each iteration allocates memory + for(unsigned i = 0; i != iterations; ++i) + { + sizes[i] = dmbr.remaining_storage()+1; + bufs[i] = (char*)dmbr.do_allocate(sizes[i], 1); + BOOST_TEST(mrl.m_info.size() == (i+1)); + } + std::size_t remaining = dmbr.remaining_storage(); + //Test do_deallocate does not release any storage + for(unsigned i = 0; i != iterations; ++i) + { + dmbr.do_deallocate(bufs[i], sizes[i], 1u); + BOOST_TEST(mrl.m_info.size() == iterations); + BOOST_TEST(remaining == dmbr.remaining_storage()); + BOOST_TEST(mrl.m_mismatches == 0u); + } + } +} + +void test_do_is_equal() +{ + //! Returns: + //! `this == dynamic_cast(&other)`. + memory_resource_logger mrl; + derived_from_monotonic_buffer_resource dmbr(&mrl); + derived_from_monotonic_buffer_resource dmbr2(&mrl); + BOOST_TEST(true == dmbr.do_is_equal(dmbr)); + BOOST_TEST(false == dmbr.do_is_equal(dmbr2)); + //A different type should be always different + derived_from_memory_resource dmr; + BOOST_TEST(false == dmbr.do_is_equal(dmr)); +} + +void test_release() +{ + { + memory_resource_logger mrl; + const std::size_t initial_size = 1u; + derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl); + //First test, no buffer + const unsigned iterations = 8; + //Test each iteration allocates memory + for(unsigned i = 0; i != iterations; ++i) + { + dmbr.do_allocate(dmbr.remaining_storage()+1, 1); + BOOST_TEST(mrl.m_info.size() == (i+1)); + } + //Release and check memory was released + dmbr.release(); + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); + } + //Now use a local buffer + { + boost::move_detail::aligned_storage + ::type buf; + //Supply an external buffer + monotonic_buffer_resource monr(&buf, sizeof(buf)); + memory_resource &mr = monr; + BOOST_TEST(monr.remaining_storage(1u) == sizeof(buf)); + //Allocate all remaining storage + mr.allocate(monr.remaining_storage(1u), 1u); + BOOST_TEST(monr.current_buffer() == ((char*)&buf + sizeof(buf))); + //No new allocation should have occurred + BOOST_TEST(monr.remaining_storage(1u) == 0u); + //Release and check memory was released and the original buffer is back + monr.release(); + BOOST_TEST(monr.remaining_storage(1u) == sizeof(buf)); + BOOST_TEST(monr.current_buffer() == &buf); + } +} + +void test_destructor() +{ + memory_resource_logger mrl; + const std::size_t initial_size = 1u; + { + derived_from_monotonic_buffer_resource dmbr(initial_size, &mrl); + //First test, no buffer + const unsigned iterations = 8; + //Test each iteration allocates memory + for(unsigned i = 0; i != iterations; ++i) + { + dmbr.do_allocate(dmbr.remaining_storage()+1, 1); + BOOST_TEST(mrl.m_info.size() == (i+1)); + } + } //dmbr is destroyed, memory should be released + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); +} + +int main() +{ + test_block_chain::test_constructor(); + test_block_chain::test_allocate(); + test_block_chain::test_release(); + test_block_chain::test_memory_resource(); + test_block_chain::test_destructor(); + + test_resource_constructor(); + test_initial_size_constructor(); + test_buffer_constructor(); + + test_upstream_resource(); + test_do_allocate(); + test_do_deallocate(); + test_do_is_equal(); + test_release(); + test_destructor(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/movable_int.hpp b/src/boost/libs/container/test/movable_int.hpp new file mode 100644 index 00000000..c38146ec --- /dev/null +++ b/src/boost/libs/container/test/movable_int.hpp @@ -0,0 +1,437 @@ +/////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_MOVABLE_INT_HEADER +#define BOOST_CONTAINER_TEST_MOVABLE_INT_HEADER + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace test { + +template +struct is_copyable; + +template<> +struct is_copyable +{ + static const bool value = true; +}; + + +class movable_int +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_int) + + public: + + static unsigned int count; + + movable_int() + : m_int(0) + { ++count; } + + explicit movable_int(int a) + : m_int(a) + { + //Disallow INT_MIN + BOOST_ASSERT(this->m_int != INT_MIN); + ++count; + } + + movable_int(BOOST_RV_REF(movable_int) mmi) + : m_int(mmi.m_int) + { mmi.m_int = 0; ++count; } + + movable_int & operator= (BOOST_RV_REF(movable_int) mmi) + { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } + + movable_int & operator= (int i) + { this->m_int = i; BOOST_ASSERT(this->m_int != INT_MIN); return *this; } + + ~movable_int() + { + //Double destructor called + BOOST_ASSERT(this->m_int != INT_MIN); + this->m_int = INT_MIN; + --count; + } + + friend bool operator ==(const movable_int &l, const movable_int &r) + { return l.m_int == r.m_int; } + + friend bool operator !=(const movable_int &l, const movable_int &r) + { return l.m_int != r.m_int; } + + friend bool operator <(const movable_int &l, const movable_int &r) + { return l.m_int < r.m_int; } + + friend bool operator <=(const movable_int &l, const movable_int &r) + { return l.m_int <= r.m_int; } + + friend bool operator >=(const movable_int &l, const movable_int &r) + { return l.m_int >= r.m_int; } + + friend bool operator >(const movable_int &l, const movable_int &r) + { return l.m_int > r.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const movable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_int &r) + { return l == r.get_int(); } + + friend bool operator<(const movable_int &l, int r) + { return l.get_int() < r; } + + friend bool operator<(int l, const movable_int &r) + { return l < r.get_int(); } + + friend std::size_t hash_value(const movable_int &v) + { return (std::size_t)v.get_int(); } + + private: + int m_int; +}; + +unsigned int movable_int::count = 0; + +inline movable_int produce_movable_int() +{ return movable_int(); } + +template +std::basic_ostream & operator<< + (std::basic_ostream & os, movable_int const & p) + +{ + os << p.get_int(); + return os; +} + +template<> +struct is_copyable +{ + static const bool value = false; +}; + +class movable_and_copyable_int +{ + BOOST_COPYABLE_AND_MOVABLE(movable_and_copyable_int) + + public: + + static unsigned int count; + + movable_and_copyable_int() + : m_int(0) + { ++count; } + + explicit movable_and_copyable_int(int a) + : m_int(a) + { + //Disallow INT_MIN + BOOST_ASSERT(this->m_int != INT_MIN); + ++count; + } + + movable_and_copyable_int(const movable_and_copyable_int& mmi) + : m_int(mmi.m_int) + { ++count; } + + movable_and_copyable_int(BOOST_RV_REF(movable_and_copyable_int) mmi) + : m_int(mmi.m_int) + { mmi.m_int = 0; ++count; } + + ~movable_and_copyable_int() + { + //Double destructor called + BOOST_ASSERT(this->m_int != INT_MIN); + this->m_int = INT_MIN; + --count; + } + + movable_and_copyable_int &operator= (BOOST_COPY_ASSIGN_REF(movable_and_copyable_int) mi) + { this->m_int = mi.m_int; return *this; } + + movable_and_copyable_int & operator= (BOOST_RV_REF(movable_and_copyable_int) mmi) + { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } + + movable_and_copyable_int & operator= (int i) + { this->m_int = i; BOOST_ASSERT(this->m_int != INT_MIN); return *this; } + + friend bool operator ==(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int == r.m_int; } + + friend bool operator !=(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int != r.m_int; } + + friend bool operator <(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int < r.m_int; } + + friend bool operator <=(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int <= r.m_int; } + + friend bool operator >=(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int >= r.m_int; } + + friend bool operator >(const movable_and_copyable_int &l, const movable_and_copyable_int &r) + { return l.m_int > r.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const movable_and_copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const movable_and_copyable_int &r) + { return l == r.get_int(); } + + friend bool operator<(const movable_and_copyable_int &l, int r) + { return l.get_int() < r; } + + friend bool operator<(int l, const movable_and_copyable_int &r) + { return l < r.get_int(); } + + friend std::size_t hash_value(const movable_and_copyable_int &v) + { return (std::size_t)v.get_int(); } + + private: + int m_int; +}; + +unsigned int movable_and_copyable_int::count = 0; + +inline movable_and_copyable_int produce_movable_and_copyable_int() +{ return movable_and_copyable_int(); } + +template +std::basic_ostream & operator<< + (std::basic_ostream & os, movable_and_copyable_int const & p) + +{ + os << p.get_int(); + return os; +} + +template<> +struct is_copyable +{ + static const bool value = true; +}; + +class copyable_int +{ + public: + + static unsigned int count; + + copyable_int() + : m_int(0) + { ++count; } + + explicit copyable_int(int a) + : m_int(a) + { + //Disallow INT_MIN + BOOST_ASSERT(this->m_int != INT_MIN); + ++count; + } + + copyable_int(const copyable_int& mmi) + : m_int(mmi.m_int) + { ++count; } + + copyable_int & operator= (int i) + { this->m_int = i; BOOST_ASSERT(this->m_int != INT_MIN); return *this; } + + copyable_int & operator= (const copyable_int &ci) + { this->m_int = ci.m_int; BOOST_ASSERT(this->m_int != INT_MIN); return *this; } + + ~copyable_int() + { + //Double destructor called + BOOST_ASSERT(this->m_int != INT_MIN); + this->m_int = INT_MIN; + --count; + } + + friend bool operator ==(const copyable_int &l, const copyable_int &r) + { return l.m_int == r.m_int; } + + friend bool operator !=(const copyable_int &l, const copyable_int &r) + { return l.m_int != r.m_int; } + + friend bool operator <(const copyable_int &l, const copyable_int &r) + { return l.m_int < r.m_int; } + + friend bool operator <=(const copyable_int &l, const copyable_int &r) + { return l.m_int <= r.m_int; } + + friend bool operator >=(const copyable_int &l, const copyable_int &r) + { return l.m_int >= r.m_int; } + + friend bool operator >(const copyable_int &l, const copyable_int &r) + { return l.m_int > r.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const copyable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const copyable_int &r) + { return l == r.get_int(); } + + friend bool operator<(const copyable_int &l, int r) + { return l.get_int() < r; } + + friend bool operator<(int l, const copyable_int &r) + { return l < r.get_int(); } + + friend std::size_t hash_value(const copyable_int &v) + { return (std::size_t)v.get_int(); } + + private: + int m_int; +}; + +unsigned int copyable_int::count = 0; + +inline copyable_int produce_copyable_int() +{ return copyable_int(); } + +template +std::basic_ostream & operator<< + (std::basic_ostream & os, copyable_int const & p) + +{ + os << p.get_int(); + return os; +} + +template<> +struct is_copyable +{ + static const bool value = true; +}; + +class non_copymovable_int +{ + non_copymovable_int(const non_copymovable_int& mmi); + non_copymovable_int & operator= (const non_copymovable_int &mi); + + public: + + static unsigned int count; + + non_copymovable_int() + : m_int(0) + { ++count; } + + explicit non_copymovable_int(int a) + : m_int(a) + { ++count; } + + ~non_copymovable_int() + { m_int = 0; --count; } + + bool operator ==(const non_copymovable_int &mi) const + { return this->m_int == mi.m_int; } + + bool operator !=(const non_copymovable_int &mi) const + { return this->m_int != mi.m_int; } + + bool operator <(const non_copymovable_int &mi) const + { return this->m_int < mi.m_int; } + + bool operator <=(const non_copymovable_int &mi) const + { return this->m_int <= mi.m_int; } + + bool operator >=(const non_copymovable_int &mi) const + { return this->m_int >= mi.m_int; } + + bool operator >(const non_copymovable_int &mi) const + { return this->m_int > mi.m_int; } + + int get_int() const + { return m_int; } + + friend bool operator==(const non_copymovable_int &l, int r) + { return l.get_int() == r; } + + friend bool operator==(int l, const non_copymovable_int &r) + { return l == r.get_int(); } + + friend bool operator<(const non_copymovable_int &l, int r) + { return l.get_int() < r; } + + friend bool operator<(int l, const non_copymovable_int &r) + { return l < r.get_int(); } + + friend std::size_t hash_value(const non_copymovable_int &v) + { return (std::size_t)v.get_int(); } + + private: + int m_int; +}; + +unsigned int non_copymovable_int::count = 0; + +template +struct life_count +{ + static unsigned check(unsigned) { return true; } +}; + +template<> +struct life_count< movable_int > +{ + static unsigned check(unsigned c) + { return c == movable_int::count; } +}; + +template<> +struct life_count< copyable_int > +{ + static unsigned check(unsigned c) + { return c == copyable_int::count; } +}; + +template<> +struct life_count< movable_and_copyable_int > +{ + static unsigned check(unsigned c) + { return c == movable_and_copyable_int::count; } +}; + +template<> +struct life_count< non_copymovable_int > +{ + static unsigned check(unsigned c) + { return c == non_copymovable_int::count; } +}; + + +} //namespace test { +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_TEST_MOVABLE_INT_HEADER diff --git a/src/boost/libs/container/test/node_handle_test.cpp b/src/boost/libs/container/test/node_handle_test.cpp new file mode 100644 index 00000000..3c263794 --- /dev/null +++ b/src/boost/libs/container/test/node_handle_test.cpp @@ -0,0 +1,633 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2016-2016. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + +using namespace ::boost::container; + +enum EAllocState +{ + DefaultConstructed, + MoveConstructed, + MoveAssigned, + CopyConstructed, + CopyAssigned, + Swapped, + Destructed +}; + +template +class trace_allocator + : public new_allocator +{ + BOOST_COPYABLE_AND_MOVABLE(trace_allocator) + + typedef new_allocator base_t; + + public: + + struct propagate_on_container_move_assignment + { + static const bool value = true; + }; + + struct propagate_on_container_swap + { + static const bool value = true; + }; + + //!Obtains an new_allocator that allocates + //!objects of type T2 + template + struct rebind + { + typedef trace_allocator other; + }; + + explicit trace_allocator(unsigned value = 999) + : m_state(DefaultConstructed), m_value(value) + { + ++count; + } + + trace_allocator(BOOST_RV_REF(trace_allocator) other) + : base_t(boost::move(BOOST_MOVE_BASE(base_t, other))), m_state(MoveConstructed), m_value(other.m_value) + { + ++count; + } + + trace_allocator(const trace_allocator &other) + : base_t(other), m_state(CopyConstructed), m_value(other.m_value) + { + ++count; + } + + trace_allocator & operator=(BOOST_RV_REF(trace_allocator) other) + { + m_value = other.m_value; + m_state = MoveAssigned; + return *this; + } + + template + trace_allocator(const trace_allocator &other) + : m_state(CopyConstructed), m_value(other.m_value) + { + ++count; + } + + template + trace_allocator & operator=(BOOST_COPY_ASSIGN_REF(trace_allocator) other) + { + m_value = other.m_value; + m_state = CopyAssigned; + return *this; + } + + ~trace_allocator() + { + m_value = 0u-1u; + m_state = Destructed; + --count; + } + + void swap(trace_allocator &other) + { + boost::adl_move_swap(m_value, other.m_value); + m_state = other.m_state = Swapped; + } + + friend void swap(trace_allocator &left, trace_allocator &right) + { + left.swap(right); + } + + EAllocState m_state; + unsigned m_value; + + static unsigned int count; + + static void reset_count() + { count = 0; } +}; + +template +unsigned int trace_allocator::count = 0; + +template +struct node +{ + typedef T value_type; + value_type value; + + value_type &get_data() { return value; } + const value_type &get_data() const { return value; } + + node() + { + ++count; + } + + ~node() + { + --count; + } + + static unsigned int count; + + static void reset_count() + { count = 0; } +}; + +template +struct value +{ + T1 first; + T2 second; +}; + +template +unsigned int node::count = 0; + + +//Common types +typedef value test_pair; +typedef pair_key_mapped_of_value key_mapped_t; +typedef node node_t; +typedef trace_allocator< node_t > node_alloc_t; +typedef node_handle node_handle_set_t; +typedef node_handle node_handle_map_t; +typedef allocator_traits::portable_rebind_alloc::type value_allocator_type; + +void test_types() +{ + //set + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + + //map + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + BOOST_STATIC_ASSERT(( dtl::is_same::value )); + BOOST_STATIC_ASSERT(( dtl::is_same::value )); +} + +void test_default_constructor() +{ + node_alloc_t::reset_count(); + { + node_handle_set_t nh; + BOOST_TEST(node_alloc_t::count == 0); + } + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_arg_constructor() +{ + //With non-null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh(new node_t, al); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //With null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh(0, al); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + BOOST_TEST(node_t::count == 0); + } + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_move_constructor() +{ + //With non-null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_t *const from_ptr = new node_t; + node_handle_set_t nh(from_ptr, al); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + { + node_handle_set_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(!nh2.empty()); + BOOST_TEST(nh2.get() == from_ptr); + BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //With null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh; + { + node_handle_set_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(nh2.empty()); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_related_constructor() +{ + //With non-null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_t *const from_ptr = new node_t; + node_handle_map_t nh(from_ptr, al); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + { + node_handle_set_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(!nh2.empty()); + BOOST_TEST(nh2.get() == from_ptr); + BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 2); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //With null pointer + node_alloc_t::reset_count(); + node_t::reset_count(); + { + const node_alloc_t al; + BOOST_TEST(node_alloc_t::count == 1); + { + node_handle_set_t nh; + { + node_handle_map_t nh2(boost::move(nh)); + BOOST_TEST(nh.empty()); + BOOST_TEST(nh2.empty()); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); +} + +void test_move_assignment() +{ + //empty = full + { + node_alloc_t::reset_count(); + node_t::reset_count(); + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + + //empty = empty + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + } + + //full = empty + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_handle_set_t nh_to(new node_t, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + } + + //full = full + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_handle_set_t nh_to(new node_t, node_alloc_t()); + BOOST_TEST(node_t::count == 2); + BOOST_TEST(node_alloc_t::count == 2); + + nh_to = boost::move(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == MoveAssigned); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } +} + +void test_value_key_mapped() +{ + //value() + { + node_t *from_ptr = new node_t; + const node_handle_set_t nh_from(from_ptr, node_alloc_t()); + from_ptr->value.first = -99; + from_ptr->value.second = 99; + BOOST_TEST(nh_from.value().first == -99); + BOOST_TEST(nh_from.value().second == 99); + } + //key()/mapped() + { + node_t *from_ptr = new node_t; + const node_handle_map_t nh_from(from_ptr, node_alloc_t()); + from_ptr->value.first = -98; + from_ptr->value.second = 98; + BOOST_TEST(nh_from.key() == -98); + BOOST_TEST(nh_from.mapped() == 98); + } +} + +void test_get_allocator() +{ + const node_handle_set_t nh(new node_t, node_alloc_t(888)); + allocator_traits::portable_rebind_alloc::type a = nh.get_allocator(); + BOOST_TEST(a.m_value == 888); +} + +void test_bool_conversion_empty() +{ + const node_handle_set_t nh(new node_t, node_alloc_t(777)); + const node_handle_set_t nh_null; + BOOST_TEST(nh && !nh_null); + BOOST_TEST(!(!nh || nh_null)); + BOOST_TEST(!nh.empty() && nh_null.empty()); + BOOST_TEST(!(nh.empty() || !nh_null.empty())); +} + +void test_swap() +{ + //empty.swap(full) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to.swap(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + + //empty.swap(empty) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_handle_set_t nh_to; + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + nh_to.swap(nh_from); + + BOOST_TEST(nh_from.empty()); + BOOST_TEST(nh_to.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + } + + //full.swap(empty) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_handle_set_t nh_from; + BOOST_TEST(nh_from.empty()); + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + node_t *const to_ptr = new node_t; + node_handle_set_t nh_to(to_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + nh_to.swap(nh_from); + + BOOST_TEST(!nh_from.empty()); + BOOST_TEST(nh_from.node_alloc().m_state == MoveConstructed); + BOOST_TEST(nh_from.get() == to_ptr); + BOOST_TEST(nh_to.empty()); + + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + + //full.swap(full) + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const from_ptr = new node_t; + node_handle_set_t nh_from(from_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + node_t *const to_ptr = new node_t; + node_handle_set_t nh_to(to_ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 2); + BOOST_TEST(node_alloc_t::count == 2); + + nh_to.swap(nh_from); + + BOOST_TEST(!nh_from.empty()); + BOOST_TEST(nh_from.get() == to_ptr); + BOOST_TEST(nh_from.node_alloc().m_state == Swapped); + + BOOST_TEST(!nh_to.empty()); + BOOST_TEST(nh_to.get() == from_ptr); + BOOST_TEST(nh_to.node_alloc().m_state == Swapped); + + BOOST_TEST(node_t::count == 2); + BOOST_TEST(node_alloc_t::count == 2); + } +} + +void test_get_release() +{ + //get() + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const ptr = new node_t; + const node_handle_set_t nh(ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + BOOST_TEST(nh.get() == ptr); + BOOST_TEST(!nh.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + } + BOOST_TEST(node_t::count == 0); + BOOST_TEST(node_alloc_t::count == 0); + + //release() + { + node_alloc_t::reset_count(); + node_t::reset_count(); + + node_t *const ptr = new node_t; + node_handle_set_t nh(ptr, node_alloc_t()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 1); + + BOOST_TEST(nh.release() == ptr); + BOOST_TEST(nh.empty()); + BOOST_TEST(node_t::count == 1); + BOOST_TEST(node_alloc_t::count == 0); + delete ptr; + } + BOOST_TEST(node_t::count == 0); +} + +int main() +{ + test_types(); + test_default_constructor(); + test_arg_constructor(); + test_move_constructor(); + test_related_constructor(); + test_move_assignment(); + test_value_key_mapped(); + test_get_allocator(); + test_bool_conversion_empty(); + test_swap(); + test_get_release(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/null_iterators_test.cpp b/src/boost/libs/container/test/null_iterators_test.cpp new file mode 100644 index 00000000..f081dbe0 --- /dev/null +++ b/src/boost/libs/container/test/null_iterators_test.cpp @@ -0,0 +1,96 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace boost::container; + +typedef boost::container::dtl::aligned_storage::type buffer_t; + +static buffer_t buffer_0x00; +static buffer_t buffer_0xFF; + +template +const Iterator &on_0x00_buffer() +{ + BOOST_STATIC_ASSERT(sizeof(buffer_t) >= sizeof(Iterator)); + return * ::new(std::memset(&buffer_0x00, 0x00, sizeof(buffer_0x00))) Iterator(); +} + +template +const Iterator &on_0xFF_buffer() +{ + BOOST_STATIC_ASSERT(sizeof(buffer_t) >= sizeof(Iterator)); + return * ::new(std::memset(&buffer_0xFF, 0xFF, sizeof(buffer_0xFF))) Iterator(); +} + +namespace boost { +namespace container { +namespace test { + +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(reverse_iterator) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(const_reverse_iterator) + +}}} //namespace boost::container::test { + +template +void check_null_iterators() +{ + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT + (boost::container::test::, Container + ,reverse_iterator, iterator) reverse_iterator; + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT + (boost::container::test::, Container + ,const_reverse_iterator, const_iterator) const_reverse_iterator; + + BOOST_TEST(on_0xFF_buffer() == on_0x00_buffer()); + BOOST_TEST(on_0xFF_buffer() == on_0x00_buffer()); + BOOST_TEST(on_0xFF_buffer() == on_0x00_buffer()); + BOOST_TEST(on_0xFF_buffer() == on_0x00_buffer()); +} + +int main() +{ + check_null_iterators< vector >(); + check_null_iterators< deque >(); + check_null_iterators< stable_vector >(); + check_null_iterators< static_vector >(); + check_null_iterators< string >(); + check_null_iterators< list >(); + check_null_iterators< slist >(); + check_null_iterators< map >(); + check_null_iterators< multimap >(); + check_null_iterators< set >(); + check_null_iterators< multiset >(); + check_null_iterators< flat_set >(); + check_null_iterators< flat_multiset >(); + check_null_iterators< flat_map >(); + check_null_iterators< flat_multimap >(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/container/test/pair_test.cpp b/src/boost/libs/container/test/pair_test.cpp new file mode 100644 index 00000000..5ead7a45 --- /dev/null +++ b/src/boost/libs/container/test/pair_test.cpp @@ -0,0 +1,156 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include "movable_int.hpp" +#include "emplace_test.hpp" +#include +#include +#include + +//non_copymovable_int +//copyable_int +//movable_int +//movable_and_copyable_int + + +#include + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || (defined(BOOST_MSVC) && (BOOST_MSVC == 1700 || BOOST_MSVC == 1600)) +#define BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE +#endif + +#if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) +#include +#endif + +using namespace ::boost::container; + +int main () +{ + { + dtl::pair p1; + dtl::pair p2; + dtl::pair p3; + dtl::pair p4; + } + { //Constructible from two values + dtl::pair p1(1, 2); + dtl::pair p2(1, 2); + dtl::pair p3(1, 2); + dtl::pair p4(1, 2); + } + + { //Constructible from internal types + dtl::pair p2(test::copyable_int(1), test::copyable_int(2)); + { + test::movable_int a(1), b(2); + dtl::pair p3(::boost::move(a), ::boost::move(b)); + } + { + test::movable_and_copyable_int a(1), b(2); + dtl::pair p4(::boost::move(a), ::boost::move(b)); + } + } + { //piecewise construct from boost tuple + using namespace boost::tuples; + { + boost::container::dtl::pair p(piecewise_construct, tuple<>(), tuple<>()); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 0.f); + } + { + boost::container::dtl::pair p(piecewise_construct, tuple<>(), tuple(2.f)); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 2.f); + } + { + boost::container::dtl::pair p(piecewise_construct, tuple(2), tuple(1.f)); + BOOST_TEST(p.first == 2); + BOOST_TEST(p.second == 1.f); + } + { + boost::container::dtl::pair + < boost::container::dtl::pair + , boost::container::dtl::pair + > p(piecewise_construct, tuple(3, 4.f), tuple(8.,'a')); + BOOST_TEST(p.first.first == 3); + BOOST_TEST(p.first.second == 4.f); + BOOST_TEST(p.second.first == 8.); + BOOST_TEST(p.second.second == 'a'); + } + { + boost::container::dtl::pair + < tuple + , char + > p(piecewise_construct, tuple(3, 16.f, 32.), tuple('b')); + BOOST_TEST(p.first.get<0>() == 3); + BOOST_TEST(p.first.get<1>() == 16.f); + BOOST_TEST(p.first.get<2>() == 32.); + BOOST_TEST(p.second == 'b'); + } + } + #if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) + { //piecewise construct from std tuple + using std::tuple; + { + boost::container::dtl::pair p(piecewise_construct, tuple<>(), tuple<>()); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 0.f); + } + { + boost::container::dtl::pair p(piecewise_construct, tuple<>(), tuple(2.f)); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 2.f); + } + { + boost::container::dtl::pair p(piecewise_construct, tuple(2), tuple(1.f)); + BOOST_TEST(p.first == 2); + BOOST_TEST(p.second == 1.f); + } + { + boost::container::dtl::pair + < boost::container::dtl::pair + , boost::container::dtl::pair + > p(piecewise_construct, tuple(3, 4.f), tuple(8.,'a')); + BOOST_TEST(p.first.first == 3); + BOOST_TEST(p.first.second == 4.f); + BOOST_TEST(p.second.first == 8.); + BOOST_TEST(p.second.second == 'a'); + } + { + boost::container::dtl::pair + < tuple + , char + > p(piecewise_construct, tuple(3, 16.f, 32.), tuple('b')); + BOOST_TEST(std::get<0>(p.first) == 3); + BOOST_TEST(std::get<1>(p.first) == 16.f); + BOOST_TEST(std::get<2>(p.first) == 32.); + BOOST_TEST(p.second == 'b'); + } + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + typedef dtl::pair movable_pair_t; + typedef dtl::pair movable_pair_pair_t; + test::movable_int a(1), b(2), c(3), d(4); + movable_pair_pair_t p( piecewise_construct + , dtl::forward_as_tuple_impl(boost::move(a), boost::move(b)) + , dtl::forward_as_tuple_impl(boost::move(c), boost::move(d)) + ); + BOOST_TEST(p.first.first == 1); + BOOST_TEST(p.first.second == 2); + BOOST_TEST(p.second.first == 3); + BOOST_TEST(p.second.second == 4); + #endif + } + #endif //#!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + return ::boost::report_errors(); +} + +#include diff --git a/src/boost/libs/container/test/pmr_deque_test.cpp b/src/boost/libs/container/test/pmr_deque_test.cpp new file mode 100644 index 00000000..15c67e2a --- /dev/null +++ b/src/boost/libs/container/test/pmr_deque_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef deque > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_flat_map_test.cpp b/src/boost/libs/container/test/pmr_flat_map_test.cpp new file mode 100644 index 00000000..f98e497b --- /dev/null +++ b/src/boost/libs/container/test/pmr_flat_map_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef flat_map, pmr::polymorphic_allocator > > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_flat_set_test.cpp b/src/boost/libs/container/test/pmr_flat_set_test.cpp new file mode 100644 index 00000000..5c9efe1a --- /dev/null +++ b/src/boost/libs/container/test/pmr_flat_set_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef flat_set, pmr::polymorphic_allocator > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_list_test.cpp b/src/boost/libs/container/test/pmr_list_test.cpp new file mode 100644 index 00000000..794ccf52 --- /dev/null +++ b/src/boost/libs/container/test/pmr_list_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef list > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_map_test.cpp b/src/boost/libs/container/test/pmr_map_test.cpp new file mode 100644 index 00000000..5db3f109 --- /dev/null +++ b/src/boost/libs/container/test/pmr_map_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef map, pmr::polymorphic_allocator > > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_set_test.cpp b/src/boost/libs/container/test/pmr_set_test.cpp new file mode 100644 index 00000000..3093fd43 --- /dev/null +++ b/src/boost/libs/container/test/pmr_set_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef set, pmr::polymorphic_allocator > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_slist_test.cpp b/src/boost/libs/container/test/pmr_slist_test.cpp new file mode 100644 index 00000000..ed4b5ae9 --- /dev/null +++ b/src/boost/libs/container/test/pmr_slist_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::slist; + +int main() +{ + ::boost::container::slist dummy; + (void)dummy; + return 0; +} diff --git a/src/boost/libs/container/test/pmr_small_vector_test.cpp b/src/boost/libs/container/test/pmr_small_vector_test.cpp new file mode 100644 index 00000000..334588da --- /dev/null +++ b/src/boost/libs/container/test/pmr_small_vector_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef small_vector > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_stable_vector_test.cpp b/src/boost/libs/container/test/pmr_stable_vector_test.cpp new file mode 100644 index 00000000..246f071c --- /dev/null +++ b/src/boost/libs/container/test/pmr_stable_vector_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef stable_vector > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_static_vector_test.cpp b/src/boost/libs/container/test/pmr_static_vector_test.cpp new file mode 100644 index 00000000..6681f7cd --- /dev/null +++ b/src/boost/libs/container/test/pmr_static_vector_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::static_vector; + +int main() +{ + ::boost::container::static_vector dummy; + (void)dummy; + return 0; +} diff --git a/src/boost/libs/container/test/pmr_string_test.cpp b/src/boost/libs/container/test/pmr_string_test.cpp new file mode 100644 index 00000000..c8d81a5b --- /dev/null +++ b/src/boost/libs/container/test/pmr_string_test.cpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef basic_string, pmr::polymorphic_allocator > string_t; + typedef basic_string, pmr::polymorphic_allocator > wstring_t; + BOOST_STATIC_ASSERT(( is_same::value )); + BOOST_STATIC_ASSERT(( is_same::type>::value )); + BOOST_STATIC_ASSERT(( is_same::value )); + BOOST_STATIC_ASSERT(( is_same::type>::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same::value )); + BOOST_STATIC_ASSERT(( is_same::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/pmr_vector_test.cpp b/src/boost/libs/container/test/pmr_vector_test.cpp new file mode 100644 index 00000000..293291ce --- /dev/null +++ b/src/boost/libs/container/test/pmr_vector_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef vector > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/src/boost/libs/container/test/polymorphic_allocator_test.cpp b/src/boost/libs/container/test/polymorphic_allocator_test.cpp new file mode 100644 index 00000000..10899cac --- /dev/null +++ b/src/boost/libs/container/test/polymorphic_allocator_test.cpp @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include "derived_from_memory_resource.hpp" +#include "propagation_test_allocator.hpp" + +using namespace boost::container::pmr; +using namespace boost::container; + +void test_default_constructor() +{ + polymorphic_allocator a; + BOOST_TEST(a.resource() == get_default_resource()); +} + +void test_resource_constructor() +{ + polymorphic_allocator a(0); + BOOST_TEST(a.resource() == get_default_resource()); + + derived_from_memory_resource d; + polymorphic_allocator b(&d); + BOOST_TEST(&d == b.resource()); +} + +void test_copy_constructor() +{ + derived_from_memory_resource d; + polymorphic_allocator b(&d); + polymorphic_allocator c(b); + BOOST_TEST(b.resource() == c.resource()); +} + +void test_copy_assignment() +{ + derived_from_memory_resource d; + polymorphic_allocator b(&d); + polymorphic_allocator c; + BOOST_TEST(c.resource() == get_default_resource()); + c = b; + BOOST_TEST(c.resource() == b.resource()); +} + +void test_allocate() +{ + int dummy; + derived_from_memory_resource d; + polymorphic_allocator p(&d); + d.reset(); + d.do_allocate_return = &dummy; + p.allocate(2); + BOOST_TEST(d.do_allocate_called == true); + BOOST_TEST(d.do_allocate_return == &dummy); + //It shall allocate 2*sizeof(int), alignment_of + BOOST_TEST(d.do_allocate_bytes == 2*sizeof(int)); + BOOST_TEST(d.do_allocate_alignment == dtl::alignment_of::value); +} + +void test_deallocate() +{ + int dummy; + derived_from_memory_resource d; + polymorphic_allocator p(&d); + d.reset(); + p.deallocate(&dummy, 3); + BOOST_TEST(d.do_deallocate_called == true); + //It shall deallocate 2*sizeof(int), alignment_of + BOOST_TEST(d.do_deallocate_p == &dummy); + BOOST_TEST(d.do_deallocate_bytes == 3*sizeof(int)); + BOOST_TEST(d.do_deallocate_alignment == dtl::alignment_of::value); +} + +void test_construct() +{ + //0 arg + { + typedef allocator_argument_tester value_type; + value_type value; + value.~value_type(); + polymorphic_allocator pa; + pa.construct(&value); + BOOST_TEST(value.construction_type == NotUsesAllocator); + BOOST_TEST(value.value == 0); + value.~value_type(); + } + { + typedef allocator_argument_tester value_type; + value_type value; + value.~value_type(); + polymorphic_allocator pa; + pa.construct(&value); + BOOST_TEST(value.construction_type == ConstructiblePrefix); + BOOST_TEST(value.value == 0); + value.~value_type(); + } + { + typedef allocator_argument_tester value_type; + value_type value; + value.~value_type(); + polymorphic_allocator pa; + pa.construct(&value); + BOOST_TEST(value.construction_type == ConstructibleSuffix); + BOOST_TEST(value.value == 0); + value.~value_type(); + } + //1 arg + { + typedef allocator_argument_tester value_type; + value_type value; + value.~value_type(); + polymorphic_allocator pa; + pa.construct(&value, 2); + BOOST_TEST(value.construction_type == NotUsesAllocator); + BOOST_TEST(value.value == 2); + value.~value_type(); + } + { + typedef allocator_argument_tester value_type; + value_type value; + value.~value_type(); + polymorphic_allocator pa; + pa.construct(&value, 3); + BOOST_TEST(value.construction_type == ConstructiblePrefix); + BOOST_TEST(value.value == 3); + value.~value_type(); + } + { + typedef allocator_argument_tester value_type; + value_type value; + value.~value_type(); + polymorphic_allocator pa; + pa.construct(&value, 4); + BOOST_TEST(value.construction_type == ConstructibleSuffix); + BOOST_TEST(value.value == 4); + value.~value_type(); + } +} + +struct char_holder +{ + char m_char; + ~char_holder() + { destructor_called = true; } + static bool destructor_called; +}; + +bool char_holder::destructor_called = false; + +void test_destroy() +{ + char_holder ch; + polymorphic_allocator p; + BOOST_TEST(char_holder::destructor_called == false); + p.destroy(&ch); + BOOST_TEST(char_holder::destructor_called == true); +} + +void test_select_on_container_copy_construction() +{ + //select_on_container_copy_construction shall return + //a default constructed polymorphic_allocator + //which uses the default resource. + derived_from_memory_resource d; + polymorphic_allocator p(&d); + BOOST_TEST(get_default_resource() == p.select_on_container_copy_construction().resource()); +} + +void test_resource() +{ + derived_from_memory_resource d; + polymorphic_allocator p(&d); + BOOST_TEST(&d == p.resource()); +} + +int main() +{ + test_default_constructor(); + test_resource_constructor(); + test_copy_constructor(); + test_copy_assignment(); + test_allocate(); + test_deallocate(); + test_construct(); + test_destroy(); + test_select_on_container_copy_construction(); + test_resource(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/pool_resource_test.hpp b/src/boost/libs/container/test/pool_resource_test.hpp new file mode 100644 index 00000000..110274e3 --- /dev/null +++ b/src/boost/libs/container/test/pool_resource_test.hpp @@ -0,0 +1,493 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +#include "derived_from_memory_resource.hpp" +#include "memory_resource_logger.hpp" + +using namespace boost::container::pmr; + +template +struct derived_from_pool_resource + : public PoolResource +{ + derived_from_pool_resource(const pool_options& opts, memory_resource* upstream) + : PoolResource(opts, upstream) + {} + + explicit derived_from_pool_resource(memory_resource *p) + : PoolResource(p) + {} + + explicit derived_from_pool_resource(const pool_options &opts) + : PoolResource(opts) + {} + + derived_from_pool_resource() + : PoolResource() + {} + + using PoolResource::do_allocate; + using PoolResource::do_deallocate; + using PoolResource::do_is_equal; +}; + +template +void test_default_constructor() +{ + //With default options/resource + { + derived_from_memory_resource dmr; + dmr.reset(); + PoolResource m; + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } +} + +template +void test_upstream_constructor() +{ + //With a resource, default options + { + derived_from_memory_resource dmr; + dmr.reset(); + PoolResource m(&dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } +} + +template +void test_options_constructor() +{ + //Default options + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + pool_options opts; + PoolResource m(opts); + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + } + //Too large option values + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + pool_options opts; + opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk+1; + opts.largest_required_pool_block = pool_options_default_largest_required_pool_block+1; + PoolResource m(opts); + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + } + //Too small option values + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + pool_options opts; + opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block-1u; + PoolResource m(opts); + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_minimum_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + } + //In range option values + { + memory_resource_logger mrl; + BOOST_TEST(mrl.m_info.size() == 0u); + set_default_resource(&mrl); + pool_options opts; + opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk; + opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block; + PoolResource m(opts); + //test postconditions + BOOST_TEST(m.upstream_resource() == get_default_resource()); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_minimum_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(mrl.m_info.size() == 0u); + } +} + +template +void test_options_upstream_constructor() +{ + //Default options + { + derived_from_memory_resource dmr; + dmr.reset(); + pool_options opts; + PoolResource m(opts, &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } + //Too large option values + { + derived_from_memory_resource dmr; + dmr.reset(); + pool_options opts; + opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk+1; + opts.largest_required_pool_block = pool_options_default_largest_required_pool_block+1; + PoolResource m(opts, &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_default_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } + //Too small option values + { + derived_from_memory_resource dmr; + dmr.reset(); + pool_options opts; + opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block-1u; + PoolResource m(opts, &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + BOOST_TEST(m.options().largest_required_pool_block == pool_options_minimum_largest_required_pool_block); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } + //In range option values + { + derived_from_memory_resource dmr; + dmr.reset(); + pool_options opts; + opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk; + opts.largest_required_pool_block = pool_options_minimum_largest_required_pool_block; + PoolResource m(opts, &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + //max blocks is unchanged in this implementation + BOOST_TEST(m.options().max_blocks_per_chunk == pool_options_default_max_blocks_per_chunk); + //largest block is rounded to pow2 + BOOST_TEST(m.options().largest_required_pool_block == bi::detail::ceil_pow2(opts.largest_required_pool_block)); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } +} + +template +void test_options() +{ + //In range option values + { + derived_from_memory_resource dmr; + dmr.reset(); + pool_options opts; + opts.max_blocks_per_chunk = pool_options_default_max_blocks_per_chunk/2u; + opts.largest_required_pool_block = (pool_options_default_largest_required_pool_block + - pool_options_minimum_largest_required_pool_block) | std::size_t(1); //guaranteed to be non power of 2. + PoolResource m(opts, &dmr); + //test postconditions + BOOST_TEST(m.upstream_resource() == &dmr); + //max blocks is unchanged in this implementation + BOOST_TEST(m.options().max_blocks_per_chunk == opts.max_blocks_per_chunk); + //largest block is rounded to pow2 + BOOST_TEST(m.options().largest_required_pool_block == bi::detail::ceil_pow2(opts.largest_required_pool_block)); + //test it does not allocate any memory + BOOST_TEST(dmr.do_allocate_called == false); + } +} + +template +void test_do_allocate_deallocate() +{ + memory_resource_logger mrl; + { + derived_from_pool_resource dmbr(&mrl); + { + //First block from pool 0 + dmbr.do_allocate(1, 1); + //It should allocate the pool array plus an initial block + BOOST_TEST(mrl.m_info.size() == 2u); + //Second block from pool 0 + dmbr.do_allocate(1, 1); + //It should allocate again (with 2 chunks per block) + BOOST_TEST(mrl.m_info.size() == 3u); + //Third block from pool 0 + dmbr.do_allocate(1, 1); + //It should NOT allocate again (previous was a 2 block chunk) + BOOST_TEST(mrl.m_info.size() == 3u); + } + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); + + //Allocate and deallocate from the same chunk to test block caching + { + derived_from_pool_resource dmbr(&mrl); + { + //First block from pool 0 + void *p = dmbr.do_allocate(1, 1); + //It should allocate the pool array plus an initial block + BOOST_TEST(mrl.m_info.size() == 2u); + //No cached, as initial blocks per chunk is 1 + BOOST_TEST(dmbr.pool_cached_blocks(0u) == 0u); + //Deallocate and allocate again + dmbr.do_deallocate(p, 1, 1); + //Cached + BOOST_TEST(dmbr.pool_cached_blocks(0u) == 1u); + p = dmbr.do_allocate(1, 1); + //Reused + BOOST_TEST(dmbr.pool_cached_blocks(0u) == 0u); + //It should have NOT allocated (block reuse) + BOOST_TEST(mrl.m_info.size() == 2u); + + //Allocate again 2 times (a 2 block chunk is exhausted) + void *p2 = dmbr.do_allocate(1, 1); + //1 left cached + BOOST_TEST(dmbr.pool_cached_blocks(0u) == 1u); + void *p3 = dmbr.do_allocate(1, 1); + //Cache exhausted + BOOST_TEST(dmbr.pool_cached_blocks(0u) == 0u); + //Single chunk allocation happened + BOOST_TEST(mrl.m_info.size() == 3u); + + //Now deallocate all (no memory is freed, all cached) + dmbr.do_deallocate(p2, 1, 1); + dmbr.do_deallocate(p3, 1, 1); + dmbr.do_deallocate(p, 1, 1); + BOOST_TEST(dmbr.pool_cached_blocks(0u) == 3u); + BOOST_TEST(mrl.m_info.size() == 3u); + } + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); + + //Now test max block per chunk + { + pool_options opts; + //so after max_blocks_per_chunk*2-1 allocations, all new chunks must hold max_blocks_per_chunk blocks + opts.max_blocks_per_chunk = 32u; + derived_from_pool_resource dmbr(opts, &mrl); + { + std::size_t loops = opts.max_blocks_per_chunk*2-1u; + while(loops--){ + dmbr.do_allocate(1, 1); + } + //pool array + log2(max_blocks_per_chunk)+1 chunks (sizes [1, 2, 4, ...]) + const std::size_t num_chunks = bi::detail::floor_log2(opts.max_blocks_per_chunk)+1u; + BOOST_TEST(mrl.m_info.size() == 1u + num_chunks); + //Next allocation should allocate max_blocks_per_chunk blocks in a chunk so max_blocks_per_chunk-1 should remain free + dmbr.do_allocate(1, 1); + BOOST_TEST(mrl.m_info.size() == 1u + num_chunks + 1u); + BOOST_TEST(dmbr.pool_cached_blocks(0u) == (opts.max_blocks_per_chunk-1u)); + //Exhaust the chunk and allocate a new one, test max_blocks_per_chunk is not passed again + loops = opts.max_blocks_per_chunk; + while(loops--){ + dmbr.do_allocate(1, 1); + } + BOOST_TEST(mrl.m_info.size() == 1u + num_chunks + 2u); + BOOST_TEST(dmbr.pool_cached_blocks(0u) == (opts.max_blocks_per_chunk-1u)); + } + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); + + //Now test max block per chunk + { + pool_options opts; + //so after max_blocks_per_chunk*2-1 allocations, all new chunks must hold max_blocks_per_chunk blocks + opts.max_blocks_per_chunk = 32u; + derived_from_pool_resource dmbr(opts, &mrl); + { + std::size_t loops = opts.max_blocks_per_chunk*2-1u; + while(loops--){ + dmbr.do_allocate(1, 1); + } + //pool array + log2(max_blocks_per_chunk)+1 chunks (sizes [1, 2, 4, ...]) + BOOST_TEST(dmbr.pool_next_blocks_per_chunk(0u) == opts.max_blocks_per_chunk); + const std::size_t num_chunks = bi::detail::floor_log2(opts.max_blocks_per_chunk)+1u; + BOOST_TEST(mrl.m_info.size() == 1u + num_chunks); + //Next allocation should allocate max_blocks_per_chunk blocks in a chunk so max_blocks_per_chunk-1 should remain free + dmbr.do_allocate(1, 1); + BOOST_TEST(dmbr.pool_next_blocks_per_chunk(0u) == opts.max_blocks_per_chunk); + BOOST_TEST(mrl.m_info.size() == 1u + num_chunks + 1u); + BOOST_TEST(dmbr.pool_cached_blocks(0u) == (opts.max_blocks_per_chunk-1u)); + } + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); + + //Now test different pool sizes + { + pool_options opts; + //so after max_blocks_per_chunk*2-1 allocations, all new chunks must hold max_blocks_per_chunk blocks + opts.max_blocks_per_chunk = 1u; + derived_from_pool_resource dmbr(opts, &mrl); + const pool_options &final_opts = dmbr.options(); + + //Force pool creation + dmbr.do_deallocate(dmbr.do_allocate(1, 1), 1, 1); + //pool array plus first pool's chunk allocation + BOOST_TEST(mrl.m_info.size() == 2u); + //pool count must be: + // log2(the maximum block) - log2(the minimum block) + 1. Example if minimum block is 8, and maximum 32: + // log(32) - log2(8) + 1u = 3 pools (block sizes: 8, 16, and 32) + const std::size_t minimum_size = dmbr.pool_block(0u); + const std::size_t maximum_size = final_opts.largest_required_pool_block; + BOOST_TEST(dmbr.pool_count() == (1u + bi::detail::floor_log2(maximum_size) - bi::detail::floor_log2(minimum_size))); + for(std::size_t i = 0, s = minimum_size, max = dmbr.pool_count(); i != max; ++i, s*=2){ + //Except in the first pool, each cache should be empty + BOOST_TEST(dmbr.pool_cached_blocks(i) == std::size_t(i == 0)); + dmbr.do_deallocate(dmbr.do_allocate(s/2+1, 1), s/2+1, 1); + dmbr.do_deallocate(dmbr.do_allocate(s-1, 1), s-1, 1); + dmbr.do_deallocate(dmbr.do_allocate(s, 1), s, 1); + //pool array plus each previous chunk allocation + BOOST_TEST(mrl.m_info.size() == (1u + i + 1u)); + //as we limited max_blocks_per_chunk to 1, no cached blocks should be available except one + BOOST_TEST(dmbr.pool_cached_blocks(i) == 1u); + } + //Now test out of maximum values, which should go directly to upstream + //it should be directly deallocated. + void *p = dmbr.do_allocate(maximum_size+1, 1); + BOOST_TEST(mrl.m_info.size() == (1u + dmbr.pool_count() + 1u)); + dmbr.do_deallocate(p, maximum_size+1, 1); + BOOST_TEST(mrl.m_info.size() == (1u + dmbr.pool_count())); + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); +} + +template +void test_do_is_equal() +{ + //`this == dynamic_cast(&other)`. + memory_resource_logger mrl; + derived_from_pool_resource dmbr(&mrl); + derived_from_pool_resource dmbr2(&mrl); + BOOST_TEST(true == dmbr.do_is_equal(dmbr)); + BOOST_TEST(false == dmbr.do_is_equal(dmbr2)); + //A different type should be always different + derived_from_memory_resource dmr; + BOOST_TEST(false == dmbr.do_is_equal(dmr)); +} + +template +void test_release() +{ + memory_resource_logger mrl; + { + pool_options opts; + //so after max_blocks_per_chunk*2-1 allocations, all new chunks must hold max_blocks_per_chunk blocks + opts.max_blocks_per_chunk = 4u; + derived_from_pool_resource dmbr(opts, &mrl); + const pool_options &final_opts = dmbr.options(); + const std::size_t minimum_size = dmbr.pool_block(0u); + const std::size_t maximum_size = final_opts.largest_required_pool_block; + const std::size_t pool_count = 1u + bi::detail::floor_log2(maximum_size) - bi::detail::floor_log2(minimum_size); + + std::size_t expected_memory_allocs = 0; + for(std::size_t i = 0, imax = pool_count, s = minimum_size; i != imax; s*=2, ++i){ + for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){ + dmbr.do_allocate(s, 1); + } + //One due to the pool array, and for each pool, log2(max_blocks_per_chunk)+1 allocations + expected_memory_allocs = 1 + (bid::floor_log2(opts.max_blocks_per_chunk) + 1u)*(i+1); + //pool array plus each previous chunk allocation + BOOST_TEST(mrl.m_info.size() == expected_memory_allocs); + } + //Now with out-of-pool sizes + for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){ + dmbr.do_allocate(maximum_size+1, 1); + BOOST_TEST(mrl.m_info.size() == ++expected_memory_allocs); + } + //Now release memory and check all memory allocated through do_allocate was deallocated to upstream + dmbr.release(); + BOOST_TEST(mrl.m_info.size() == 1u); + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); +} + +template +void test_destructor() +{ + memory_resource_logger mrl; + { + pool_options opts; + //so after max_blocks_per_chunk*2-1 allocations, all new chunks must hold max_blocks_per_chunk blocks + opts.max_blocks_per_chunk = 4u; + derived_from_pool_resource dmbr(opts, &mrl); + const pool_options &final_opts = dmbr.options(); + const std::size_t minimum_size = dmbr.pool_block(0u); + const std::size_t maximum_size = final_opts.largest_required_pool_block; + const std::size_t pool_count = 1u + bi::detail::floor_log2(maximum_size) - bi::detail::floor_log2(minimum_size); + + std::size_t expected_memory_allocs = 0; + for(std::size_t i = 0, imax = pool_count, s = minimum_size; i != imax; s*=2, ++i){ + for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){ + dmbr.do_allocate(s, 1); + } + //One due to the pool array, and for each pool, log2(max_blocks_per_chunk)+1 allocations + expected_memory_allocs = 1 + (bid::floor_log2(opts.max_blocks_per_chunk) + 1u)*(i+1); + //pool array plus each previous chunk allocation + BOOST_TEST(mrl.m_info.size() == expected_memory_allocs); + } + //Now with out-of-pool sizes + for(std::size_t j = 0, j_max = opts.max_blocks_per_chunk*2u-1u; j != j_max; ++j){ + dmbr.do_allocate(maximum_size+1, 1); + BOOST_TEST(mrl.m_info.size() == ++expected_memory_allocs); + } + //Don't release, all memory, including internal allocations, should be automatically + //released after the destructor is run + } + BOOST_TEST(mrl.m_mismatches == 0u); + BOOST_TEST(mrl.m_info.size() == 0u); +} + + +template +void test_pool_resource() +{ + test_options_upstream_constructor(); + test_default_constructor(); + test_upstream_constructor(); + test_options_constructor(); + test_options(); + test_do_allocate_deallocate(); + test_do_is_equal(); + test_release(); + test_destructor(); +} diff --git a/src/boost/libs/container/test/print_container.hpp b/src/boost/libs/container/test/print_container.hpp new file mode 100644 index 00000000..2e49ec60 --- /dev/null +++ b/src/boost/libs/container/test/print_container.hpp @@ -0,0 +1,46 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_PRINTCONTAINER_HPP +#define BOOST_PRINTCONTAINER_HPP + +#include +#include + +namespace boost{ +namespace container { +namespace test{ + +//Function to dump data +template +void PrintContainers(MyBoostCont *boostcont, MyStdCont *stdcont) +{ + typename MyBoostCont::iterator itboost = boostcont->begin(), itboostend = boostcont->end(); + typename MyStdCont::iterator itstd = stdcont->begin(), itstdend = stdcont->end(); + + std::cout << "MyBoostCont" << std::endl; + for(; itboost != itboostend; ++itboost){ + std::cout << *itboost << std::endl; + } + std::cout << "MyStdCont" << std::endl; + + for(; itstd != itstdend; ++itstd){ + std::cout << *itstd << std::endl; + } +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_PRINTCONTAINER_HPP diff --git a/src/boost/libs/container/test/propagate_allocator_test.hpp b/src/boost/libs/container/test/propagate_allocator_test.hpp new file mode 100644 index 00000000..e3a50481 --- /dev/null +++ b/src/boost/libs/container/test/propagate_allocator_test.hpp @@ -0,0 +1,368 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP +#define BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP + +#include +#include +#include "dummy_test_allocator.hpp" + +#include + +namespace boost{ +namespace container { +namespace test{ + +template +struct alloc_propagate_base; + +template +class alloc_propagate_wrapper + : public alloc_propagate_base::template apply::type +{ + BOOST_COPYABLE_AND_MOVABLE(alloc_propagate_wrapper) + + public: + typedef typename alloc_propagate_base + ::template apply::type Base; + + typedef typename Base::allocator_type allocator_type; + typedef typename Base::value_type value_type; + typedef typename Base::size_type size_type; + + alloc_propagate_wrapper() + : Base() + {} + + explicit alloc_propagate_wrapper(const allocator_type &a) + : Base(a) + {} +/* + //sequence containers only + explicit alloc_propagate_wrapper(size_type n, const value_type &v, const allocator_type &a) + : Base(n, v, a) + {} + + alloc_propagate_wrapper(size_type n, const allocator_type &a) + : Base(n, a) + {}*/ + + template + alloc_propagate_wrapper(Iterator b, Iterator e, const allocator_type &a) + : Base(b, e, a) + {} + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + alloc_propagate_wrapper(std::initializer_list il, const allocator_type& a) + : Base(il, a) + {} +/* + //associative containers only + alloc_propagate_wrapper(std::initializer_list il, const Compare& comp, const allocator_type& a) + : Base(il, comp, a) + {}*/ + + #endif + + alloc_propagate_wrapper(const alloc_propagate_wrapper &x) + : Base(x) + {} + + alloc_propagate_wrapper(const alloc_propagate_wrapper &x, const allocator_type &a) + : Base(x, a) + {} + + alloc_propagate_wrapper(BOOST_RV_REF(alloc_propagate_wrapper) x) + : Base(boost::move(static_cast(x))) + {} + + alloc_propagate_wrapper(BOOST_RV_REF(alloc_propagate_wrapper) x, const allocator_type &a) + : Base(boost::move(static_cast(x)), a) + {} + + alloc_propagate_wrapper &operator=(BOOST_COPY_ASSIGN_REF(alloc_propagate_wrapper) x) + { this->Base::operator=((const Base &)x); return *this; } + + alloc_propagate_wrapper &operator=(BOOST_RV_REF(alloc_propagate_wrapper) x) + { this->Base::operator=(boost::move(static_cast(x))); return *this; } + + void swap(alloc_propagate_wrapper &x) + { this->Base::swap(x); } +}; + +template +struct get_real_stored_allocator +{ + typedef typename T::stored_allocator_type type; +}; + +template +void test_propagate_allocator_allocator_arg(); + +template +bool test_propagate_allocator() +{ + { + typedef propagation_test_allocator AlwaysPropagate; + typedef alloc_propagate_wrapper PropagateCont; + typedef typename get_real_stored_allocator::type StoredAllocator; + { + ////////////////////////////////////////// + //Test AlwaysPropagate allocator propagation + ////////////////////////////////////////// + + //default constructor + StoredAllocator::reset_unique_id(111); + PropagateCont c; //stored 112 + BOOST_TEST (c.get_stored_allocator().id_ == 112); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + } + { + //copy constructor + StoredAllocator::reset_unique_id(222); + PropagateCont c; //stored 223 + BOOST_TEST (c.get_stored_allocator().id_ == 223); + //propagate_on_copy_constructor produces copies, moves or RVO (depending on the compiler). + //For allocators that copy in select_on_container_copy_construction, at least we must have a copy + PropagateCont c2(c); //should propagate 223 + BOOST_TEST (c2.get_stored_allocator().id_ == 223); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ >= 1); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //move constructor + StoredAllocator::reset_unique_id(333); + PropagateCont c; //stored 334 + BOOST_TEST (c.get_stored_allocator().id_ == 334); + PropagateCont c2(boost::move(c)); //should propagate 334 + BOOST_TEST (c2.get_stored_allocator().id_ == 334); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ > 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //copy assign + StoredAllocator::reset_unique_id(444); + PropagateCont c; //stored 445 + BOOST_TEST (c.get_stored_allocator().id_ == 445); + PropagateCont c2; //stored 446 + BOOST_TEST (c2.get_stored_allocator().id_ == 446); + c2 = c; //should propagate 445 + BOOST_TEST (c2.get_stored_allocator().id_ == 445); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 1); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //move assign + StoredAllocator::reset_unique_id(555); + PropagateCont c; //stored 556 + BOOST_TEST (c.get_stored_allocator().id_ == 556); + PropagateCont c2; //stored 557 + BOOST_TEST (c2.get_stored_allocator().id_ == 557); + c = boost::move(c2); //should propagate 557 + BOOST_TEST (c.get_stored_allocator().id_ == 557); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 1); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + } + { + //swap + StoredAllocator::reset_unique_id(666); + PropagateCont c; //stored 667 + BOOST_TEST (c.get_stored_allocator().id_ == 667); + PropagateCont c2; //stored 668 + BOOST_TEST (c2.get_stored_allocator().id_ == 668); + c.swap(c2); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 1); + BOOST_TEST (c.get_stored_allocator().swaps_ == 1); + } + //And now allocator argument constructors + test_propagate_allocator_allocator_arg(); + } + + ////////////////////////////////////////// + //Test NeverPropagate allocator propagation + ////////////////////////////////////////// + { + typedef propagation_test_allocator NeverPropagate; + typedef alloc_propagate_wrapper NoPropagateCont; + typedef typename get_real_stored_allocator::type StoredAllocator; + { + //default constructor + StoredAllocator::reset_unique_id(111); + NoPropagateCont c; //stored 112 + BOOST_TEST (c.get_stored_allocator().id_ == 112); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + } + { + //copy constructor + //propagate_on_copy_constructor produces copies, moves or RVO (depending on the compiler) + //For allocators that don't copy in select_on_container_copy_construction we must have a default + //construction + StoredAllocator::reset_unique_id(222); + NoPropagateCont c; //stored 223 + BOOST_TEST (c.get_stored_allocator().id_ == 223); + NoPropagateCont c2(c); //should NOT propagate 223 + BOOST_TEST (c2.get_stored_allocator().id_ == 224); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ >= 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //move constructor + StoredAllocator::reset_unique_id(333); + NoPropagateCont c; //stored 334 + BOOST_TEST (c.get_stored_allocator().id_ == 334); + NoPropagateCont c2(boost::move(c)); // should NOT propagate 334 + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ >= 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //copy assign + StoredAllocator::reset_unique_id(444); + NoPropagateCont c; //stored 445 + NoPropagateCont c2; //stored 446 + c2 = c; // should NOT propagate 445 + BOOST_TEST (c2.get_stored_allocator().id_ == 446); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //move assign + StoredAllocator::reset_unique_id(555); + NoPropagateCont c; //stored 556 + NoPropagateCont c2; //stored 557 + c2 = c; // should NOT propagate 556 + BOOST_TEST (c2.get_stored_allocator().id_ == 557); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //swap + StoredAllocator::reset_unique_id(666); + NoPropagateCont c; //stored 667 + BOOST_TEST (c.get_stored_allocator().id_ == 667); + NoPropagateCont c2; //stored 668 + BOOST_TEST (c2.get_stored_allocator().id_ == 668); + c2.swap(c); // should NOT swap 667 and 668 + BOOST_TEST (c2.get_stored_allocator().id_ == 668); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + BOOST_TEST (c.get_stored_allocator().id_ == 667); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + } + //And now allocator argument constructors + test_propagate_allocator_allocator_arg(); + } + + return report_errors() == 0; +} + +template +void test_propagate_allocator_allocator_arg() +{ + typedef typename Container::allocator_type allocator_type; + typedef typename get_real_stored_allocator::type StoredAllocator; + + { //The allocator must be always propagated + //allocator constructor + allocator_type::reset_unique_id(111); + const allocator_type & a = allocator_type(); //stored 112 + Container c(a); //should propagate 112 + BOOST_TEST (c.get_stored_allocator().id_ == 112); + BOOST_TEST (c.get_stored_allocator().ctr_copies_ > 0); + BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c.get_stored_allocator().swaps_ == 0); + } + { + //copy allocator constructor + StoredAllocator::reset_unique_id(999); + Container c; + //stored_allocator_type could be the same type as allocator_type + //so reset it again to get a predictable result + allocator_type::reset_unique_id(222); + Container c2(c, allocator_type()); //should propagate 223 + BOOST_TEST (c2.get_stored_allocator().id_ == 223); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ > 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } + { + //move allocator constructor + StoredAllocator::reset_unique_id(999); + Container c; + //stored_allocator_type could be the same type as allocator_type + //so reset it again to get a predictable result + allocator_type::reset_unique_id(333); + Container c2(boost::move(c), allocator_type()); //should propagate 334 + BOOST_TEST (c2.get_stored_allocator().id_ == 334); + BOOST_TEST (c2.get_stored_allocator().ctr_copies_ > 0); + BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); + BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); + BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); + } +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP diff --git a/src/boost/libs/container/test/propagation_test_allocator.hpp b/src/boost/libs/container/test/propagation_test_allocator.hpp new file mode 100644 index 00000000..7c8643c5 --- /dev/null +++ b/src/boost/libs/container/test/propagation_test_allocator.hpp @@ -0,0 +1,268 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_ALLOCATOR_ARGUMENT_TESTER_HPP +#define BOOST_CONTAINER_TEST_ALLOCATOR_ARGUMENT_TESTER_HPP + +#include +#include +#include +#include + + +template +class propagation_test_allocator +{ + BOOST_COPYABLE_AND_MOVABLE(propagation_test_allocator) + public: + + template + struct rebind + { + typedef propagation_test_allocator other; + }; + + typedef boost::container::dtl::bool_ propagate_on_container_copy_assignment; + typedef boost::container::dtl::bool_ propagate_on_container_move_assignment; + typedef boost::container::dtl::bool_ propagate_on_container_swap; + typedef boost::container::dtl::bool_ is_always_equal; + typedef T value_type; + + propagation_test_allocator() + : m_default_contructed(true), m_move_contructed(false), m_move_assigned(false) + {} + + propagation_test_allocator(const propagation_test_allocator&) + : m_default_contructed(false), m_move_contructed(false), m_move_assigned(false) + {} + + propagation_test_allocator(BOOST_RV_REF(propagation_test_allocator) ) + : m_default_contructed(false), m_move_contructed(true), m_move_assigned(false) + {} + + template + propagation_test_allocator(BOOST_RV_REF_BEG propagation_test_allocator BOOST_RV_REF_END) + : m_default_contructed(false), m_move_contructed(true), m_move_assigned(false) + {} + + template + propagation_test_allocator(const propagation_test_allocator &) + {} + + propagation_test_allocator & operator=(BOOST_COPY_ASSIGN_REF(propagation_test_allocator)) + { return *this; } + + propagation_test_allocator & operator=(BOOST_RV_REF(propagation_test_allocator)) + { + m_move_assigned = true; + return *this; + } + + std::size_t max_size() const + { return std::size_t(-1); } + + T* allocate(std::size_t n) + { return (T*)::new char[n*sizeof(T)]; } + + void deallocate(T*p, std::size_t) + { delete []static_cast(static_cast(p)); } + + bool m_default_contructed; + bool m_move_contructed; + bool m_move_assigned; +}; + +template +bool operator==( const propagation_test_allocator& + , const propagation_test_allocator&) +{ return true; } + +template +bool operator!=( const propagation_test_allocator& + , const propagation_test_allocator&) +{ return false; } + +//This enum lists the construction options +//for an allocator-aware type +enum ConstructionTypeEnum +{ + ConstructiblePrefix, + ConstructibleSuffix, + ErasedTypePrefix, + ErasedTypeSuffix, + NotUsesAllocator +}; + +//This base class provices types for +//the derived class to implement each construction +//type. If a construction type does not apply +//the typedef is set to an internal nat +//so that the class is not constructible from +//the user arguments. +template +struct uses_allocator_base; + +template +struct uses_allocator_base +{ + typedef propagation_test_allocator allocator_type; + typedef allocator_type allocator_constructor_type; + struct nat{}; + typedef nat allocator_arg_type; +}; + +template +struct uses_allocator_base +{ + typedef propagation_test_allocator allocator_type; + typedef allocator_type allocator_constructor_type; + typedef boost::container::allocator_arg_t allocator_arg_type; +}; + +template +struct uses_allocator_base +{ + typedef boost::container::erased_type allocator_type; + typedef boost::container::pmr::polymorphic_allocator allocator_constructor_type; + typedef boost::container::allocator_arg_t allocator_arg_type; +}; + +template +struct uses_allocator_base +{ + typedef boost::container::erased_type allocator_type; + typedef boost::container::pmr::polymorphic_allocator allocator_constructor_type; + struct nat{}; + typedef nat allocator_arg_type; +}; + +template +struct uses_allocator_base +{ + struct nat{}; + typedef nat allocator_constructor_type; + typedef nat allocator_arg_type; +}; + +template +struct allocator_argument_tester + : uses_allocator_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(allocator_argument_tester) + + public: + + typedef uses_allocator_base base_type; + + //0 user argument constructors + allocator_argument_tester() + : construction_type(NotUsesAllocator), value(0) + {} + + explicit allocator_argument_tester + (typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(0) + {} + + explicit allocator_argument_tester + (typename base_type::allocator_arg_type, typename base_type::allocator_constructor_type) + : construction_type(ConstructiblePrefix), value(0) + {} + + //1 user argument constructors + explicit allocator_argument_tester(int i) + : construction_type(NotUsesAllocator), value(i) + {} + + allocator_argument_tester + (int i, typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(i) + {} + + allocator_argument_tester + ( typename base_type::allocator_arg_type + , typename base_type::allocator_constructor_type + , int i) + : construction_type(ConstructiblePrefix), value(i) + {} + + //Copy constructors + allocator_argument_tester(const allocator_argument_tester &other) + : construction_type(NotUsesAllocator), value(other.value) + {} + + allocator_argument_tester( const allocator_argument_tester &other + , typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(other.value) + {} + + allocator_argument_tester( typename base_type::allocator_arg_type + , typename base_type::allocator_constructor_type + , const allocator_argument_tester &other) + : construction_type(ConstructiblePrefix), value(other.value) + {} + + //Move constructors + allocator_argument_tester(BOOST_RV_REF(allocator_argument_tester) other) + : construction_type(NotUsesAllocator), value(other.value) + { other.value = 0; other.construction_type = NotUsesAllocator; } + + allocator_argument_tester( BOOST_RV_REF(allocator_argument_tester) other + , typename base_type::allocator_constructor_type) + : construction_type(ConstructibleSuffix), value(other.value) + { other.value = 0; other.construction_type = ConstructibleSuffix; } + + allocator_argument_tester( typename base_type::allocator_arg_type + , typename base_type::allocator_constructor_type + , BOOST_RV_REF(allocator_argument_tester) other) + : construction_type(ConstructiblePrefix), value(other.value) + { other.value = 0; other.construction_type = ConstructiblePrefix; } + + ConstructionTypeEnum construction_type; + int value; +}; + +namespace boost { +namespace container { + +template +struct constructible_with_allocator_prefix + < ::allocator_argument_tester > +{ + static const bool value = true; +}; + +template +struct constructible_with_allocator_prefix + < ::allocator_argument_tester > +{ + static const bool value = true; +}; + + +template +struct constructible_with_allocator_suffix + < ::allocator_argument_tester > +{ + static const bool value = true; +}; + +template +struct constructible_with_allocator_suffix + < ::allocator_argument_tester > +{ + static const bool value = true; +}; + +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_TEST_ALLOCATOR_ARGUMENT_TESTER_HPP diff --git a/src/boost/libs/container/test/resource_adaptor_test.cpp b/src/boost/libs/container/test/resource_adaptor_test.cpp new file mode 100644 index 00000000..5f8ece29 --- /dev/null +++ b/src/boost/libs/container/test/resource_adaptor_test.cpp @@ -0,0 +1,234 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include "propagation_test_allocator.hpp" +#include "derived_from_memory_resource.hpp" +#include +#include + +using namespace boost::container::pmr; + +static const std::size_t max_alignment_value = boost::move_detail::alignment_of::value; + +void test_default_constructor() +{ + typedef propagation_test_allocator alloc_t; + resource_adaptor ra; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); +} + +void test_copy_constructor() +{ + typedef propagation_test_allocator alloc_t; + resource_adaptor ra; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); + resource_adaptor rb(ra); + BOOST_TEST(rb.get_allocator().m_default_contructed == false); + BOOST_TEST(rb.get_allocator().m_move_contructed == false); +} + +void test_move_constructor() +{ + typedef propagation_test_allocator alloc_t; + resource_adaptor ra; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); + resource_adaptor rb(::boost::move(ra)); + BOOST_TEST(rb.get_allocator().m_default_contructed == false); + BOOST_TEST(rb.get_allocator().m_move_contructed == true); +} + +void test_lvalue_alloc_constructor() +{ + typedef propagation_test_allocator alloc_t; + alloc_t a; + resource_adaptor ra(a); + BOOST_TEST(ra.get_allocator().m_default_contructed == false); + BOOST_TEST(ra.get_allocator().m_move_contructed == false); +} + +void test_rvalue_alloc_constructor() +{ + typedef propagation_test_allocator alloc_t; + alloc_t a; + resource_adaptor ra(::boost::move(a)); + BOOST_TEST(ra.get_allocator().m_default_contructed == false); + BOOST_TEST(ra.get_allocator().m_move_contructed == true); +} + +void test_copy_assign() +{ + typedef propagation_test_allocator alloc_t; + resource_adaptor ra; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); + resource_adaptor rb; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); + rb = ra; + BOOST_TEST(rb.get_allocator().m_move_contructed == false); + BOOST_TEST(rb.get_allocator().m_move_assigned == false); +} + +void test_move_assign() +{ + typedef propagation_test_allocator alloc_t; + resource_adaptor ra; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); + resource_adaptor rb; + BOOST_TEST(ra.get_allocator().m_default_contructed == true); + rb = ::boost::move(ra); + BOOST_TEST(rb.get_allocator().m_move_contructed == false); + BOOST_TEST(rb.get_allocator().m_move_assigned == true); +} + +struct stateful +{ + public: + typedef char value_type; + + template + struct rebind + { typedef stateful other; }; + + stateful() + : m_u(0u) + {} + + char *allocate(std::size_t n) + { allocate_size = n; return allocate_return; } + + void deallocate(char *p, std::size_t n) + { deallocate_p = p; deallocate_size = n; } + + friend bool operator==(const stateful &l, const stateful &r) + { return l.m_u == r.m_u; } + + friend bool operator!=(const stateful &l, const stateful &r) + { return l.m_u != r.m_u; } + + public: + unsigned m_u; + std::size_t allocate_size; + char *allocate_return; + std::size_t deallocate_size; + char *deallocate_p; +}; + +void test_get_allocator() +{ + stateful a; + a.m_u = 999; + resource_adaptor ra(a); + const resource_adaptor & cra = ra; + BOOST_TEST( ra.get_allocator().m_u == 999); + BOOST_TEST(cra.get_allocator().m_u == 999); +} + +typedef resource_adaptor stateful_resource_adaptor_t; + +struct derived_from_resource_adaptor_stateful + : public stateful_resource_adaptor_t +{ + public: + typedef stateful_resource_adaptor_t base_t; + using base_t::do_allocate; + using base_t::do_deallocate; + using base_t::do_is_equal; +}; + +void test_do_allocate_deallocate() +{ + { + derived_from_resource_adaptor_stateful dra; + char dummy = 0; + dra.get_allocator().allocate_return = &dummy; + void *allocate_ret = dra.do_allocate(998, 1); + BOOST_TEST(allocate_ret == &dummy); + BOOST_TEST(dra.get_allocator().allocate_size == 998); + } + { + derived_from_resource_adaptor_stateful dra; + char dummy = 0; + dra.do_deallocate(&dummy, 1234, 1); + BOOST_TEST(dra.get_allocator().deallocate_p == &dummy); + BOOST_TEST(dra.get_allocator().deallocate_size == 1234); + } + { + //Overaligned allocation + derived_from_resource_adaptor_stateful dra; + const std::size_t alignment = max_alignment_value*2u; + const std::size_t bytes = alignment/2; + char dummy[alignment*2u+sizeof(void*)]; + dra.get_allocator().allocate_return = dummy; + + //First allocate + void *allocate_ret = dra.do_allocate(bytes, alignment); + BOOST_TEST( (char*)allocate_ret >= (dummy+sizeof(void*)) && (char*)allocate_ret < (dummy + sizeof(dummy)) ); + BOOST_TEST( (std::size_t(allocate_ret) & (alignment - 1u)) == 0 ); + BOOST_TEST( dra.get_allocator().allocate_size >= (alignment/2+sizeof(void*)) ); + + //Then allocate + dra.do_deallocate(allocate_ret, bytes, alignment); + BOOST_TEST(dra.get_allocator().deallocate_p == dummy); + BOOST_TEST(dra.get_allocator().deallocate_size == dra.get_allocator().allocate_size); + } + { + typedef resource_adaptor< boost::container::new_allocator > new_resource_alloc_t; + new_resource_alloc_t ra; + boost::container::pmr::memory_resource &mr = ra; + + //new_allocator, low alignment + mr.deallocate(mr.allocate(16, 1), 16, 1); + + //new_allocator, high alignment + mr.deallocate(mr.allocate(16, max_alignment_value*4u), 16, max_alignment_value*4u); + } + { + typedef resource_adaptor > new_resource_alloc_t; + new_resource_alloc_t ra; + boost::container::pmr::memory_resource &mr = ra; + + //std::allocator, low alignment + mr.deallocate(mr.allocate(16, 1), 16, 1); + + //std::allocator, high alignment + mr.deallocate(mr.allocate(16, max_alignment_value*4u), 16, max_alignment_value*4u); + } +} + +void test_do_is_equal() +{ + derived_from_resource_adaptor_stateful dra; + derived_from_memory_resource dmr; + //Different dynamic type must return false + BOOST_TEST(dra.do_is_equal(dmr) == false); + + //Same dynamic type with same state must return true + derived_from_resource_adaptor_stateful dra2; + BOOST_TEST(dra.do_is_equal(dra2) == true); + + //Same dynamic type with different state must return false + dra2.get_allocator().m_u = 1234; + BOOST_TEST(dra.do_is_equal(dra2) == false); +} + +int main() +{ + test_default_constructor(); + test_copy_constructor(); + test_move_constructor(); + test_lvalue_alloc_constructor(); + test_rvalue_alloc_constructor(); + test_copy_assign(); + test_move_assign(); + test_get_allocator(); + test_do_allocate_deallocate(); + test_do_is_equal(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/scoped_allocator_adaptor_test.cpp b/src/boost/libs/container/test/scoped_allocator_adaptor_test.cpp new file mode 100644 index 00000000..6a051e27 --- /dev/null +++ b/src/boost/libs/container/test/scoped_allocator_adaptor_test.cpp @@ -0,0 +1,1377 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include + +// container/detail +#include +// move +#include +#include +//boost +#include +// std +#include +#include + +#if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) +#include +#endif + +//test +#include + +#include "allocator_argument_tester.hpp" + +template +struct tagged_integer +{}; + +struct mark_on_destructor +{ + mark_on_destructor() + { + destroyed = false; + } + + ~mark_on_destructor() + { + destroyed = true; + } + + static bool destroyed; +}; + +bool mark_on_destructor::destroyed = false; + +#include +#include +#include +#include + +int main() +{ + using namespace boost::container; + + typedef propagation_test_allocator, 0> OuterAlloc; + typedef propagation_test_allocator, 10> Outer10IdAlloc; + typedef propagation_test_allocator, 0> Rebound9OuterAlloc; + typedef propagation_test_allocator, 1> InnerAlloc1; + typedef propagation_test_allocator, 2> InnerAlloc2; + typedef propagation_test_allocator, 11> Inner11IdAlloc1; + + typedef propagation_test_allocator, 0, false> OuterAllocFalseHasTrueTypes; + typedef propagation_test_allocator, 0, true> OuterAllocTrueHasTrueTypes; + typedef propagation_test_allocator, 1, false> InnerAlloc1FalseHasTrueTypes; + typedef propagation_test_allocator, 1, true> InnerAlloc1TrueHasTrueTypes; + typedef propagation_test_allocator, 2, false> InnerAlloc2FalseHasTrueTypes; + typedef propagation_test_allocator, 2, true> InnerAlloc2TrueHasTrueTypes; + + // + typedef scoped_allocator_adaptor< OuterAlloc > Scoped0Inner; + typedef scoped_allocator_adaptor< OuterAlloc + , InnerAlloc1 > Scoped1Inner; + typedef scoped_allocator_adaptor< OuterAlloc + , InnerAlloc1 + , InnerAlloc2 > Scoped2Inner; + typedef scoped_allocator_adaptor + < scoped_allocator_adaptor + + > ScopedScoped0Inner; + typedef scoped_allocator_adaptor + < scoped_allocator_adaptor + + , InnerAlloc1 + > ScopedScoped1Inner; + typedef scoped_allocator_adaptor< Rebound9OuterAlloc > Rebound9Scoped0Inner; + typedef scoped_allocator_adaptor< Rebound9OuterAlloc + , InnerAlloc1 > Rebound9Scoped1Inner; + typedef scoped_allocator_adaptor< Rebound9OuterAlloc + , InnerAlloc1 + , InnerAlloc2 > Rebound9Scoped2Inner; + + //outer_allocator_type + BOOST_STATIC_ASSERT(( dtl::is_same< OuterAlloc + , Scoped0Inner::outer_allocator_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< OuterAlloc + , Scoped1Inner::outer_allocator_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< OuterAlloc + , Scoped2Inner::outer_allocator_type>::value )); + //value_type + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::value_type + , Scoped0Inner::value_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::value_type + , Scoped1Inner::value_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::value_type + , Scoped2Inner::value_type>::value )); + //size_type + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::size_type + , Scoped0Inner::size_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::size_type + , Scoped1Inner::size_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::size_type + , Scoped2Inner::size_type>::value )); + + //difference_type + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::difference_type + , Scoped0Inner::difference_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::difference_type + , Scoped1Inner::difference_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::difference_type + , Scoped2Inner::difference_type>::value )); + + //pointer + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::pointer + , Scoped0Inner::pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::pointer + , Scoped1Inner::pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::pointer + , Scoped2Inner::pointer>::value )); + + //const_pointer + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::const_pointer + , Scoped0Inner::const_pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::const_pointer + , Scoped1Inner::const_pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::const_pointer + , Scoped2Inner::const_pointer>::value )); + + //void_pointer + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::void_pointer + , Scoped0Inner::void_pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::void_pointer + , Scoped1Inner::void_pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::void_pointer + , Scoped2Inner::void_pointer>::value )); + + //const_void_pointer + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::const_void_pointer + , Scoped0Inner::const_void_pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::const_void_pointer + , Scoped1Inner::const_void_pointer>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< allocator_traits::const_void_pointer + , Scoped2Inner::const_void_pointer>::value )); + + //rebind + BOOST_STATIC_ASSERT(( dtl::is_same >::other + , Rebound9Scoped0Inner >::value )); + BOOST_STATIC_ASSERT(( dtl::is_same >::other + , Rebound9Scoped1Inner >::value )); + BOOST_STATIC_ASSERT(( dtl::is_same >::other + , Rebound9Scoped2Inner >::value )); + + //inner_allocator_type + BOOST_STATIC_ASSERT(( dtl::is_same< Scoped0Inner + , Scoped0Inner::inner_allocator_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< scoped_allocator_adaptor + , Scoped1Inner::inner_allocator_type>::value )); + BOOST_STATIC_ASSERT(( dtl::is_same< scoped_allocator_adaptor + , Scoped2Inner::inner_allocator_type>::value )); + + { + //Propagation test + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes > Scoped0InnerF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes > Scoped0InnerT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1FalseHasTrueTypes > Scoped1InnerFF; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1TrueHasTrueTypes > Scoped1InnerFT; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1FalseHasTrueTypes > Scoped1InnerTF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1TrueHasTrueTypes > Scoped1InnerTT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerFFF; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerFFT; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerFTF; + typedef scoped_allocator_adaptor< OuterAllocFalseHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerFTT; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerTFF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1FalseHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerTFT; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2FalseHasTrueTypes > Scoped2InnerTTF; + typedef scoped_allocator_adaptor< OuterAllocTrueHasTrueTypes + , InnerAlloc1TrueHasTrueTypes + , InnerAlloc2TrueHasTrueTypes > Scoped2InnerTTT; + + //propagate_on_container_copy_assignment + //0 inner + BOOST_STATIC_ASSERT(( !Scoped0InnerF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped0InnerT::propagate_on_container_copy_assignment::value )); + //1 inner + BOOST_STATIC_ASSERT(( !Scoped1InnerFF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerFT::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTT::propagate_on_container_copy_assignment::value )); + //2 inner + BOOST_STATIC_ASSERT(( !Scoped2InnerFFF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFFT::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFTF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFTT::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTFF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTFT::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTF::propagate_on_container_copy_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTT::propagate_on_container_copy_assignment::value )); + + //propagate_on_container_move_assignment + //0 inner + BOOST_STATIC_ASSERT(( !Scoped0InnerF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped0InnerT::propagate_on_container_move_assignment::value )); + //1 inner + BOOST_STATIC_ASSERT(( !Scoped1InnerFF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerFT::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTT::propagate_on_container_move_assignment::value )); + //2 inner + BOOST_STATIC_ASSERT(( !Scoped2InnerFFF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFFT::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFTF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFTT::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTFF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTFT::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTF::propagate_on_container_move_assignment::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTT::propagate_on_container_move_assignment::value )); + + //propagate_on_container_swap + //0 inner + BOOST_STATIC_ASSERT(( !Scoped0InnerF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped0InnerT::propagate_on_container_swap::value )); + //1 inner + BOOST_STATIC_ASSERT(( !Scoped1InnerFF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerFT::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTT::propagate_on_container_swap::value )); + //2 inner + BOOST_STATIC_ASSERT(( !Scoped2InnerFFF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFFT::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFTF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerFTT::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTFF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTFT::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTF::propagate_on_container_swap::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTT::propagate_on_container_swap::value )); + //is_always_equal + //0 inner + BOOST_STATIC_ASSERT(( !Scoped0InnerF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( Scoped0InnerT::is_always_equal::value )); + //1 inner + BOOST_STATIC_ASSERT(( !Scoped1InnerFF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped1InnerFT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped1InnerTF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( Scoped1InnerTT::is_always_equal::value )); + //2 inner + BOOST_STATIC_ASSERT(( !Scoped2InnerFFF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerFFT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerFTF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerFTT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerTFF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerTFT::is_always_equal::value )); + BOOST_STATIC_ASSERT(( !Scoped2InnerTTF::is_always_equal::value )); + BOOST_STATIC_ASSERT(( Scoped2InnerTTT::is_always_equal::value )); + } + + //Default constructor + { + Scoped0Inner s0i; + Scoped1Inner s1i; + //Swap + { + Scoped0Inner s0i2; + Scoped1Inner s1i2; + boost::adl_move_swap(s0i, s0i2); + boost::adl_move_swap(s1i, s1i2); + } + } + + //Default constructor + { + Scoped0Inner s0i; + Scoped1Inner s1i; + } + + //Copy constructor/assignment + { + Scoped0Inner s0i; + Scoped1Inner s1i; + Scoped2Inner s2i; + + Scoped0Inner s0i_b(s0i); + Scoped1Inner s1i_b(s1i); + Scoped2Inner s2i_b(s2i); + + BOOST_TEST(s0i == s0i_b); + BOOST_TEST(s1i == s1i_b); + BOOST_TEST(s2i == s2i_b); + + s0i_b = s0i; + s1i_b = s1i; + s2i_b = s2i; + + BOOST_TEST(s0i == s0i_b); + BOOST_TEST(s1i == s1i_b); + BOOST_TEST(s2i == s2i_b); + } + + //Copy/move constructor/assignment + { + Scoped0Inner s0i; + Scoped1Inner s1i; + Scoped2Inner s2i; + + Scoped0Inner s0i_b(::boost::move(s0i)); + Scoped1Inner s1i_b(::boost::move(s1i)); + Scoped2Inner s2i_b(::boost::move(s2i)); + + BOOST_TEST(s0i_b.outer_allocator().m_move_contructed); + BOOST_TEST(s1i_b.outer_allocator().m_move_contructed); + BOOST_TEST(s2i_b.outer_allocator().m_move_contructed); + + s0i_b = ::boost::move(s0i); + s1i_b = ::boost::move(s1i); + s2i_b = ::boost::move(s2i); + + BOOST_TEST(s0i_b.outer_allocator().m_move_assigned); + BOOST_TEST(s1i_b.outer_allocator().m_move_assigned); + BOOST_TEST(s2i_b.outer_allocator().m_move_assigned); + } + + //inner_allocator() + { + Scoped0Inner s0i; + Scoped1Inner s1i; + Scoped2Inner s2i; + const Scoped0Inner const_s0i; + const Scoped1Inner const_s1i; + const Scoped2Inner const_s2i; + + Scoped0Inner::inner_allocator_type &s0i_inner = s0i.inner_allocator(); + (void)s0i_inner; + const Scoped0Inner::inner_allocator_type &const_s0i_inner = const_s0i.inner_allocator(); + (void)const_s0i_inner; + Scoped1Inner::inner_allocator_type &s1i_inner = s1i.inner_allocator(); + (void)s1i_inner; + const Scoped1Inner::inner_allocator_type &const_s1i_inner = const_s1i.inner_allocator(); + (void)const_s1i_inner; + Scoped2Inner::inner_allocator_type &s2i_inner = s2i.inner_allocator(); + (void)s2i_inner; + const Scoped2Inner::inner_allocator_type &const_s2i_inner = const_s2i.inner_allocator(); + (void)const_s2i_inner; + } + + //operator==/!= + { + const Scoped0Inner const_s0i; + const Rebound9Scoped0Inner const_rs0i; + + BOOST_TEST(const_s0i == const_s0i); + BOOST_TEST(const_rs0i == const_s0i); + BOOST_TEST(const_s0i == const_s0i); + BOOST_TEST(const_s0i == const_rs0i); + + const Scoped1Inner const_s1i; + const Rebound9Scoped1Inner const_rs1i; + + BOOST_TEST(const_s1i == const_s1i); + BOOST_TEST(const_rs1i == const_s1i); + + BOOST_TEST(const_s1i == const_s1i); + BOOST_TEST(const_s1i == const_rs1i); + + const Scoped2Inner const_s2i; + const Rebound9Scoped2Inner const_rs2i; + + BOOST_TEST(const_s2i == const_s2i); + BOOST_TEST(const_s2i == const_rs2i); + + BOOST_TEST(const_s2i == const_s2i); + BOOST_TEST(const_s2i == const_rs2i); + } + + //outer_allocator() + { + Scoped0Inner s0i; + Scoped1Inner s1i; + Scoped2Inner s2i; + const Scoped0Inner const_s0i; + const Scoped1Inner const_s1i; + const Scoped2Inner const_s2i; + + Scoped0Inner::outer_allocator_type &s0i_inner = s0i.outer_allocator(); + (void)s0i_inner; + const Scoped0Inner::outer_allocator_type &const_s0i_inner = const_s0i.outer_allocator(); + (void)const_s0i_inner; + Scoped1Inner::outer_allocator_type &s1i_inner = s1i.outer_allocator(); + (void)s1i_inner; + const Scoped1Inner::outer_allocator_type &const_s1i_inner = const_s1i.outer_allocator(); + (void)const_s1i_inner; + Scoped2Inner::outer_allocator_type &s2i_inner = s2i.outer_allocator(); + (void)s2i_inner; + const Scoped2Inner::outer_allocator_type &const_s2i_inner = const_s2i.outer_allocator(); + (void)const_s2i_inner; + } + + //max_size() + { + const Scoped0Inner const_s0i; + const Scoped1Inner const_s1i; + const Scoped2Inner const_s2i; + const OuterAlloc const_oa; + const InnerAlloc1 const_ia1; + const InnerAlloc2 const_ia2; + + BOOST_TEST(const_s0i.max_size() == const_oa.max_size()); + BOOST_TEST(const_s1i.max_size() == const_oa.max_size()); + + BOOST_TEST(const_s2i.max_size() == const_oa.max_size()); + BOOST_TEST(const_s1i.inner_allocator().max_size() == const_ia1.max_size()); + BOOST_TEST(const_s2i.inner_allocator().inner_allocator().max_size() == const_ia2.max_size()); + } + //Copy and move operations + { + //Construction + { + Scoped0Inner s0i_a, s0i_b(s0i_a), s0i_c(::boost::move(s0i_b)); + Scoped1Inner s1i_a, s1i_b(s1i_a), s1i_c(::boost::move(s1i_b)); + Scoped2Inner s2i_a, s2i_b(s2i_a), s2i_c(::boost::move(s2i_b)); + } + //Assignment + { + Scoped0Inner s0i_a, s0i_b; + s0i_a = s0i_b; + s0i_a = ::boost::move(s0i_b); + Scoped1Inner s1i_a, s1i_b; + s1i_a = s1i_b; + s1i_a = ::boost::move(s1i_b); + Scoped2Inner s2i_a, s2i_b; + s2i_a = s2i_b; + s2i_a = ::boost::move(s2i_b); + } + + OuterAlloc oa; + InnerAlloc1 ia1; + InnerAlloc2 ia2; + Rebound9OuterAlloc roa; + Rebound9Scoped0Inner rs0i; + Rebound9Scoped1Inner rs1i; + Rebound9Scoped2Inner rs2i; + + //Copy from outer + { + Scoped0Inner s0i(oa); + Scoped1Inner s1i(oa, ia1); + Scoped2Inner s2i(oa, ia1, ia2); + } + //Move from outer + { + Scoped0Inner s0i(::boost::move(oa)); + Scoped1Inner s1i(::boost::move(oa), ia1); + Scoped2Inner s2i(::boost::move(oa), ia1, ia2); + } + //Copy from rebound outer + { + Scoped0Inner s0i(roa); + Scoped1Inner s1i(roa, ia1); + Scoped2Inner s2i(roa, ia1, ia2); + } + //Move from rebound outer + { + Scoped0Inner s0i(::boost::move(roa)); + Scoped1Inner s1i(::boost::move(roa), ia1); + Scoped2Inner s2i(::boost::move(roa), ia1, ia2); + } + //Copy from rebound scoped + { + Scoped0Inner s0i(rs0i); + Scoped1Inner s1i(rs1i); + Scoped2Inner s2i(rs2i); + } + //Move from rebound scoped + { + Scoped0Inner s0i(::boost::move(rs0i)); + Scoped1Inner s1i(::boost::move(rs1i)); + Scoped2Inner s2i(::boost::move(rs2i)); + } + } + + { + vector > > dummy; + dummy.push_back(0); + } + + //destroy() + { + { + Scoped0Inner s0i; + mark_on_destructor mod; + s0i.destroy(&mod); + BOOST_TEST(mark_on_destructor::destroyed); + } + + { + Scoped1Inner s1i; + mark_on_destructor mod; + s1i.destroy(&mod); + BOOST_TEST(mark_on_destructor::destroyed); + } + { + Scoped2Inner s2i; + mark_on_destructor mod; + s2i.destroy(&mod); + BOOST_TEST(mark_on_destructor::destroyed); + } + } + + //construct + { + //////////////////////////////////////////////////////////// + //First check scoped allocator with just OuterAlloc. + //In this case OuterAlloc (propagation_test_allocator with tag 0) should be + //used to construct types. + //////////////////////////////////////////////////////////// + { + Scoped0Inner s0i; + //Check construction with 0 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s0i.construct(&dummy); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 0 ); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s0i.construct(&dummy); + BOOST_TEST(dummy.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s0i.construct(&dummy); + BOOST_TEST(dummy.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + + //Check construction with 1 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s0i.construct(&dummy, 1); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 1); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s0i.construct(&dummy, 2); + BOOST_TEST(dummy.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.value == 2); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s0i.construct(&dummy, 3); + BOOST_TEST(dummy.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.value == 3); + dummy.~MarkType(); + } + } + //////////////////////////////////////////////////////////// + //Then check scoped allocator with OuterAlloc and InnerAlloc. + //In this case InnerAlloc (propagation_test_allocator with tag 1) should be + //used to construct types. + //////////////////////////////////////////////////////////// + { + Scoped1Inner s1i; + //Check construction with 0 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s1i.construct(&dummy); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s1i.construct(&dummy); + BOOST_TEST(dummy.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s1i.construct(&dummy); + BOOST_TEST(dummy.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + + //Check construction with 1 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s1i.construct(&dummy, 1); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 1); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s1i.construct(&dummy, 2); + BOOST_TEST(dummy.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.value == 2); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + s1i.construct(&dummy, 3); + BOOST_TEST(dummy.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.value == 3); + dummy.~MarkType(); + } + } + + ////////////////////////////////////////////////////////////////////////////////// + //Now test recursive OuterAllocator types (OuterAllocator is a scoped_allocator) + ////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////// + //First check scoped allocator with just OuterAlloc. + //In this case OuterAlloc (propagation_test_allocator with tag 0) should be + //used to construct types. + //////////////////////////////////////////////////////////// + { + //Check outer_allocator_type is scoped + BOOST_STATIC_ASSERT(( is_scoped_allocator + ::value )); + BOOST_STATIC_ASSERT(( dtl::is_same + < outermost_allocator::type + , Outer10IdAlloc + >::value )); + BOOST_STATIC_ASSERT(( dtl::is_same + < ScopedScoped0Inner::outer_allocator_type + , scoped_allocator_adaptor + >::value )); + BOOST_STATIC_ASSERT(( dtl::is_same + < scoped_allocator_adaptor::outer_allocator_type + , Outer10IdAlloc + >::value )); + ScopedScoped0Inner ssro0i; + Outer10IdAlloc & val = outermost_allocator::get(ssro0i); + (void)val; + //Check construction with 0 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro0i.construct(&dummy); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro0i.construct(&dummy); + BOOST_TEST(dummy.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro0i.construct(&dummy); + BOOST_TEST(dummy.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + + //Check construction with 1 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro0i.construct(&dummy, 1); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 1); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro0i.construct(&dummy, 2); + BOOST_TEST(dummy.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.value == 2); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro0i.construct(&dummy, 3); + BOOST_TEST(dummy.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.value == 3); + dummy.~MarkType(); + } + } + //////////////////////////////////////////////////////////// + //Then check scoped allocator with OuterAlloc and InnerAlloc. + //In this case inner_allocator_type is not convertible to + //::allocator_argument_tester so uses_allocator + //should be false on all tests. + //////////////////////////////////////////////////////////// + { + //Check outer_allocator_type is scoped + BOOST_STATIC_ASSERT(( is_scoped_allocator + ::value )); + BOOST_STATIC_ASSERT(( dtl::is_same + < outermost_allocator::type + , Outer10IdAlloc + >::value )); + BOOST_STATIC_ASSERT(( dtl::is_same + < ScopedScoped1Inner::outer_allocator_type + , scoped_allocator_adaptor + >::value )); + BOOST_STATIC_ASSERT(( dtl::is_same + < scoped_allocator_adaptor::outer_allocator_type + , Outer10IdAlloc + >::value )); + BOOST_STATIC_ASSERT(( ! + uses_allocator + < ::allocator_argument_tester + , ScopedScoped1Inner::inner_allocator_type::outer_allocator_type + >::value )); + ScopedScoped1Inner ssro1i; + Outer10IdAlloc & val = outermost_allocator::get(ssro1i); + (void)val; + + //Check construction with 0 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro1i.construct(&dummy); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro1i.construct(&dummy); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro1i.construct(&dummy); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 0); + dummy.~MarkType(); + } + + //Check construction with 1 user arguments + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro1i.construct(&dummy, 1); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 1); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro1i.construct(&dummy, 2); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 2); + dummy.~MarkType(); + } + { + typedef ::allocator_argument_tester MarkType; + MarkType dummy; + dummy.~MarkType(); + ssro1i.construct(&dummy, 3); + BOOST_TEST(dummy.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.value == 3); + dummy.~MarkType(); + } + } + + //////////////////////////////////////////////////////////// + //Now check propagation to pair + //////////////////////////////////////////////////////////// + //First check scoped allocator with just OuterAlloc. + //In this case OuterAlloc (propagation_test_allocator with tag 0) should be + //used to construct types. + //////////////////////////////////////////////////////////// + { + using dtl::pair; + typedef propagation_test_allocator< pair< tagged_integer<0> + , tagged_integer<0> >, 0> OuterPairAlloc; + // + typedef scoped_allocator_adaptor < OuterPairAlloc > ScopedPair0Inner; + + ScopedPair0Inner s0i; + //Check construction with 0 user arguments + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + #if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) + //Check construction with 0 user arguments and Std tuple + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + #endif //BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE + //Check construction with 1 user arguments for each pair + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, 1, 1); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, 1, 1); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, 2, 2); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + //Check construction with 1 user arguments for each pair and Boost tuple + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, boost::tuple(1), boost::tuple(1)); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, boost::tuple(1), boost::tuple(1)); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, boost::tuple(2), boost::tuple(2)); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + #if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) + //Check construction with 1 user arguments for each pair and Boost tuple + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple(1), std::tuple(1)); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple(1), std::tuple(1)); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple(2), std::tuple(2)); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + #endif //BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE + //Check construction with pair copy construction + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy, dummy2; + dummy.~MarkTypePair(); + s0i.construct(&dummy, dummy2); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy, dummy2(1, 1); + dummy.~MarkTypePair(); + s0i.construct(&dummy, dummy2); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy, dummy2(2, 2); + dummy.~MarkTypePair(); + s0i.construct(&dummy, dummy2); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + //Check construction with pair move construction + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy, dummy2(3, 3); + dummy2.first.construction_type = dummy2.second.construction_type = ConstructibleSuffix; + dummy.~MarkTypePair(); + s0i.construct(&dummy, ::boost::move(dummy2)); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 3); + BOOST_TEST(dummy.second.value == 3); + BOOST_TEST(dummy2.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy2.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy2.first.value == 0); + BOOST_TEST(dummy2.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy, dummy2(1, 1); + dummy.~MarkTypePair(); + s0i.construct(&dummy, ::boost::move(dummy2)); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + BOOST_TEST(dummy2.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy2.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy2.first.value == 0); + BOOST_TEST(dummy2.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy, dummy2(2, 2); + dummy.~MarkTypePair(); + s0i.construct(&dummy, ::boost::move(dummy2)); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + BOOST_TEST(dummy2.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy2.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy2.first.value == 0); + BOOST_TEST(dummy2.second.value == 0); + dummy.~MarkTypePair(); + } + //Check construction with related pair copy construction + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + pair dummy2; + dummy.~MarkTypePair(); + s0i.construct(&dummy, dummy2); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + pair dummy2(1, 1); + dummy.~MarkTypePair(); + s0i.construct(&dummy, dummy2); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + pair dummy2(2, 2); + dummy.~MarkTypePair(); + s0i.construct(&dummy, dummy2); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + //Check construction with related pair move construction + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + pair dummy2(3, 3); + dummy.~MarkTypePair(); + s0i.construct(&dummy, ::boost::move(dummy2)); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 3); + BOOST_TEST(dummy.second.value == 3); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + pair dummy2(1, 1); + dummy.~MarkTypePair(); + s0i.construct(&dummy, ::boost::move(dummy2)); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + pair dummy2(2, 2); + dummy.~MarkTypePair(); + s0i.construct(&dummy, ::boost::move(dummy2)); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 2); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + //Check construction with 0/1 arguments for each pair and Boost tuple + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, boost::tuple<>(), boost::tuple(1)); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, boost::tuple(1), boost::tuple<>()); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, boost::tuple<>(), boost::tuple(2)); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + #if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) + //Check construction with 0/1 arguments for each pair and Boost tuple + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple(1)); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple(1), std::tuple<>()); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 1); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, piecewise_construct, std::tuple<>(), std::tuple(2)); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 0); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + #endif //BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE + + //Check construction with try_emplace_t 0/1 arguments for each pair + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, try_emplace_t(), 5, 1); + BOOST_TEST(dummy.first.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.second.construction_type == NotUsesAllocator); + BOOST_TEST(dummy.first.value == 5); + BOOST_TEST(dummy.second.value == 1); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, try_emplace_t(), 6); + BOOST_TEST(dummy.first.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.second.construction_type == ConstructibleSuffix); + BOOST_TEST(dummy.first.value == 6); + BOOST_TEST(dummy.second.value == 0); + dummy.~MarkTypePair(); + } + { + typedef ::allocator_argument_tester MarkType; + typedef pair MarkTypePair; + MarkTypePair dummy; + dummy.~MarkTypePair(); + s0i.construct(&dummy, try_emplace_t(), 7, 2); + BOOST_TEST(dummy.first.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.second.construction_type == ConstructiblePrefix); + BOOST_TEST(dummy.first.value == 7); + BOOST_TEST(dummy.second.value == 2); + dummy.~MarkTypePair(); + } + } + } + + return ::boost::report_errors(); +} +#include diff --git a/src/boost/libs/container/test/scoped_allocator_usage_test.cpp b/src/boost/libs/container/test/scoped_allocator_usage_test.cpp new file mode 100644 index 00000000..6eb14381 --- /dev/null +++ b/src/boost/libs/container/test/scoped_allocator_usage_test.cpp @@ -0,0 +1,428 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +template +class SimpleAllocator +{ +public: + typedef Ty value_type; + + explicit SimpleAllocator(int value) + : m_state(value) + {} + + template + SimpleAllocator(const SimpleAllocator &other) + : m_state(other.m_state) + {} + + Ty* allocate(std::size_t n) + { + return m_allocator.allocate(n); + } + + void deallocate(Ty* p, std::size_t n) + { + m_allocator.deallocate(p, n); + } + + int get_value() const + { return m_state; } + + private: + int m_state; + std::allocator m_allocator; + + template friend class SimpleAllocator; + + friend bool operator == (const SimpleAllocator &, const SimpleAllocator &) + { return true; } + + friend bool operator != (const SimpleAllocator &, const SimpleAllocator &) + { return false; } +}; + +class alloc_int +{ + private: // Not copyable + + BOOST_MOVABLE_BUT_NOT_COPYABLE(alloc_int) + + public: + typedef SimpleAllocator allocator_type; + + alloc_int(BOOST_RV_REF(alloc_int)other) + : m_value(other.m_value), m_allocator(boost::move(other.m_allocator)) + { + other.m_value = -1; + } + + alloc_int(BOOST_RV_REF(alloc_int)other, const allocator_type &allocator) + : m_value(other.m_value), m_allocator(allocator) + { + other.m_value = -1; + } + + alloc_int(int value, const allocator_type &allocator) + : m_value(value), m_allocator(allocator) + {} + + alloc_int & operator=(BOOST_RV_REF(alloc_int)other) + { + other.m_value = other.m_value; + return *this; + } + + int get_allocator_state() const + { return m_allocator.get_value(); } + + int get_value() const + { return m_value; } + + friend bool operator < (const alloc_int &l, const alloc_int &r) + { return l.m_value < r.m_value; } + + friend bool operator == (const alloc_int &l, const alloc_int &r) + { return l.m_value == r.m_value; } + + private: + int m_value; + allocator_type m_allocator; +}; + +using namespace ::boost::container; + +//general allocator +typedef scoped_allocator_adaptor > AllocIntAllocator; + +//[multi]map/set +typedef std::pair MapNode; +typedef scoped_allocator_adaptor > MapAllocator; +typedef map, MapAllocator> Map; +typedef set, AllocIntAllocator> Set; +typedef multimap, MapAllocator> MultiMap; +typedef multiset, AllocIntAllocator> MultiSet; + +//[multi]flat_map/set +typedef std::pair FlatMapNode; +typedef scoped_allocator_adaptor > FlatMapAllocator; +typedef flat_map, FlatMapAllocator> FlatMap; +typedef flat_set, AllocIntAllocator> FlatSet; +typedef flat_multimap, FlatMapAllocator> FlatMultiMap; +typedef flat_multiset, AllocIntAllocator> FlatMultiSet; + +//vector, deque, list, slist, stable_vector. +typedef vector Vector; +typedef deque Deque; +typedef list List; +typedef slist Slist; +typedef stable_vector StableVector; +typedef small_vector SmallVector; + +///////// +//is_unique_assoc +///////// + +template +struct is_unique_assoc +{ + static const bool value = false; +}; + +template +struct is_unique_assoc< map > +{ + static const bool value = true; +}; + +template +struct is_unique_assoc< flat_map > +{ + static const bool value = true; +}; + +template +struct is_unique_assoc< set > +{ + static const bool value = true; +}; + +template +struct is_unique_assoc< flat_set > +{ + static const bool value = true; +}; + + +///////// +//is_map +///////// + +template +struct is_map +{ + static const bool value = false; +}; + +template +struct is_map< map > +{ + static const bool value = true; +}; + +template +struct is_map< flat_map > +{ + static const bool value = true; +}; + +template +struct is_map< multimap > +{ + static const bool value = true; +}; + +template +struct is_map< flat_multimap > +{ + static const bool value = true; +}; + +template +struct is_set +{ + static const bool value = false; +}; + +template +struct is_set< set > +{ + static const bool value = true; +}; + +template +struct is_set< flat_set > +{ + static const bool value = true; +}; + +template +struct is_set< multiset > +{ + static const bool value = true; +}; + +template +struct is_set< flat_multiset > +{ + static const bool value = true; +}; + +///////// +//container_wrapper +///////// + +//Try to define-allocator_aware requirements +template< class Container + , bool Assoc = is_set::value || is_map::value + , bool UniqueAssoc = is_unique_assoc::value + , bool Map = is_map::value + > +struct container_wrapper_inserter +{ + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + template + static iterator emplace(Container &c, const_iterator p, const Arg &arg) + { return c.emplace(p, arg); } +}; + +template //map +struct container_wrapper_inserter +{ + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + template + static iterator emplace(Container &c, const_iterator, const Arg &arg) + { return c.emplace(arg, arg).first; } +}; + +template //set +struct container_wrapper_inserter +{ + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + template + static iterator emplace(Container &c, const_iterator, const Arg &arg) + { return c.emplace(arg).first; } +}; + +template //multimap +struct container_wrapper_inserter +{ + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + template + static iterator emplace(Container &c, const_iterator, const Arg &arg) + { return c.emplace(arg, arg); } +}; + +//multiset +template //multimap +struct container_wrapper_inserter +{ + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + template + static iterator emplace(Container &c, const_iterator, const Arg &arg) + { return c.emplace(arg); } +}; + +template< class Container> +struct container_wrapper + : public Container +{ + private: + BOOST_COPYABLE_AND_MOVABLE(container_wrapper) + + public: + typedef typename Container::allocator_type allocator_type; + typedef typename Container::const_iterator const_iterator; + typedef typename Container::iterator iterator; + + container_wrapper(const allocator_type &a) + : Container(a) + {} + + container_wrapper(BOOST_RV_REF(container_wrapper) o, const allocator_type &a) + : Container(BOOST_MOVE_BASE(Container, o), a) + {} + + container_wrapper(const container_wrapper &o, const allocator_type &a) + : Container(o, a) + {} + + template + iterator emplace(const_iterator p, const Arg &arg) + { return container_wrapper_inserter::emplace(*this, p, arg); } +}; + + +bool test_value_and_state_equals(const alloc_int &r, int value, int state) +{ return r.get_value() == value && r.get_allocator_state() == state; } + +template +bool test_value_and_state_equals(const dtl::pair &p, int value, int state) +{ return test_value_and_state_equals(p.first, value, state) && test_alloc_state_equals(p.second, value, state); } + +template +bool test_value_and_state_equals(const std::pair &p, int value, int state) +{ return test_value_and_state_equals(p.first, value, state) && test_value_and_state_equals(p.second, value, state); } + +template +bool one_level_allocator_propagation_test() +{ + typedef container_wrapper ContainerWrapper; + typedef typename ContainerWrapper::iterator iterator; + typedef typename ContainerWrapper::allocator_type allocator_type; + typedef typename ContainerWrapper::value_type value_type; + { + allocator_type al(SimpleAllocator(5)); + ContainerWrapper c(al); + + c.clear(); + iterator it = c.emplace(c.cbegin(), 42); + + if(!test_value_and_state_equals(*it, 42, 5)) + return false; + } + { + allocator_type al(SimpleAllocator(4)); + ContainerWrapper c2(al); + ContainerWrapper c(::boost::move(c2), allocator_type(SimpleAllocator(5))); + + c.clear(); + iterator it = c.emplace(c.cbegin(), 42); + + if(!test_value_and_state_equals(*it, 42, 5)) + return false; + }/* + { + ContainerWrapper c2(allocator_type(SimpleAllocator(3))); + ContainerWrapper c(c2, allocator_type(SimpleAllocator(5))); + + c.clear(); + iterator it = c.emplace(c.cbegin(), 42); + + if(!test_value_and_state_equals(*it, 42, 5)) + return false; + }*/ + return true; +} + +int main() +{ + //unique assoc + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + //multi assoc + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + //sequence containers + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + if(!one_level_allocator_propagation_test()) + return 1; + return 0; +} + +#include diff --git a/src/boost/libs/container/test/set_test.cpp b/src/boost/libs/container/test/set_test.cpp new file mode 100644 index 00000000..a7d0b474 --- /dev/null +++ b/src/boost/libs/container/test/set_test.cpp @@ -0,0 +1,655 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include "print_container.hpp" +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" +#include "set_test.hpp" +#include "propagate_allocator_test.hpp" +#include "emplace_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +//Test recursive structures +class recursive_set +{ +public: + recursive_set & operator=(const recursive_set &x) + { id_ = x.id_; set_ = x.set_; return *this; } + + int id_; + set set_; + set::iterator it_; + set::const_iterator cit_; + set::reverse_iterator rit_; + set::const_reverse_iterator crit_; + + friend bool operator< (const recursive_set &a, const recursive_set &b) + { return a.id_ < b.id_; } +}; + +//Test recursive structures +class recursive_multiset +{ + public: + recursive_multiset & operator=(const recursive_multiset &x) + { id_ = x.id_; multiset_ = x.multiset_; return *this; } + + int id_; + multiset multiset_; + multiset::iterator it_; + multiset::const_iterator cit_; + multiset::reverse_iterator rit_; + multiset::const_reverse_iterator crit_; + + friend bool operator< (const recursive_multiset &a, const recursive_multiset &b) + { return a.id_ < b.id_; } +}; + +template +void test_move() +{ + //Now test move semantics + C original; + original.emplace(); + C move_ctor(boost::move(original)); + C move_assign; + move_assign.emplace(); + move_assign = boost::move(move_ctor); + move_assign.swap(original); +} + +bool node_type_test() +{ + using namespace boost::container; + { + typedef set set_type; + set_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3); + src.emplace(boost::move(mv_1)); + src.emplace(boost::move(mv_2)); + src.emplace(boost::move(mv_3)); + } + if(src.size() != 3) + return false; + + set_type dst; + { + test::movable_int mv_3(3); + dst.emplace(boost::move(mv_3)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_33(33); + set_type::insert_return_type r; + + r = dst.insert(src.extract(mv_33)); // Key version, try to insert empty node + if(! (r.position == dst.end() && r.inserted == false && r.node.empty()) ) + return false; + r = dst.insert(src.extract(src.find(mv_1))); // Iterator version, successful + if(! (r.position == dst.find(mv_1) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(dst.begin(), src.extract(mv_2)); // Key type version, successful + if(! (r.position == dst.find(mv_2) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(src.extract(mv_3)); // Key type version, unsuccessful + + if(!src.empty()) + return false; + if(dst.size() != 3) + return false; + if(! (r.position == dst.find(mv_3) && r.inserted == false && r.node.value() == mv_3) ) + return false; + } + + { + typedef multiset multiset_type; + multiset_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_3bis(3); + src.emplace(boost::move(mv_1)); + src.emplace(boost::move(mv_2)); + src.emplace(boost::move(mv_3)); + src.emplace_hint(src.begin(), boost::move(mv_3bis)); + } + if(src.size() != 4) + return false; + + multiset_type dst; + { + test::movable_int mv_3(3); + dst.emplace(boost::move(mv_3)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_4(4); + multiset_type::iterator r; + + multiset_type::node_type nt(src.extract(mv_3)); + r = dst.insert(dst.begin(), boost::move(nt)); + if(! (*r == mv_3 && dst.find(mv_3) == r && nt.empty()) ) + return false; + + nt = src.extract(src.find(mv_1)); + r = dst.insert(boost::move(nt)); // Iterator version, successful + if(! (*r == mv_1 && nt.empty()) ) + return false; + + nt = src.extract(mv_2); + r = dst.insert(boost::move(nt)); // Key type version, successful + if(! (*r == mv_2 && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_3)); // Key type version, successful + if(! (*r == mv_3 && r == --multiset_type::iterator(dst.upper_bound(mv_3)) && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_4)); // Key type version, unsuccessful + if(! (r == dst.end()) ) + return false; + + if(!src.empty()) + return false; + if(dst.size() != 5) + return false; + } + return true; +} + +struct boost_container_set; +struct boost_container_multiset; + +namespace boost { +namespace container { +namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::set, Allocator> type; + }; +}; + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::multiset, Allocator> type; + }; +}; + +bool constructor_template_auto_deduction_test() +{ +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + using namespace boost::container; + const std::size_t NumElements = 100; + { + std::set int_set; + for (std::size_t i = 0; i != NumElements; ++i) { + int_set.insert(static_cast(i)); + } + std::multiset int_mset; + for (std::size_t i = 0; i != NumElements; ++i) { + int_mset.insert(static_cast(i)); + } + + typedef std::less comp_int_t; + typedef std::allocator alloc_int_t; + + //range + { + auto fset = set(int_set.begin(), int_set.end()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(int_mset.begin(), int_mset.end()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp + { + auto fset = set(int_set.begin(), int_set.end(), comp_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(int_mset.begin(), int_mset.end(), comp_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp+alloc + { + auto fset = set(int_set.begin(), int_set.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(int_mset.begin(), int_mset.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+alloc + { + auto fset = set(int_set.begin(), int_set.end(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(int_mset.begin(), int_mset.end(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + + //ordered_unique_range / ordered_range + + //range + { + auto fset = set(ordered_unique_range, int_set.begin(), int_set.end()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp + { + auto fset = set(ordered_unique_range, int_set.begin(), int_set.end(), comp_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end(), comp_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+comp+alloc + { + auto fset = set(ordered_unique_range, int_set.begin(), int_set.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end(), comp_int_t(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + //range+alloc + { + auto fset = set(ordered_unique_range, int_set.begin(), int_set.end(), alloc_int_t()); + if (!CheckEqualContainers(int_set, fset)) + return false; + auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end(), alloc_int_t()); + if (!CheckEqualContainers(int_mset, fmset)) + return false; + } + } +#endif + return true; +} + +}}} //boost::container::test + +template +struct GetAllocatorSet +{ + template + struct apply + { + typedef set < ValueType + , std::less + , typename allocator_traits + ::template portable_rebind_alloc::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type + > set_type; + + typedef multiset < ValueType + , std::less + , typename allocator_traits + ::template portable_rebind_alloc::type + , typename boost::container::tree_assoc_options + < boost::container::tree_type + >::type + > multiset_type; + }; +}; + +void test_merge_from_different_comparison() +{ + set set1; + set > set2; + set1.merge(set2); +} + +bool test_heterogeneous_lookups() +{ + typedef set set_t; + typedef multiset mset_t; + + set_t set1; + mset_t mset1; + + const set_t &cset1 = set1; + const mset_t &cmset1 = mset1; + + set1.insert(1); + set1.insert(1); + set1.insert(2); + set1.insert(2); + set1.insert(3); + + mset1.insert(1); + mset1.insert(1); + mset1.insert(2); + mset1.insert(2); + mset1.insert(3); + + const test::non_copymovable_int find_me(2); + + //find + if(*set1.find(find_me) != 2) + return false; + if(*cset1.find(find_me) != 2) + return false; + if(*mset1.find(find_me) != 2) + return false; + if(*cmset1.find(find_me) != 2) + return false; + + //count + if(set1.count(find_me) != 1) + return false; + if(cset1.count(find_me) != 1) + return false; + if(mset1.count(find_me) != 2) + return false; + if(cmset1.count(find_me) != 2) + return false; + + //contains + if(!set1.contains(find_me)) + return false; + if(!cset1.contains(find_me)) + return false; + if(!mset1.contains(find_me)) + return false; + if(!cmset1.contains(find_me)) + return false; + + //lower_bound + if(*set1.lower_bound(find_me) != 2) + return false; + if(*cset1.lower_bound(find_me) != 2) + return false; + if(*mset1.lower_bound(find_me) != 2) + return false; + if(*cmset1.lower_bound(find_me) != 2) + return false; + + //upper_bound + if(*set1.upper_bound(find_me) != 3) + return false; + if(*cset1.upper_bound(find_me) != 3) + return false; + if(*mset1.upper_bound(find_me) != 3) + return false; + if(*cmset1.upper_bound(find_me) != 3) + return false; + + //equal_range + if(*set1.equal_range(find_me).first != 2) + return false; + if(*cset1.equal_range(find_me).second != 3) + return false; + if(*mset1.equal_range(find_me).first != 2) + return false; + if(*cmset1.equal_range(find_me).second != 3) + return false; + + return true; +} + +int main () +{ + //Recursive container instantiation + { + set set_; + multiset multiset_; + } + //Allocator argument container + { + set set_((set::allocator_type())); + multiset multiset_((multiset::allocator_type())); + } + //Now test move semantics + { + test_move >(); + test_move >(); + } + //Test std::pair value type as tree has workarounds to make old std::pair + //implementations movable that can break things + { + boost::container::set > s; + std::pair p(0, 0); + s.insert(p); + s.emplace(p); + } + + if (!boost::container::test::instantiate_constructors, multiset >()) + return 1; + + test_merge_from_different_comparison(); + + //////////////////////////////////// + // Constructor Template Auto Deduction test + //////////////////////////////////// + if (!test::constructor_template_auto_deduction_test()) { + return 1; + } + + if(!test_heterogeneous_lookups()) + return 1; + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + { + typedef std::set MyStdSet; + typedef std::multiset MyStdMultiSet; + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetAllocatorSet, avl_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, avl_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, avl_tree>" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetAllocatorSet, scapegoat_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, scapegoat_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, scapegoat_tree>" << std::endl; + return 1; + } + + /////////// + + if (0 != test::set_test + < GetAllocatorSet, splay_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, splay_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, splay_tree>" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>" << std::endl; + return 1; + } + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC); + if(!boost::container::test::test_emplace, SetOptions>()) + return 1; + if(!boost::container::test::test_emplace, SetOptions>()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + if(!boost::container::test::test_propagate_allocator()) + return 1; + + if (!boost::container::test::test_set_methods_with_initializer_list_as_argument_for >()) + return 1; + + if (!boost::container::test::test_set_methods_with_initializer_list_as_argument_for >()) + return 1; + + //////////////////////////////////// + // Test optimize_size option + //////////////////////////////////// + // + // set + // + typedef set< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > rbset_size_optimized_no; + + typedef set< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > avlset_size_optimized_yes; + // + // multiset + // + typedef multiset< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > rbmset_size_optimized_yes; + + typedef multiset< int*, std::less, std::allocator + , tree_assoc_options< optimize_size, tree_type >::type > avlmset_size_optimized_no; + + BOOST_STATIC_ASSERT(sizeof(rbmset_size_optimized_yes) < sizeof(rbset_size_optimized_no)); + BOOST_STATIC_ASSERT(sizeof(avlset_size_optimized_yes) < sizeof(avlmset_size_optimized_no)); + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::set cont_int; + cont_int a; a.insert(0); a.insert(1); a.insert(2); + boost::intrusive::test::test_iterator_bidirectional< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + { + typedef boost::container::multiset cont_int; + cont_int a; a.insert(0); a.insert(1); a.insert(2); + boost::intrusive::test::test_iterator_bidirectional< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + + //////////////////////////////////// + // Node extraction/insertion testing functions + //////////////////////////////////// + if(!node_type_test()) + return 1; + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // set, default allocator + { + typedef boost::container::set cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(set, default allocator) test failed" << std::endl; + return 1; + } + } + // set, std::allocator + { + typedef boost::container::set, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(set, std::allocator) test failed" << std::endl; + return 1; + } + } + // multiset, default allocator + { + typedef boost::container::multiset cont; + typedef boost::container::dtl::tree, void, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multiset, default allocator) test failed" << std::endl; + return 1; + } + } + // multiset, std::allocator + { + typedef boost::container::multiset, std::allocator > cont; + typedef boost::container::dtl::tree, std::allocator, void> tree; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(multiset, std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} + +#include diff --git a/src/boost/libs/container/test/set_test.hpp b/src/boost/libs/container/test/set_test.hpp new file mode 100644 index 00000000..7bc3a093 --- /dev/null +++ b/src/boost/libs/container/test/set_test.hpp @@ -0,0 +1,942 @@ +//////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +//////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_SET_TEST_HEADER +#define BOOST_CONTAINER_TEST_SET_TEST_HEADER + +#include +#include "check_equal_containers.hpp" +#include "print_container.hpp" +#include "movable_int.hpp" +#include +#include +#include + +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME rebalance +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace test { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include + +namespace boost{ +namespace container { +namespace test{ + +template +void set_test_rebalanceable(C &, boost::container::dtl::false_type) +{} + +template +void set_test_rebalanceable(C &c, boost::container::dtl::true_type) +{ + c.rebalance(); +} + +template +int set_test_copyable(boost::container::dtl::false_type) +{ return 0; } + +const int MaxElem = 50; + +template +int set_test_copyable(boost::container::dtl::true_type) +{ + typedef typename MyBoostSet::value_type IntType; + + ::boost::movelib::unique_ptr const pboostset = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdset = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultiset = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdmultiset = ::boost::movelib::make_unique(); + + MyBoostSet &boostset = *pboostset; + MyStdSet &stdset = *pstdset; + MyBoostMultiSet &boostmultiset = *pboostmultiset; + MyStdMultiSet &stdmultiset = *pstdmultiset; + + //Just to test move aware catch conversions + boostset.insert(boostset.cbegin(), boostset.cend()); + boostmultiset.insert(boostmultiset.cbegin(), boostmultiset.cend()); + boostset.insert(boostset.begin(), boostset.end()); + boostmultiset.insert(boostmultiset.begin(), boostmultiset.end()); + + for(int i = 0; i < MaxElem; ++i){ + IntType move_me(i); + boostset.insert(boost::move(move_me)); + stdset.insert(i); + IntType move_me2(i); + boostmultiset.insert(boost::move(move_me2)); + stdmultiset.insert(i); + } + if(!CheckEqualContainers(boostset, stdset)) return 1; + if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1; + + { + //Now, test copy constructor + MyBoostSet boostsetcopy(boostset); + MyStdSet stdsetcopy(stdset); + + if(!CheckEqualContainers(boostsetcopy, stdsetcopy)) + return 1; + + MyBoostMultiSet boostmsetcopy(boostmultiset); + MyStdMultiSet stdmsetcopy(stdmultiset); + + if(!CheckEqualContainers(boostmsetcopy, stdmsetcopy)) + return 1; + + //And now assignment + boostsetcopy =boostset; + stdsetcopy = stdset; + + if(!CheckEqualContainers(boostsetcopy, stdsetcopy)) + return 1; + + boostmsetcopy = boostmultiset; + stdmsetcopy = stdmultiset; + + if(!CheckEqualContainers(boostmsetcopy, stdmsetcopy)) + return 1; + } + { + //Now, test copy constructor + MyBoostSet boostsetcopy(boostset, typename MyBoostSet::allocator_type()); + MyStdSet stdsetcopy(stdset); + + if(!CheckEqualContainers(boostsetcopy, stdsetcopy)) + return 1; + + MyBoostMultiSet boostmsetcopy(boostmultiset, typename MyBoostSet::allocator_type()); + MyStdMultiSet stdmsetcopy(stdmultiset); + + if(!CheckEqualContainers(boostmsetcopy, stdmsetcopy)) + return 1; + } + return 0; +} + + +template +int set_test () +{ + typedef typename MyBoostSet::value_type IntType; + + ::boost::movelib::unique_ptr const pboostset = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdset = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultiset = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pstdmultiset = ::boost::movelib::make_unique(); + + MyBoostSet &boostset = *pboostset; + MyStdSet &stdset = *pstdset; + MyBoostMultiSet &boostmultiset = *pboostmultiset; + MyStdMultiSet &stdmultiset = *pstdmultiset; + + //Test construction from a range + { //Set(beg, end, compare) + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i/2; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); + } + ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::key_compare()); + ::boost::movelib::unique_ptr const pstdset2 = ::boost::movelib::make_unique(&aux_vect2[0], &aux_vect2[0]+50); + if(!test::CheckEqualContainers(*pboostset2, *pstdset2)) return 1; + ::boost::movelib::unique_ptr const pboostmultiset2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0]+50), typename MyBoostMultiSet::key_compare()); + ::boost::movelib::unique_ptr const pstdmultiset2 = ::boost::movelib::make_unique(&aux_vect2[0], &aux_vect2[0]+50); + if(!test::CheckEqualContainers(*pboostmultiset2, *pstdmultiset2)) return 1; + } + { //Set(beg, end, alloc) + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i/2; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); + } + ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0]+50), typename MyBoostSet::allocator_type()); + ::boost::movelib::unique_ptr const pstdset2 = ::boost::movelib::make_unique(&aux_vect2[0], &aux_vect2[0]+50); + if(!test::CheckEqualContainers(*pboostset2, *pstdset2)) return 1; + ::boost::movelib::unique_ptr const pboostmultiset2 = ::boost::movelib::make_unique + (boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0]+50), typename MyBoostMultiSet::allocator_type()); + ::boost::movelib::unique_ptr const pstdmultiset2 = ::boost::movelib::make_unique(&aux_vect2[0], &aux_vect2[0]+50); + if(!test::CheckEqualContainers(*pboostmultiset2, *pstdmultiset2)) return 1; + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i/2; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(i/2); + aux_vect3[i] = boost::move(move_me); + } + + ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(aux_vect + 50)); + ::boost::movelib::unique_ptr const pstdset2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + 50); + ::boost::movelib::unique_ptr const pboostmultiset2 = ::boost::movelib::make_unique + ( boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(aux_vect3 + 50)); + ::boost::movelib::unique_ptr const pstdmultiset2 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + 50); + + MyBoostSet &boostset2 = *pboostset2; + MyStdSet &stdset2 = *pstdset2; + MyBoostMultiSet &boostmultiset2 = *pboostmultiset2; + MyStdMultiSet &stdmultiset2 = *pstdmultiset2; + + if(!CheckEqualContainers(boostset2, stdset2)){ + std::cout << "Error in construct(MyBoostSet2)" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset2, stdmultiset2)){ + std::cout << "Error in construct(MyBoostMultiSet2)" << std::endl; + return 1; + } + + //ordered range insertion + for(int i = 0; i < 50; ++i){ + IntType move_me(i); + aux_vect[i] = boost::move(move_me); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i; + } + + for(int i = 0; i < 50; ++i){ + IntType move_me(i); + aux_vect3[i] = boost::move(move_me); + } + + //some comparison operators + if(!(boostset2 == boostset2)) + return 1; + if(boostset2 != boostset2) + return 1; + if(boostset2 < boostset2) + return 1; + if(boostset2 > boostset2) + return 1; + if(!(boostset2 <= boostset2)) + return 1; + if(!(boostset2 >= boostset2)) + return 1; + + ::boost::movelib::unique_ptr const pboostset3 = ::boost::movelib::make_unique + ( ordered_unique_range + , boost::make_move_iterator(&aux_vect[0]) + , boost::make_move_iterator(&aux_vect[0] + 50)); + ::boost::movelib::unique_ptr const pstdset3 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + 50); + ::boost::movelib::unique_ptr const pboostmultiset3 = ::boost::movelib::make_unique + ( ordered_range + , boost::make_move_iterator(&aux_vect3[0]) + , boost::make_move_iterator(aux_vect3 + 50)); + ::boost::movelib::unique_ptr const pstdmultiset3 = ::boost::movelib::make_unique + (&aux_vect2[0], &aux_vect2[0] + 50); + + MyBoostSet &boostset3 = *pboostset3; + MyStdSet &stdset3 = *pstdset3; + MyBoostMultiSet &boostmultiset3 = *pboostmultiset3; + MyStdMultiSet &stdmultiset3 = *pstdmultiset3; + + if(!CheckEqualContainers(boostset3, stdset3)){ + std::cout << "Error in construct(MyBoostSet3)" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset3, stdmultiset3)){ + std::cout << "Error in construct(MyBoostMultiSet3)" << std::endl; + return 1; + } + } + + for(int i = 0; i < MaxElem; ++i){ + IntType move_me(i); + boostset.insert(boost::move(move_me)); + stdset.insert(i); + boostset.insert(IntType(i)); + stdset.insert(i); + IntType move_me2(i); + boostmultiset.insert(boost::move(move_me2)); + stdmultiset.insert(i); + boostmultiset.insert(IntType(i)); + stdmultiset.insert(i); + } + + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boost::move(move_me)" << std::endl; + return 1; + } + + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boost::move(move_me)" << std::endl; + return 1; + } + + typename MyBoostSet::iterator it = boostset.begin(); + typename MyBoostSet::const_iterator cit = it; + (void)cit; + + boostset.erase(boostset.begin()); + stdset.erase(stdset.begin()); + boostmultiset.erase(boostmultiset.begin()); + stdmultiset.erase(stdmultiset.begin()); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.erase(boostset.begin())" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.erase(boostmultiset.begin())" << std::endl; + return 1; + } + + boostset.erase(boostset.begin()); + stdset.erase(stdset.begin()); + boostmultiset.erase(boostmultiset.begin()); + stdmultiset.erase(stdmultiset.begin()); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.erase(boostset.begin())" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.erase(boostmultiset.begin())" << std::endl; + return 1; + } + + //Swapping test + MyBoostSet tmpboosteset2; + MyStdSet tmpstdset2; + MyBoostMultiSet tmpboostemultiset2; + MyStdMultiSet tmpstdmultiset2; + boostset.swap(tmpboosteset2); + stdset.swap(tmpstdset2); + boostmultiset.swap(tmpboostemultiset2); + stdmultiset.swap(tmpstdmultiset2); + boostset.swap(tmpboosteset2); + stdset.swap(tmpstdset2); + boostmultiset.swap(tmpboostemultiset2); + stdmultiset.swap(tmpstdmultiset2); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.swap(tmpboosteset2)" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.swap(tmpboostemultiset2)" << std::endl; + return 1; + } + + //Insertion from other container + //Initialize values + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect3[i] = boost::move(move_me); + } + + boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); + stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect3[0])..." << std::endl; + return 1; + } + boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(aux_vect3 + 50)); + stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boost::make_move_iterator(&aux_vect3[0]), ..." << std::endl; + return 1; + } + + for(int i = 0, j = static_cast(boostset.size()); i < j; ++i){ + IntType erase_me(i); + boostset.erase(erase_me); + stdset.erase(i); + boostmultiset.erase(erase_me); + stdmultiset.erase(i); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.erase(erase_me)" << boostset.size() << " " << stdset.size() << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.erase(erase_me)" << std::endl; + return 1; + } + } + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect[i] = boost::move(move_me); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + IntType aux_vect3[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect3[i] = boost::move(move_me); + } + + IntType aux_vect4[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect4[i] = boost::move(move_me); + } + + IntType aux_vect5[50]; + for(int i = 0; i < 50; ++i){ + IntType move_me(-1); + aux_vect5[i] = boost::move(move_me); + } + + boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); + boostset.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50)); + stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + stdset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boost::make_move_iterator(&aux_vect3[0])..." << std::endl; + return 1; + } + boostmultiset.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(&aux_vect4[0] + 50)); + boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(&aux_vect5[0] + 50)); + stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + stdmultiset.insert(&aux_vect2[0], &aux_vect2[0] + 50); + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boost::make_move_iterator(&aux_vect5[0])..." << std::endl; + return 1; + } + + boostset.erase(*boostset.begin()); + stdset.erase(*stdset.begin()); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.erase(*boostset.begin())" << std::endl; + return 1; + } + boostmultiset.erase(*boostmultiset.begin()); + stdmultiset.erase(*stdmultiset.begin()); + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.erase(*boostmultiset.begin())" << std::endl; + return 1; + } + } + + for(int i = 0; i < MaxElem; ++i){ + IntType move_me(i); + boostset.insert(boost::move(move_me)); + stdset.insert(i); + IntType move_me2(i); + boostmultiset.insert(boost::move(move_me2)); + stdmultiset.insert(i); + } + + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boost::move(move_me)) try 2" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boost::move(move_me2)) try 2" << std::endl; + return 1; + } + + for(int i = 0; i < MaxElem; ++i){ + { + IntType move_me(i); + boostset.insert(boostset.begin(), boost::move(move_me)); + stdset.insert(stdset.begin(), i); + //PrintContainers(boostset, stdset); + IntType move_me2(i); + boostmultiset.insert(boostmultiset.begin(), boost::move(move_me2)); + stdmultiset.insert(stdmultiset.begin(), i); + //PrintContainers(boostmultiset, stdmultiset); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boostset.begin(), boost::move(move_me))" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boostmultiset.begin(), boost::move(move_me2))" << std::endl; + return 1; + } + + IntType move_me3(i); + boostset.insert(boostset.end(), boost::move(move_me3)); + stdset.insert(stdset.end(), i); + IntType move_me4(i); + boostmultiset.insert(boostmultiset.end(), boost::move(move_me4)); + stdmultiset.insert(stdmultiset.end(), i); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boostset.end(), boost::move(move_me3))" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boostmultiset.end(), boost::move(move_me4))" << std::endl; + return 1; + } + } + { + IntType move_me(i); + boostset.insert(boostset.upper_bound(move_me), boost::move(move_me)); + stdset.insert(stdset.upper_bound(i), i); + //PrintContainers(boostset, stdset); + IntType move_me2(i); + boostmultiset.insert(boostmultiset.upper_bound(move_me2), boost::move(move_me2)); + stdmultiset.insert(stdmultiset.upper_bound(i), i); + //PrintContainers(boostmultiset, stdmultiset); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boostset.upper_bound(move_me), boost::move(move_me))" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boostmultiset.upper_bound(move_me2), boost::move(move_me2))" << std::endl; + return 1; + } + + } + { + IntType move_me(i); + IntType move_me2(i); + boostset.insert(boostset.lower_bound(move_me), boost::move(move_me2)); + stdset.insert(stdset.lower_bound(i), i); + //PrintContainers(boostset, stdset); + move_me2 = i; + boostmultiset.insert(boostmultiset.lower_bound(move_me2), boost::move(move_me2)); + stdmultiset.insert(stdmultiset.lower_bound(i), i); + //PrintContainers(boostmultiset, stdmultiset); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.insert(boostset.lower_bound(move_me), boost::move(move_me2))" << std::endl; + return 1; + } + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.insert(boostmultiset.lower_bound(move_me2), boost::move(move_me2))" << std::endl; + return 1; + } + set_test_rebalanceable(boostset + , dtl::bool_::value>()); + if(!CheckEqualContainers(boostset, stdset)){ + std::cout << "Error in boostset.rebalance()" << std::endl; + return 1; + } + set_test_rebalanceable(boostmultiset + , dtl::bool_::value>()); + if(!CheckEqualContainers(boostmultiset, stdmultiset)){ + std::cout << "Error in boostmultiset.rebalance()" << std::endl; + return 1; + } + } + } + + //Compare count with std containers + for(int i = 0; i < MaxElem; ++i){ + IntType k(i); + if(boostset.count(k) != stdset.count(i)){ + return -1; + } + + if(boostset.contains(k) != (stdset.find(i) != stdset.end())){ + return -1; + } + + if(boostmultiset.count(k) != stdmultiset.count(i)){ + return -1; + } + + if(boostmultiset.contains(k) != (stdmultiset.find(i) != stdmultiset.end())){ + return -1; + } + } + + //Compare find/lower_bound/upper_bound in set + { + typename MyBoostSet::iterator bs_b = boostset.begin(); + typename MyBoostSet::iterator bs_e = boostset.end(); + typename MyStdSet::iterator ss_b = stdset.begin(); + + std::size_t i = 0; + while(bs_b != bs_e){ + ++i; + typename MyBoostSet::iterator bs_i; + typename MyStdSet::iterator ss_i; + //find + bs_i = boostset.find(*bs_b); + ss_i = stdset.find(*ss_b); + if(!CheckEqualIt(bs_i, ss_i, boostset, stdset)){ + return -1; + } + //lower bound + bs_i = boostset.lower_bound(*bs_b); + ss_i = stdset.lower_bound(*ss_b); + if(!CheckEqualIt(bs_i, ss_i, boostset, stdset)){ + return -1; + } + //upper bound + bs_i = boostset.upper_bound(*bs_b); + ss_i = stdset.upper_bound(*ss_b); + if(!CheckEqualIt(bs_i, ss_i, boostset, stdset)){ + return -1; + } + //equal range + std::pair bs_ip; + std::pair ss_ip; + bs_ip = boostset.equal_range(*bs_b); + ss_ip = stdset.equal_range(*ss_b); + if(!CheckEqualIt(bs_ip.first, ss_ip.first, boostset, stdset)){ + return -1; + } + if(!CheckEqualIt(bs_ip.second, ss_ip.second, boostset, stdset)){ + return -1; + } + ++bs_b; + ++ss_b; + } + } + //Compare find/lower_bound/upper_bound in multiset + { + typename MyBoostMultiSet::iterator bm_b = boostmultiset.begin(); + typename MyBoostMultiSet::iterator bm_e = boostmultiset.end(); + typename MyStdMultiSet::iterator sm_b = stdmultiset.begin(); + + while(bm_b != bm_e){ + typename MyBoostMultiSet::iterator bm_i; + typename MyStdMultiSet::iterator sm_i; + //find + bm_i = boostmultiset.find(*bm_b); + sm_i = stdmultiset.find(*sm_b); + if(!CheckEqualIt(bm_i, sm_i, boostmultiset, stdmultiset)){ + return -1; + } + //lower bound + bm_i = boostmultiset.lower_bound(*bm_b); + sm_i = stdmultiset.lower_bound(*sm_b); + if(!CheckEqualIt(bm_i, sm_i, boostmultiset, stdmultiset)){ + return -1; + } + //upper bound + bm_i = boostmultiset.upper_bound(*bm_b); + sm_i = stdmultiset.upper_bound(*sm_b); + if(!CheckEqualIt(bm_i, sm_i, boostmultiset, stdmultiset)){ + return -1; + } + //equal range + std::pair bm_ip; + std::pair sm_ip; + bm_ip = boostmultiset.equal_range(*bm_b); + sm_ip = stdmultiset.equal_range(*sm_b); + if(!CheckEqualIt(bm_ip.first, sm_ip.first, boostmultiset, stdmultiset)){ + return -1; + } + if(!CheckEqualIt(bm_ip.second, sm_ip.second, boostmultiset, stdmultiset)){ + return -1; + } + ++bm_b; + ++sm_b; + } + } + + //Now do count exercise + boostset.erase(boostset.begin(), boostset.end()); + boostmultiset.erase(boostmultiset.begin(), boostmultiset.end()); + boostset.clear(); + boostmultiset.clear(); + + for(int j = 0; j < 3; ++j) + for(int i = 0; i < 100; ++i){ + IntType move_me(i); + boostset.insert(boost::move(move_me)); + IntType move_me2(i); + boostmultiset.insert(boost::move(move_me2)); + IntType count_me(i); + if(boostset.count(count_me) != typename MyBoostMultiSet::size_type(1)){ + std::cout << "Error in boostset.count(count_me)" << std::endl; + return 1; + } + if(boostmultiset.count(count_me) != typename MyBoostMultiSet::size_type(j+1)){ + std::cout << "Error in boostmultiset.count(count_me)" << std::endl; + return 1; + } + } + + { //merge + ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultiset2 = ::boost::movelib::make_unique(); + + MyBoostSet &boostset2 = *pboostset2; + MyBoostMultiSet &boostmultiset2 = *pboostmultiset2; + + boostset.clear(); + boostset2.clear(); + boostmultiset.clear(); + boostmultiset2.clear(); + stdset.clear(); + stdmultiset.clear(); + + { + IntType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect[i] = i; + } + + IntType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect2[i] = MaxElem/2+i; + } + IntType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect3[i] = MaxElem*2/2+i; + } + boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostset2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostmultiset2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdset.insert(i); + } + for(int i = 0; i < MaxElem; ++i){ + stdset.insert(MaxElem/2+i); + } + + boostset.merge(boost::move(boostset2)); + if(!CheckEqualContainers(boostset, stdset)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdset.insert(MaxElem*2/2+i); + } + + boostset.merge(boost::move(boostmultiset2)); + if(!CheckEqualContainers(boostset, stdset)) return 1; + + boostset.clear(); + boostset2.clear(); + boostmultiset.clear(); + boostmultiset2.clear(); + stdset.clear(); + stdmultiset.clear(); + { + IntType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect[i] = i; + } + + IntType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect2[i] = MaxElem/2+i; + } + IntType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect3[i] = MaxElem*2/2+i; + } + boostmultiset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmultiset2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostset2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultiset.insert(i); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultiset.insert(MaxElem/2+i); + } + boostmultiset.merge(boost::move(boostmultiset2)); + if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdmultiset.insert(MaxElem*2/2+i); + } + + boostmultiset.merge(boost::move(boostset2)); + if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1; + } + + if(set_test_copyable + (dtl::bool_::value>())){ + return 1; + } + + return 0; +} + +template +bool test_set_methods_with_initializer_list_as_argument_for() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::initializer_list il = { 1, 2, 3, 4, 5, 5 }; + std::initializer_list ilu = { 1, 2, 3, 4, 5 }; + SetType expected(il.begin(), il.end()); + SetType expectedu(ilu.begin(), ilu.end()); + { + SetType sil((il)); + if (sil != expected) + return false; + + SetType sila(il, typename SetType::allocator_type()); + if (sila != expected) + return false; + + SetType silca(il, typename SetType::key_compare(), typename SetType::allocator_type()); + if (silca != expected) + return false; + + SetType sil_ordered(ordered_unique_range, ilu); + if (sil_ordered != expectedu) + return false; + + SetType sil_assign = { 99, 100, 101, 102, 103, 104, 105 }; + sil_assign = il; + if (sil_assign != expected) + return false; + } + { + SetType sil; + sil.insert(il); + if (sil != expected) + return false; + } + return true; +#endif + return true; +} + +template +bool instantiate_constructors() +{ + { + typedef typename SetType::value_type value_type; + typename SetType::key_compare comp; + typename SetType::allocator_type a; + value_type value; + { + SetType s0; + SetType s1(comp); + SetType s2(a); + SetType s3(comp, a); + } + { + SetType s0(&value, &value); + SetType s1(&value, &value ,comp); + SetType s2(&value, &value ,a); + SetType s3(&value, &value ,comp, a); + } + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + { + SetType s0({ 0 }); + SetType s1({ 0 },comp); + SetType s2({ 0 },a); + SetType s3({ 0 },comp, a); + } + { + std::initializer_list il{0}; + SetType s0(ordered_unique_range, il); + SetType s1(ordered_unique_range, il,comp); + SetType s3(ordered_unique_range, il,comp, a); + } + #endif + { + SetType s0(ordered_unique_range, &value, &value); + SetType s1(ordered_unique_range, &value, &value ,comp); + SetType s2(ordered_unique_range, &value, &value ,comp, a); + } + } + + { + typedef typename MultisetType::value_type value_type; + typename MultisetType::key_compare comp; + typename MultisetType::allocator_type a; + value_type value; + { + MultisetType s0; + MultisetType s1(comp); + MultisetType s2(a); + MultisetType s3(comp, a); + } + { + MultisetType s0(&value, &value); + MultisetType s1(&value, &value ,comp); + MultisetType s2(&value, &value ,a); + MultisetType s3(&value, &value ,comp, a); + } + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + { + MultisetType s0({ 0 }); + MultisetType s1({ 0 },comp); + MultisetType s2({ 0 },a); + MultisetType s3({ 0 },comp, a); + } + { + std::initializer_listil{0}; + MultisetType s0(ordered_range, il); + MultisetType s1(ordered_range, il,comp); + MultisetType s3(ordered_range, il,comp, a); + } + #endif + { + MultisetType s0(ordered_range, &value, &value); + MultisetType s1(ordered_range, &value, &value ,comp); + MultisetType s2(ordered_range, &value, &value ,comp, a); + } + } + return true; +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif diff --git a/src/boost/libs/container/test/slist_test.cpp b/src/boost/libs/container/test/slist_test.cpp new file mode 100644 index 00000000..08943448 --- /dev/null +++ b/src/boost/libs/container/test/slist_test.cpp @@ -0,0 +1,290 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include +#include "dummy_test_allocator.hpp" +#include "movable_int.hpp" +#include "list_test.hpp" +#include "propagate_allocator_test.hpp" +#include "emplace_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +class recursive_slist +{ +public: + int id_; + slist slist_; + slist::iterator it_; + slist::const_iterator cit_; + + recursive_slist &operator=(const recursive_slist &o) + { slist_ = o.slist_; return *this; } +}; + +void recursive_slist_test()//Test for recursive types +{ + slist recursive_list_list; +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef slist< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +bool test_support_for_initializer_list() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + const std::initializer_list il = {5, 10, 15}; + const slist expected_list(il.begin(), il.end()); + { + slist sl = il; + if(sl != expected_list) + return false; + } + + { + slist sl = {1, 2}; + sl = il; + if(sl != expected_list) + return false; + } + { + slist sl({ 1, 2 }, slist::allocator_type()); + sl = il; + if (sl != expected_list) + return false; + } + { + slist sl = {4, 5}; + sl.assign(il); + if(sl != expected_list) + return false; + } + + { + slist sl = {15}; + sl.insert(sl.cbegin(), {5, 10}); + if(sl != expected_list) + return false; + } + + { + slist sl = {5}; + sl.insert_after(sl.cbegin(), {10, 15}); + if(sl != expected_list) + return false; + } + return true; +#endif + return true; +} + +bool test_for_splice() +{ + { + slist list1; list1.push_front(3); list1.push_front(2); list1.push_front(1); list1.push_front(0); + slist list2; + slist expected1; expected1.push_front(3); expected1.push_front(2); expected1.push_front(0); + slist expected2; expected2.push_front(1); + + list2.splice(list2.begin(), list1, ++list1.begin()); + + if (!(expected1 == list1 && expected2 == list2)) + return false; + } + { + slist list1; list1.push_front(3); list1.push_front(2); list1.push_front(1); list1.push_front(0); + slist list2; + slist expected1; + slist expected2; expected2.push_front(3); expected2.push_front(2); expected2.push_front(1); expected2.push_front(0); + + list2.splice(list2.begin(), list1, list1.begin(), list1.end()); + + if (!(expected1 == list1 && expected2 == list2)) + return false; + } + return true; +} + +struct boost_container_slist; + +namespace boost { +namespace container { +namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::slist type; + }; +}; + +}}} + +int main () +{ + recursive_slist_test(); + { + //Now test move semantics + slist original; + slist move_ctor(boost::move(original)); + slist move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + { + slist recursive, copy; + //Test to test both move emulations + if(!copy.size()){ + copy = recursive; + } + } + } + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + if (test::list_test >, false>()) + return 1; + if (test::list_test, false>()) + return 1; + if (test::list_test >, false>()) + return 1; + if (test::list_test, false>()) + return 1; + if (test::list_test, false>()) + return 1; + if (test::list_test, false>()) + return 1; + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions Options = (test::EmplaceOptions) + (test::EMPLACE_FRONT | test::EMPLACE_AFTER | test::EMPLACE_BEFORE | test::EMPLACE_AFTER); + + if(!boost::container::test::test_emplace + < slist, Options>()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Initializer lists + //////////////////////////////////// + if(!test_support_for_initializer_list()) + return 1; + + //////////////////////////////////// + // Splice testing + //////////////////////////////////// + if(!test_for_splice()) + return 1; + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::slist vector_int; + vector_int a; a.push_front(2); a.push_front(1); a.push_front(0); + boost::intrusive::test::test_iterator_forward< boost::container::slist >(a); + if(boost::report_errors() != 0) { + return 1; + } + } +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //////////////////////////////////// + // Constructor Template Auto Deduction Tests + //////////////////////////////////// + { + auto gold = std::list{ 1, 2, 3 }; + auto test = boost::container::slist(gold.begin(), gold.end()); + if (test.size() != 3) { + return 1; + } + if (test.front() != 1) + return 1; + test.pop_front(); + if (test.front() != 2) + return 1; + test.pop_front(); + if (test.front() != 3) + return 1; + test.pop_front(); + } + { + auto gold = std::list{ 1, 2, 3 }; + auto test = boost::container::slist(gold.begin(), gold.end(), new_allocator()); + if (test.size() != 3) { + return 1; + } + if (test.front() != 1) + return 1; + test.pop_front(); + if (test.front() != 2) + return 1; + test.pop_front(); + if (test.front() != 3) + return 1; + test.pop_front(); + } +#endif + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::slist cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::slist > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} + +#include + diff --git a/src/boost/libs/container/test/small_vector_options_test.cpp b/src/boost/libs/container/test/small_vector_options_test.cpp new file mode 100644 index 00000000..73e48553 --- /dev/null +++ b/src/boost/libs/container/test/small_vector_options_test.cpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +using namespace boost::container; + +const std::size_t Capacity = 10u; + +void test_alignment() +{ + { //extended alignment + const std::size_t extended_alignment = sizeof(int)*4u; + BOOST_STATIC_ASSERT(extended_alignment > dtl::alignment_of::value); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< inplace_alignment >; + #else + typedef small_vector_options + < inplace_alignment >::type options_t; + #endif + + small_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % extended_alignment) == 0); + } + { //default alignment + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< inplace_alignment<0> >; + #else + typedef small_vector_options< inplace_alignment<0> >::type options_t; + #endif + + small_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % dtl::alignment_of::value) == 0); + } +} + +void test_growth_factor_50() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< growth_factor >; + #else + typedef small_vector_options + < growth_factor >::type options_t; + #endif + + small_vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + old_capacity/2); +} + +void test_growth_factor_60() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< growth_factor >; + #else + typedef small_vector_options + < growth_factor >::type options_t; + #endif + + small_vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + 3*old_capacity/5); +} + +void test_growth_factor_100() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = small_vector_options_t< growth_factor >; + #else + typedef small_vector_options + < growth_factor >::type options_t; + #endif + + small_vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == 2*old_capacity); +} + +int main() +{ + test_alignment(); + test_growth_factor_50(); + test_growth_factor_60(); + test_growth_factor_100(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/small_vector_test.cpp b/src/boost/libs/container/test/small_vector_test.cpp new file mode 100644 index 00000000..315d64dd --- /dev/null +++ b/src/boost/libs/container/test/small_vector_test.cpp @@ -0,0 +1,236 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include "vector_test.hpp" +#include "movable_int.hpp" +#include "propagate_allocator_test.hpp" +#include "default_init_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +#include + +#include + +struct boost_container_small_vector; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::small_vector type; + }; +}; + +}}} //namespace boost::container::test + +bool test_small_vector_base_test() +{ + typedef boost::container::small_vector_base smb_t; + { + typedef boost::container::small_vector sm5_t; + BOOST_STATIC_ASSERT(sm5_t::static_capacity == 5); + sm5_t sm5; + smb_t &smb = sm5; + smb.push_back(1); + sm5_t sm5_copy(sm5); + sm5_copy.push_back(1); + if (!boost::container::test::CheckEqualContainers(sm5, smb)) + return false; + } + { + typedef boost::container::small_vector sm7_t; + BOOST_STATIC_ASSERT(sm7_t::static_capacity == 7); + sm7_t sm7; + smb_t &smb = sm7; + smb.push_back(2); + sm7_t sm7_copy(sm7); + sm7_copy.push_back(2); + if (!boost::container::test::CheckEqualContainers(sm7, smb)) + return false; + } + { + typedef boost::container::small_vector sm5_t; + sm5_t sm5; + smb_t &smb = sm5; + smb.push_back(1); + sm5_t sm5_copy(smb); + if (!boost::container::test::CheckEqualContainers(sm5, sm5_copy)) + return false; + smb.push_back(2); + if(smb.size() != 2){ + return false; + } + sm5_copy = smb; + if (!boost::container::test::CheckEqualContainers(sm5, sm5_copy)) + return false; + sm5_t sm5_move(boost::move(smb)); + smb.clear(); + if (!boost::container::test::CheckEqualContainers(sm5_move, sm5_copy)) + return false; + smb = sm5_copy; + sm5_move = boost::move(smb); + smb.clear(); + if (!boost::container::test::CheckEqualContainers(sm5_move, sm5_copy)) + return false; + } + + return true; +} + +//small vector has internal storage so some special swap cases must be tested +bool test_swap() +{ + typedef boost::container::small_vector vec; + { //v bigger than static capacity, w empty + vec v; + for(std::size_t i = 0, max = v.capacity()+1; i != max; ++i){ + v.push_back(int(i)); + } + vec w; + const std::size_t v_size = v.size(); + const std::size_t w_size = w.size(); + v.swap(w); + if(v.size() != w_size || w.size() != v_size) + return false; + } + { //v smaller than static capacity, w empty + vec v; + for(std::size_t i = 0, max = v.capacity()-1; i != max; ++i){ + v.push_back(int(i)); + } + vec w; + const std::size_t v_size = v.size(); + const std::size_t w_size = w.size(); + v.swap(w); + if(v.size() != w_size || w.size() != v_size) + return false; + } + { //v & w smaller than static capacity + vec v; + for(std::size_t i = 0, max = v.capacity()-1; i != max; ++i){ + v.push_back(int(i)); + } + vec w; + for(std::size_t i = 0, max = v.capacity()/2; i != max; ++i){ + w.push_back(int(i)); + } + const std::size_t v_size = v.size(); + const std::size_t w_size = w.size(); + v.swap(w); + if(v.size() != w_size || w.size() != v_size) + return false; + } + { //v & w bigger than static capacity + vec v; + for(std::size_t i = 0, max = v.capacity()+1; i != max; ++i){ + v.push_back(int(i)); + } + vec w; + for(std::size_t i = 0, max = v.capacity()*2; i != max; ++i){ + w.push_back(int(i)); + } + const std::size_t v_size = v.size(); + const std::size_t w_size = w.size(); + v.swap(w); + if(v.size() != w_size || w.size() != v_size) + return false; + } + return true; +} + +int main() +{ + using namespace boost::container; + + if(!test_swap()) + return 1; + + if(test::vector_test< small_vector >()) + return 1; + + if(test::vector_test< small_vector >()) + return 1; + + //////////////////////////////////// + // Default init test + //////////////////////////////////// + if(!test::default_init_test< small_vector > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::container::test::test_emplace< small_vector, Options>()){ + return 1; + } + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()){ + return 1; + } + + //////////////////////////////////// + // Initializer lists testing + //////////////////////////////////// + if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for + < boost::container::small_vector >()) { + return 1; + } + + //////////////////////////////////// + // Small vector base + //////////////////////////////////// + if (!test_small_vector_base_test()){ + return 1; + } + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::small_vector cont_int; + cont_int a; a.push_back(0); a.push_back(1); a.push_back(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::small_vector cont; + if (boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::small_vector > cont; + if (boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/boost/libs/container/test/stable_vector_test.cpp b/src/boost/libs/container/test/stable_vector_test.cpp new file mode 100644 index 00000000..e0fb5867 --- /dev/null +++ b/src/boost/libs/container/test/stable_vector_test.cpp @@ -0,0 +1,227 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING +#include +#include + +#include +#include + +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "dummy_test_allocator.hpp" +#include "propagate_allocator_test.hpp" +#include "vector_test.hpp" +#include "default_init_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +class recursive_vector +{ + public: + int id_; + stable_vector vector_; + stable_vector::iterator it_; + stable_vector::const_iterator cit_; + stable_vector::reverse_iterator rit_; + stable_vector::const_reverse_iterator crit_; + + recursive_vector &operator=(const recursive_vector &o) + { vector_ = o.vector_; return *this; } +}; + +void recursive_vector_test()//Test for recursive types +{ + stable_vector recursive, copy; + //Test to test both move emulations + if(!copy.size()){ + copy = recursive; + } +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef stable_vector< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + + return 0; +} + +struct boost_container_stable_vector; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::stable_vector type; + }; +}; + +}}} //namespace boost::container::test + + +int main() +{ + recursive_vector_test(); + { + //Now test move semantics + stable_vector original; + stable_vector move_ctor(boost::move(original)); + stable_vector move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + + //Test non-copy-move operations + { + stable_vector sv; + sv.emplace_back(); + sv.resize(10); + sv.resize(1); + } + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + // std:allocator + if(test_cont_variants< std::allocator >()){ + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + return 1; + } + // boost::container::node_allocator + if(test_cont_variants< node_allocator >()){ + std::cerr << "test_cont_variants< node_allocator > failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Default init test + //////////////////////////////////// + if(!test::default_init_test< stable_vector > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::container::test::test_emplace + < stable_vector, Options>()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Initializer lists testing + //////////////////////////////////// + if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for + < boost::container::stable_vector >()) + { + std::cerr << "test_methods_with_initializer_list_as_argument failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::stable_vector cont_int; + cont_int a; a.push_back(0); a.push_back(1); a.push_back(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //////////////////////////////////// + // Constructor Template Auto Deduction testing + //////////////////////////////////// + { + auto gold = std::vector{ 1, 2, 3 }; + auto test = boost::container::stable_vector(gold.begin(), gold.end()); + if (test.size() != 3) { + return 1; + } + if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) { + return 1; + } + } +#endif + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::stable_vector cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::stable_vector > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} + +#include diff --git a/src/boost/libs/container/test/static_vector_options_test.cpp b/src/boost/libs/container/test/static_vector_options_test.cpp new file mode 100644 index 00000000..e8965d54 --- /dev/null +++ b/src/boost/libs/container/test/static_vector_options_test.cpp @@ -0,0 +1,124 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_ENABLE_ASSERT_HANDLER +#include +#include +#include //for bad_alloc +#include +using namespace boost::container; + +//User-defined assertion to test throw_on_overflow +struct throw_on_overflow_off +{}; + +namespace boost { + void assertion_failed(char const *, char const *, char const *, long) + { + throw throw_on_overflow_off(); + } + + void assertion_failed_msg(char const *, char const *, char const *, char const *, long ) + { + throw throw_on_overflow_off(); + } +} + +void test_alignment() +{ + const std::size_t Capacity = 10u; + { //extended alignment + const std::size_t extended_alignment = sizeof(int)*4u; + BOOST_STATIC_ASSERT(extended_alignment > dtl::alignment_of::value); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< inplace_alignment >; + #else + typedef static_vector_options + < inplace_alignment >::type options_t; + #endif + + static_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % extended_alignment) == 0); + } + { //default alignment + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< inplace_alignment<0> >; + #else + typedef static_vector_options< inplace_alignment<0> >::type options_t; + #endif + + static_vector v; + v.resize(v.capacity()); + BOOST_ASSERT((reinterpret_cast(&v[0]) % dtl::alignment_of::value) == 0); + } +} + +void test_throw_on_overflow() +{ + #if !defined(BOOST_NO_EXCEPTIONS) + const std::size_t Capacity = 10u; + { //throw_on_overflow == true, expect bad_alloc + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< throw_on_overflow >; + #else + typedef static_vector_options + < throw_on_overflow >::type options_t; + #endif + + static_vector v; + + v.resize(Capacity); + bool expected_type_thrown = false; + try{ + v.push_back(0); + } + catch(std::bad_alloc&) + { + expected_type_thrown = true; + } + catch(...) + {} + BOOST_TEST(expected_type_thrown == true); + BOOST_TEST(v.capacity() == Capacity); + } + { //throw_on_overflow == false, test it through BOOST_ASSERT + //even in release mode (BOOST_ENABLE_ASSERT_HANDLER), and throwing + //a special type in that assertion. + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< throw_on_overflow >; + #else + typedef static_vector_options< throw_on_overflow >::type options_t; + #endif + + static_vector v; + + v.resize(Capacity); + bool expected_type_thrown = false; + try{ + v.push_back(0); + } + catch(throw_on_overflow_off) + { + expected_type_thrown = true; + } + catch(...) + {} + BOOST_TEST(expected_type_thrown == true); + BOOST_TEST(v.capacity() == Capacity); + } + #endif +} + +int main() +{ + test_alignment(); + test_throw_on_overflow(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/static_vector_test.cpp b/src/boost/libs/container/test/static_vector_test.cpp new file mode 100644 index 00000000..f47df2e0 --- /dev/null +++ b/src/boost/libs/container/test/static_vector_test.cpp @@ -0,0 +1,827 @@ +// Boost.Container static_vector +// Unit Test + +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2013 Andrew Hundt. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include +#include +#include +#include +#include "../../intrusive/test/iterator_test.hpp" + +#include +#include + +#include "static_vector_test.hpp" + + +template +void test_ctor_ndc() +{ + static_vector s; + BOOST_STATIC_ASSERT((static_vector::static_capacity) == N); + BOOST_TEST_EQ(s.size() , 0u); + BOOST_TEST(s.capacity() == N); + BOOST_TEST(s.max_size() == N); + BOOST_TEST_THROWS( s.at(0u), std::out_of_range ); +} + +template +void test_ctor_nc(size_t n) +{ + static_vector s(n); + BOOST_STATIC_ASSERT((static_vector::static_capacity) == N); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST(s.max_size() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + T val10(10); + s[0] = val10; + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + T val20(20); + s.at(1) = val20; + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_ctor_nd(size_t n, T const& v) +{ + static_vector s(n, v); + BOOST_STATIC_ASSERT((static_vector::static_capacity) == N); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + BOOST_TEST(v == s[0]); + BOOST_TEST(v == s.at(0)); + BOOST_TEST(v == s[1]); + BOOST_TEST(v == s.at(1)); + s[0] = T(10); + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + s.at(1) = T(20); + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +void test_support_for_initializer_list() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + { + static_vector sv = {10, 8}; + BOOST_TEST(10 == sv[0]); + BOOST_TEST(8 == sv[1]); + + typedef static_vector sv_cap_1; + BOOST_TEST_THROWS(sv_cap_1({1, 1}), std::bad_alloc); + } + + { + static_vector sv; + sv.assign({1, 2}); + BOOST_TEST(1 == sv[0]); + BOOST_TEST(2 == sv[1]); + + BOOST_TEST_THROWS(sv.assign({1, 2, 3}), std::bad_alloc); + + static_vector greaterThanSv = {1, 2, 3}; + BOOST_TEST_THROWS(sv = greaterThanSv, std::bad_alloc); + } + + { + static_vector sv; + sv.insert(sv.begin(), {99, 95}); + BOOST_TEST(99 == sv[0]); + BOOST_TEST(95 == sv[1]); + + BOOST_TEST_THROWS(sv.insert(sv.begin(), {101, 102, 103}), std::bad_alloc); + } +#endif +} + +template +void test_resize_nc(size_t n) +{ + static_vector s; + + s.resize(n); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + T val10(10); + s[0] = val10; + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + T val20(20); + s.at(1) = val20; + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_resize_nd(size_t n, T const& v) +{ + static_vector s; + + s.resize(n, v); + BOOST_TEST(s.size() == n); + BOOST_TEST(s.capacity() == N); + BOOST_TEST_THROWS( s.at(n), std::out_of_range ); + if ( 1 < n ) + { + BOOST_TEST(v == s[0]); + BOOST_TEST(v == s.at(0)); + BOOST_TEST(v == s[1]); + BOOST_TEST(v == s.at(1)); + s[0] = T(10); + BOOST_TEST(T(10) == s[0]); + BOOST_TEST(T(10) == s.at(0)); + s.at(1) = T(20); + BOOST_TEST(T(20) == s[1]); + BOOST_TEST(T(20) == s.at(1)); + } +} + +template +void test_push_back_nd() +{ + static_vector s; + + BOOST_TEST(s.size() == 0); + BOOST_TEST_THROWS( s.at(0), std::out_of_range ); + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + BOOST_TEST(s.size() == i + 1); + BOOST_TEST_THROWS( s.at(i + 1), std::out_of_range ); + BOOST_TEST(T(i) == s.at(i)); + BOOST_TEST(T(i) == s[i]); + BOOST_TEST(T(i) == s.back()); + BOOST_TEST(T(0) == s.front()); + BOOST_TEST(T(i) == *(s.data() + i)); + } +} + +template +void test_pop_back_nd() +{ + static_vector s; + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + } + + for ( size_t i = N ; i > 1 ; --i ) + { + s.pop_back(); + BOOST_TEST(s.size() == i - 1); + BOOST_TEST_THROWS( s.at(i - 1), std::out_of_range ); + BOOST_TEST(T(i - 2) == s.at(i - 2)); + BOOST_TEST(T(i - 2) == s[i - 2]); + BOOST_TEST(T(i - 2) == s.back()); + BOOST_TEST(T(0) == s.front()); + } +} + +template +void test_compare_ranges(It1 first1, It1 last1, It2 first2, It2 last2) +{ + BOOST_TEST(boost::container::iterator_distance(first1, last1) == boost::container::iterator_distance(first2, last2)); + for ( ; first1 != last1 && first2 != last2 ; ++first1, ++first2 ) + BOOST_TEST(*first1 == *first2); +} + +template +void test_copy_and_assign(C const& c) +{ + { + static_vector s(c.begin(), c.end()); + BOOST_TEST(s.size() == c.size()); + test_compare_ranges(s.begin(), s.end(), c.begin(), c.end()); + } + { + static_vector s; + BOOST_TEST(0 == s.size()); + s.assign(c.begin(), c.end()); + BOOST_TEST(s.size() == c.size()); + test_compare_ranges(s.begin(), s.end(), c.begin(), c.end()); + } +} + +template +void test_copy_and_assign_nd(T const& val) +{ + static_vector s; + std::vector v; + std::list l; + + for ( size_t i = 0 ; i < N ; ++i ) + { + T t(i); + s.push_back(t); + v.push_back(t); + l.push_back(t); + } + // copy ctor + { + static_vector s1(s); + BOOST_TEST(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + // copy assignment + { + static_vector s1; + BOOST_TEST(0 == s1.size()); + s1 = s; + BOOST_TEST(s.size() == s1.size()); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + } + + // ctor(Iter, Iter) and assign(Iter, Iter) + test_copy_and_assign(s); + test_copy_and_assign(v); + test_copy_and_assign(l); + + // assign(N, V) + { + static_vector s1(s); + test_compare_ranges(s.begin(), s.end(), s1.begin(), s1.end()); + std::vector a(N, val); + s1.assign(N, val); + test_compare_ranges(a.begin(), a.end(), s1.begin(), s1.end()); + } + + stable_vector bsv(s.begin(), s.end()); + vector bv(s.begin(), s.end()); + test_copy_and_assign(bsv); + test_copy_and_assign(bv); +} + +template +void test_iterators_nd() +{ + static_vector s; + std::vector v; + + for ( size_t i = 0 ; i < N ; ++i ) + { + s.push_back(T(i)); + v.push_back(T(i)); + } + + test_compare_ranges(s.begin(), s.end(), v.begin(), v.end()); + test_compare_ranges(s.rbegin(), s.rend(), v.rbegin(), v.rend()); + + s.assign(v.rbegin(), v.rend()); + + test_compare_ranges(s.begin(), s.end(), v.rbegin(), v.rend()); + test_compare_ranges(s.rbegin(), s.rend(), v.begin(), v.end()); +} + +template +void test_erase_nd() +{ + static_vector s; + typedef typename static_vector::iterator It; + + for ( size_t i = 0 ; i < N ; ++i ) + s.push_back(T(i)); + + // erase(pos) + { + for ( size_t i = 0 ; i < N ; ++i ) + { + static_vector s1(s); + It it = s1.erase(s1.begin() + i); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == N - 1); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = i+1 ; j < N ; ++j ) + BOOST_TEST(s1[j-1] == T(j)); + } + } + // erase(first, last) + { + size_t n = N/3; + for ( size_t i = 0 ; i <= N ; ++i ) + { + static_vector s1(s); + size_t removed = i + n < N ? n : N - i; + It it = s1.erase(s1.begin() + i, s1.begin() + i + removed); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == N - removed); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = i+n ; j < N ; ++j ) + BOOST_TEST(s1[j-n] == T(j)); + } + } +} + +template +void test_insert(SV const& s, C const& c) +{ + size_t h = N/2; + size_t n = size_t(h/1.5f); + + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + + typename C::const_iterator it = c.begin(); + boost::container::iterator_advance(it, n); + typename static_vector::iterator + it1 = s1.insert(s1.begin() + i, c.begin(), it); + + BOOST_TEST(s1.begin() + i == it1); + BOOST_TEST(s1.size() == h+n); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = 0 ; j < n ; ++j ) + BOOST_TEST(s1[j+i] == T(100 + j)); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+n] == T(j+i)); + } +} + +template +void test_insert_nd(T const& val) +{ + size_t h = N/2; + + static_vector s, ss; + std::vector v; + std::list l; + + typedef typename static_vector::iterator It; + + for ( size_t i = 0 ; i < h ; ++i ) + { + s.push_back(T(i)); + ss.push_back(T(100 + i)); + v.push_back(T(100 + i)); + l.push_back(T(100 + i)); + } + + // insert(pos, val) + { + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + It it = s1.insert(s1.begin() + i, val); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == h+1); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + BOOST_TEST(s1[i] == val); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+1] == T(j+i)); + } + } + // insert(pos, n, val) + { + size_t n = size_t(h/1.5f); + for ( size_t i = 0 ; i <= h ; ++i ) + { + static_vector s1(s); + It it = s1.insert(s1.begin() + i, n, val); + BOOST_TEST(s1.begin() + i == it); + BOOST_TEST(s1.size() == h+n); + for ( size_t j = 0 ; j < i ; ++j ) + BOOST_TEST(s1[j] == T(j)); + for ( size_t j = 0 ; j < n ; ++j ) + BOOST_TEST(s1[j+i] == val); + for ( size_t j = 0 ; j < h-i ; ++j ) + BOOST_TEST(s1[j+i+n] == T(j+i)); + } + } + // insert(pos, first, last) + test_insert(s, ss); + test_insert(s, v); + test_insert(s, l); + + stable_vector bsv(ss.begin(), ss.end()); + vector bv(ss.begin(), ss.end()); + test_insert(s, bv); + test_insert(s, bsv); +} + +template +void test_capacity_0_nd() +{ + static_vector v(5u, T(0)); + + static_vector s; + BOOST_TEST(s.size() == 0); + BOOST_TEST(s.capacity() == 0); + BOOST_TEST_THROWS(s.at(0), std::out_of_range); + BOOST_TEST_THROWS(s.resize(5u, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.push_back(T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), 5u, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(5u, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(5u, T(0)), std::bad_alloc); + typedef static_vector static_vector_0_t; + BOOST_TEST_THROWS(static_vector_0_t s2(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(static_vector_0_t s1(5u, T(0)), std::bad_alloc); +} + +template +void test_exceptions_nd() +{ + static_vector v(N, T(0)); + static_vector s(N/2, T(0)); + + BOOST_TEST_THROWS(s.resize(N, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.push_back(T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), 1, T(0)), std::bad_alloc); + BOOST_TEST_THROWS(s.insert(s.end(), v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(s.assign(N, T(0)), std::bad_alloc); + typedef static_vector static_vector_n_half_t; + BOOST_TEST_THROWS(static_vector_n_half_t s2(v.begin(), v.end()), std::bad_alloc); + BOOST_TEST_THROWS(static_vector_n_half_t s1(N/2+1, T(0)), std::bad_alloc); +} + +template +void test_swap_and_move_nd() +{ + { + static_vector v1, v2, v3, v4; + static_vector s1, s2; + static_vector s4; + + for (size_t i = 0 ; i < N ; ++i ) + { + v1.push_back(T(i)); + v2.push_back(T(i)); + v3.push_back(T(i)); + v4.push_back(T(i)); + } + for (size_t i = 0 ; i < N/2 ; ++i ) + { + s1.push_back(T(100 + i)); + s2.push_back(T(100 + i)); + s4.push_back(T(100 + i)); + } + + s1.swap(v1); + s2 = boost::move(v2); + static_vector s3(boost::move(v3)); + s4.swap(v4); + + BOOST_TEST(v1.size() == N/2); + BOOST_TEST(s1.size() == N); + //iG moving does not imply emptying source + //BOOST_TEST(v2.size() == 0); + BOOST_TEST(s2.size() == N); + //iG moving does not imply emptying source + //BOOST_TEST(v3.size() == 0); + BOOST_TEST(s3.size() == N); + BOOST_TEST(v4.size() == N/2); + BOOST_TEST(s4.size() == N); + for (size_t i = 0 ; i < N/2 ; ++i ) + { + BOOST_TEST(v1[i] == T(100 + i)); + BOOST_TEST(v4[i] == T(100 + i)); + } + for (size_t i = 0 ; i < N ; ++i ) + { + BOOST_TEST(s1[i] == T(i)); + BOOST_TEST(s2[i] == T(i)); + BOOST_TEST(s3[i] == T(i)); + BOOST_TEST(s4[i] == T(i)); + } + } + { + static_vector v1, v2, v3; + static_vector s1, s2, s3; + + for (size_t i = 0 ; i < N/2 ; ++i ) + { + v1.push_back(T(i)); + v2.push_back(T(i)); + v3.push_back(T(i)); + } + for (size_t i = 0 ; i < N/3 ; ++i ) + { + s1.push_back(T(100 + i)); + s2.push_back(T(100 + i)); + } + + s1.swap(v1); + s3 = v2; + s2 = boost::move(v2); + static_vector s4(boost::move(v3)); + + BOOST_TEST(v1.size() == N/3); + BOOST_TEST(s1.size() == N/2); + //iG moving does not imply emptying source + //BOOST_TEST(v2.size() == 0); + BOOST_TEST(s2.size() == N/2); + BOOST_TEST(s3.size() == N/2); + //iG moving does not imply emptying source + //BOOST_TEST(v3.size() == 0); + BOOST_TEST(s4.size() == N/2); + for (size_t i = 0 ; i < N/3 ; ++i ) + BOOST_TEST(v1[i] == T(100 + i)); + for (size_t i = 0 ; i < N/2 ; ++i ) + { + BOOST_TEST(s1[i] == T(i)); + BOOST_TEST(s2[i] == T(i)); + BOOST_TEST(s3[i] == T(i)); + BOOST_TEST(s4[i] == T(i)); + } + } + { + typedef static_vector small_vector_t; + static_vector v(N, T(0)); + small_vector_t s(N/2, T(1)); + BOOST_TEST_THROWS(s.swap(v), std::bad_alloc); + v.resize(N, T(0)); + BOOST_TEST_THROWS(s = boost::move(v), std::bad_alloc); + BOOST_TEST_THROWS(s = v, std::bad_alloc); + v.resize(N, T(0)); + BOOST_TEST_THROWS(small_vector_t s2(boost::move(v)), std::bad_alloc); + } +} + +template +void test_emplace_0p() +{ + //emplace_back() + { + static_vector v; + + for (int i = 0 ; i < int(N) ; ++i ) + v.emplace_back(); + BOOST_TEST(v.size() == N); + BOOST_TEST_THROWS(v.emplace_back(), std::bad_alloc); + } +} + +template +void test_emplace_2p() +{ + //emplace_back(pos, int, int) + { + static_vector v; + + for (int i = 0 ; i < int(N) ; ++i ) + v.emplace_back(i, 100 + i); + BOOST_TEST(v.size() == N); + BOOST_TEST_THROWS(v.emplace_back(N, 100 + N), std::bad_alloc); + BOOST_TEST(v.size() == N); + for (int i = 0 ; i < int(N) ; ++i ) + BOOST_TEST(v[i] == T(i, 100 + i)); + } + + // emplace(pos, int, int) + { + typedef typename static_vector::iterator It; + + int h = N / 2; + + static_vector v; + for ( int i = 0 ; i < h ; ++i ) + v.emplace_back(i, 100 + i); + + for ( int i = 0 ; i <= h ; ++i ) + { + static_vector vv(v); + It it = vv.emplace(vv.begin() + i, i+100, i+200); + BOOST_TEST(vv.begin() + i == it); + BOOST_TEST(vv.size() == size_t(h+1)); + for ( int j = 0 ; j < i ; ++j ) + BOOST_TEST(vv[j] == T(j, j+100)); + BOOST_TEST(vv[i] == T(i+100, i+200)); + for ( int j = 0 ; j < h-i ; ++j ) + BOOST_TEST(vv[j+i+1] == T(j+i, j+i+100)); + } + } +} + +template +void test_sv_elem(T const& t) +{ + typedef static_vector V; + + static_vector v; + + v.push_back(V(N/2, t)); + V vvv(N/2, t); + v.push_back(boost::move(vvv)); + v.insert(v.begin(), V(N/2, t)); + v.insert(v.end(), V(N/2, t)); + v.emplace_back(N/2, t); +} + +bool default_init_test()//Test for default initialization +{ + const std::size_t Capacity = 100; + + typedef static_vector di_vector_t; + + { + di_vector_t v(Capacity, default_init); + } + { + di_vector_t v; + int *p = v.data(); + + for(std::size_t i = 0; i != Capacity; ++i, ++p){ + *p = static_cast(i); + } + + //Destroy the vector, p still pointing to the storage + v.~di_vector_t(); + + di_vector_t &rv = *::new(&v)di_vector_t(Capacity, default_init); + di_vector_t::iterator it = rv.begin(); + + for(std::size_t i = 0; i != Capacity; ++i, ++it){ + if(*it != static_cast(i)) + return false; + } + + v.~di_vector_t(); + } + { + di_vector_t v; + + int *p = v.data(); + for(std::size_t i = 0; i != Capacity; ++i, ++p){ + *p = static_cast(i+100); + } + + v.resize(Capacity, default_init); + + di_vector_t::iterator it = v.begin(); + for(std::size_t i = 0; i != Capacity; ++i, ++it){ + if(*it != static_cast(i+100)) + return false; + } + } + + return true; +} + + +int main(int, char* []) +{ + using boost::container::test::movable_and_copyable_int; + using boost::container::test::produce_movable_and_copyable_int; + BOOST_TEST(counting_value::count() == 0); + + test_ctor_ndc(); + test_ctor_ndc(); + test_ctor_ndc(); + BOOST_TEST(counting_value::count() == 0); + test_ctor_ndc(); + test_ctor_ndc(); + + test_ctor_nc(5); + test_ctor_nc(5); + test_ctor_nc(5); + BOOST_TEST(counting_value::count() == 0); + test_ctor_nc(5); + test_ctor_nc(5); + + test_ctor_nd(5, 1); + test_ctor_nd(5, value_nd(1)); + test_ctor_nd(5, counting_value(1)); + BOOST_TEST(counting_value::count() == 0); + test_ctor_nd(5, shptr_value(1)); + test_ctor_nd(5, produce_movable_and_copyable_int()); + + test_resize_nc(5); + test_resize_nc(5); + test_resize_nc(5); + BOOST_TEST(counting_value::count() == 0); + test_resize_nc(5); + test_resize_nc(5); + + test_resize_nd(5, 1); + test_resize_nd(5, value_nd(1)); + test_resize_nd(5, counting_value(1)); + BOOST_TEST(counting_value::count() == 0); + test_resize_nd(5, shptr_value(1)); + test_resize_nd(5, produce_movable_and_copyable_int()); + + test_push_back_nd(); + test_push_back_nd(); + test_push_back_nd(); + BOOST_TEST(counting_value::count() == 0); + test_push_back_nd(); + test_push_back_nd(); + + test_pop_back_nd(); + test_pop_back_nd(); + test_pop_back_nd(); + BOOST_TEST(counting_value::count() == 0); + test_pop_back_nd(); + test_pop_back_nd(); + + test_copy_and_assign_nd(1); + test_copy_and_assign_nd(value_nd(1)); + test_copy_and_assign_nd(counting_value(1)); + BOOST_TEST(counting_value::count() == 0); + test_copy_and_assign_nd(shptr_value(1)); + test_copy_and_assign_nd(produce_movable_and_copyable_int()); + + test_iterators_nd(); + test_iterators_nd(); + test_iterators_nd(); + BOOST_TEST(counting_value::count() == 0); + test_iterators_nd(); + test_iterators_nd(); + + test_erase_nd(); + test_erase_nd(); + test_erase_nd(); + BOOST_TEST(counting_value::count() == 0); + test_erase_nd(); + test_erase_nd(); + + test_insert_nd(50); + test_insert_nd(value_nd(50)); + test_insert_nd(counting_value(50)); + BOOST_TEST(counting_value::count() == 0); + test_insert_nd(shptr_value(50)); + test_insert_nd(produce_movable_and_copyable_int()); + + test_capacity_0_nd(); + test_capacity_0_nd(); + test_capacity_0_nd(); + BOOST_TEST(counting_value::count() == 0); + test_capacity_0_nd(); + test_capacity_0_nd(); + + test_exceptions_nd(); + test_exceptions_nd(); + test_exceptions_nd(); + BOOST_TEST(counting_value::count() == 0); + test_exceptions_nd(); + test_exceptions_nd(); + + test_swap_and_move_nd(); + test_swap_and_move_nd(); + test_swap_and_move_nd(); + BOOST_TEST(counting_value::count() == 0); + test_swap_and_move_nd(); + test_swap_and_move_nd(); + + test_emplace_0p(); + BOOST_TEST(counting_value::count() == 0); + + test_emplace_2p(); + BOOST_TEST(counting_value::count() == 0); + + test_sv_elem(50); + test_sv_elem(value_nd(50)); + test_sv_elem(counting_value(50)); + BOOST_TEST(counting_value::count() == 0); + test_sv_elem(shptr_value(50)); + test_sv_elem(movable_and_copyable_int(50)); + + BOOST_TEST(default_init_test() == true); + + test_support_for_initializer_list(); + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::static_vector cont_int; + cont_int a; a.push_back(0); a.push_back(1); a.push_back(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + } + + return boost::report_errors(); +} + +#include diff --git a/src/boost/libs/container/test/static_vector_test.hpp b/src/boost/libs/container/test/static_vector_test.hpp new file mode 100644 index 00000000..ab931b27 --- /dev/null +++ b/src/boost/libs/container/test/static_vector_test.hpp @@ -0,0 +1,103 @@ +// Boost.Container static_vector +// Unit Test + +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2012-2013 Andrew Hundt. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP +#define BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP + +#include + +#define BOOST_SP_DISABLE_THREADS +#include +#include "movable_int.hpp" + +using namespace boost::container; + +class value_ndc +{ +public: + explicit value_ndc(int a) : aa(a) {} + ~value_ndc() {} + bool operator==(value_ndc const& v) const { return aa == v.aa; } + bool operator<(value_ndc const& v) const { return aa < v.aa; } +private: + value_ndc(value_ndc const&) {} + value_ndc & operator=(value_ndc const&) { return *this; } + int aa; +}; + +class value_nd +{ +public: + explicit value_nd(int a) : aa(a) {} + ~value_nd() {} + bool operator==(value_nd const& v) const { return aa == v.aa; } + bool operator<(value_nd const& v) const { return aa < v.aa; } +private: + int aa; +}; + +class value_nc +{ +public: + explicit value_nc(int a = 0) : aa(a) {} + ~value_nc() {} + bool operator==(value_nc const& v) const { return aa == v.aa; } + bool operator<(value_nc const& v) const { return aa < v.aa; } +private: + value_nc(value_nc const&) {} + value_nc & operator=(value_ndc const&) { return *this; } + int aa; +}; + +class counting_value +{ + BOOST_COPYABLE_AND_MOVABLE(counting_value) + +public: + explicit counting_value(int a = 0, int b = 0) : aa(a), bb(b) { ++c(); } + counting_value(counting_value const& v) : aa(v.aa), bb(v.bb) { ++c(); } + counting_value(BOOST_RV_REF(counting_value) p) : aa(p.aa), bb(p.bb) { p.aa = 0; p.bb = 0; ++c(); } // Move constructor + counting_value& operator=(BOOST_RV_REF(counting_value) p) { aa = p.aa; p.aa = 0; bb = p.bb; p.bb = 0; return *this; } // Move assignment + counting_value& operator=(BOOST_COPY_ASSIGN_REF(counting_value) p) { aa = p.aa; bb = p.bb; return *this; } // Copy assignment + ~counting_value() { --c(); } + bool operator==(counting_value const& v) const { return aa == v.aa && bb == v.bb; } + bool operator<(counting_value const& v) const { return aa < v.aa || ( aa == v.aa && bb < v.bb ); } + static size_t count() { return c(); } + +private: + static size_t & c() { static size_t co = 0; return co; } + int aa, bb; +}; + +namespace boost { + +template +struct has_nothrow_move; + +template <> +struct has_nothrow_move +{ + static const bool value = true; +}; + +} + +class shptr_value +{ + typedef boost::shared_ptr Ptr; +public: + explicit shptr_value(int a = 0) : m_ptr(new int(a)) {} + bool operator==(shptr_value const& v) const { return *m_ptr == *(v.m_ptr); } + bool operator<(shptr_value const& v) const { return *m_ptr < *(v.m_ptr); } +private: + boost::shared_ptr m_ptr; +}; + +#endif // BOOST_CONTAINER_TEST_STATIC_VECTOR_TEST_HPP diff --git a/src/boost/libs/container/test/string_test.cpp b/src/boost/libs/container/test/string_test.cpp new file mode 100644 index 00000000..b2d17f6a --- /dev/null +++ b/src/boost/libs/container/test/string_test.cpp @@ -0,0 +1,596 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include //equal() +#include +#include +#include +#include +#include "dummy_test_allocator.hpp" +#include "check_equal_containers.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "propagate_allocator_test.hpp" +#include "default_init_test.hpp" +#include "comparison_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" +#include +#include + +using namespace boost::container; + +struct StringEqual +{ + template + bool operator ()(const Str1 &string1, const Str2 &string2) const + { + if(string1.size() != string2.size()) + return false; + return std::char_traits::compare + (string1.c_str(), string2.c_str(), string1.size()) == 0; + } +}; + +//Function to check if both lists are equal +template +bool CheckEqualStringVector(StrVector1 *strvect1, StrVector2 *strvect2) +{ + StringEqual comp; + return boost::container::algo_equal(strvect1->begin(), strvect1->end(), + strvect2->begin(), comp); +} + +template +ForwardIt unique(ForwardIt first, ForwardIt const last) +{ + if(first == last){ + ForwardIt i = first; + //Find first adjacent pair + while(1){ + if(++i == last){ + return last; + } + else if(*first == *i){ + break; + } + ++first; + } + //Now overwrite skipping adjacent elements + while (++i != last) { + if (!(*first == *i)) { + *(++first) = boost::move(*i); + } + } + ++first; + } + return first; +} + +template +struct string_literals; + +template<> +struct string_literals +{ + static const char *String() + { return "String"; } + static const char *Prefix() + { return "Prefix"; } + static const char *Suffix() + { return "Suffix"; } + static const char *LongString() + { return "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; } + static char Char() + { return 'C'; } + static void sprintf_number(char *buf, int number) + { + std::sprintf(buf, "%i", number); + } +}; + +template<> +struct string_literals +{ + static const wchar_t *String() + { return L"String"; } + static const wchar_t *Prefix() + { return L"Prefix"; } + static const wchar_t *Suffix() + { return L"Suffix"; } + static const wchar_t *LongString() + { return L"LongLongLongLongLongLongLongLongLongLongLongLongLongString"; } + static wchar_t Char() + { return L'C'; } + static void sprintf_number(wchar_t *buffer, unsigned int number) + { + //For compilers without wsprintf, print it backwards + const wchar_t *digits = L"0123456789"; + wchar_t *buf = buffer; + + while(1){ + int rem = number % 10; + number = number / 10; + + *buf = digits[rem]; + ++buf; + if(!number){ + *buf = 0; + break; + } + } + + } +}; + +template +int string_test() +{ + typedef std::basic_string StdString; + typedef vector StdStringVector; + typedef basic_string BoostString; + typedef vector BoostStringVector; + + const int MaxSize = 100; + + { + BoostStringVector *boostStringVect = new BoostStringVector; + StdStringVector *stdStringVect = new StdStringVector; + BoostString auxBoostString; + StdString auxStdString(StdString(auxBoostString.begin(), auxBoostString.end() )); + + CharType buffer [20]; + + //First, push back + for(int i = 0; i < MaxSize; ++i){ + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); + auxBoostString += buffer; + auxStdString += buffer; + boostStringVect->push_back(auxBoostString); + stdStringVect->push_back(auxStdString); + } + + if(auxBoostString.data() != const_cast(auxBoostString).data() && + auxBoostString.data() != &auxBoostString[0]) + return 1; + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)){ + return 1; + } + + //Now push back moving + for(int i = 0; i < MaxSize; ++i){ + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); + auxBoostString += buffer; + auxStdString += buffer; + boostStringVect->push_back(boost::move(auxBoostString)); + stdStringVect->push_back(auxStdString); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)){ + return 1; + } + + //push front + for(int i = 0; i < MaxSize; ++i){ + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); + auxBoostString += buffer; + auxStdString += buffer; + boostStringVect->insert(boostStringVect->begin(), auxBoostString); + stdStringVect->insert(stdStringVect->begin(), auxStdString); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)){ + return 1; + } + + //Now push front moving + for(int i = 0; i < MaxSize; ++i){ + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + string_literals::sprintf_number(buffer, i); + auxBoostString += buffer; + auxStdString += buffer; + boostStringVect->insert(boostStringVect->begin(), boost::move(auxBoostString)); + stdStringVect->insert(stdStringVect->begin(), auxStdString); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)){ + return 1; + } + + //Now test long and short representation swapping + + //Short first + auxBoostString = string_literals::String(); + auxStdString = string_literals::String(); + BoostString boost_swapper; + StdString std_swapper; + boost_swapper.swap(auxBoostString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + if(!StringEqual()(boost_swapper, std_swapper)) + return 1; + boost_swapper.swap(auxBoostString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + if(!StringEqual()(boost_swapper, std_swapper)) + return 1; + + //Shrink_to_fit + auxBoostString.shrink_to_fit(); + StdString(auxStdString).swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + + //Reserve + shrink_to_fit + auxBoostString.reserve(boost_swapper.size()*2+1); + auxStdString.reserve(std_swapper.size()*2+1); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + + auxBoostString.shrink_to_fit(); + StdString(auxStdString).swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + + //Long string + auxBoostString = string_literals::LongString(); + auxStdString = string_literals::LongString(); + boost_swapper = BoostString(); + std_swapper = StdString(); + boost_swapper.swap(auxBoostString); + std_swapper.swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + if(!StringEqual()(boost_swapper, std_swapper)) + return 1; + boost_swapper.swap(auxBoostString); + std_swapper.swap(auxStdString); + + //Shrink_to_fit + auxBoostString.shrink_to_fit(); + StdString(auxStdString).swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + + auxBoostString.clear(); + auxStdString.clear(); + auxBoostString.shrink_to_fit(); + StdString(auxStdString).swap(auxStdString); + if(!StringEqual()(auxBoostString, auxStdString)) + return 1; + + //No sort + std::sort(boostStringVect->begin(), boostStringVect->end()); + std::sort(stdStringVect->begin(), stdStringVect->end()); + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + const CharType *prefix = string_literals::Prefix(); + const int prefix_size = std::char_traits::length(prefix); + const CharType *sufix = string_literals::Suffix(); + + for(int i = 0; i < MaxSize; ++i){ + (*boostStringVect)[i].append(sufix); + (*stdStringVect)[i].append(sufix); + (*boostStringVect)[i].insert((*boostStringVect)[i].begin(), + prefix, prefix + prefix_size); + (*stdStringVect)[i].insert((*stdStringVect)[i].begin(), + prefix, prefix + prefix_size); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end()); + std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end()); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end()); + std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end()); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + std::sort(boostStringVect->begin(), boostStringVect->end()); + std::sort(stdStringVect->begin(), stdStringVect->end()); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + for(int i = 0; i < MaxSize; ++i){ + (*boostStringVect)[i].replace((*boostStringVect)[i].begin(), + (*boostStringVect)[i].end(), + string_literals::String()); + (*stdStringVect)[i].replace((*stdStringVect)[i].begin(), + (*stdStringVect)[i].end(), + string_literals::String()); + } + + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + boostStringVect->erase(::unique(boostStringVect->begin(), boostStringVect->end()), + boostStringVect->end()); + stdStringVect->erase(::unique(stdStringVect->begin(), stdStringVect->end()), + stdStringVect->end()); + if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1; + + //Check addition + { + BoostString bs2 = string_literals::String(); + StdString ss2 = string_literals::String(); + BoostString bs3 = string_literals::Suffix(); + StdString ss3 = string_literals::Suffix(); + BoostString bs4 = bs2 + bs3; + StdString ss4 = ss2 + ss3; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs4 = bs2 + BoostString(); + ss4 = ss2 + StdString(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs4 = BoostString() + bs2; + ss4 = StdString() + ss2; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs4 = BoostString() + boost::move(bs2); + ss4 = StdString() + boost::move(ss2); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = boost::move(bs2) + BoostString(); + ss4 = boost::move(ss2) + StdString(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = string_literals::Prefix() + boost::move(bs2); + ss4 = string_literals::Prefix() + boost::move(ss2); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = boost::move(bs2) + string_literals::Suffix(); + ss4 = boost::move(ss2) + string_literals::Suffix(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = string_literals::Prefix() + bs2; + ss4 = string_literals::Prefix() + ss2; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = bs2 + string_literals::Suffix(); + ss4 = ss2 + string_literals::Suffix(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = string_literals::Char() + bs2; + ss4 = string_literals::Char() + ss2; + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + bs2 = string_literals::String(); + ss2 = string_literals::String(); + bs4 = bs2 + string_literals::Char(); + ss4 = ss2 + string_literals::Char(); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + //Check front/back/begin/end + + if(bs4.front() != *ss4.begin()) + return 1; + + if(bs4.back() != *(ss4.end()-1)) + return 1; + + bs4.pop_back(); + ss4.erase(ss4.end()-1); + if(!StringEqual()(bs4, ss4)){ + return 1; + } + + if(*bs4.begin() != *ss4.begin()) + return 1; + if(*bs4.cbegin() != *ss4.begin()) + return 1; + if(*bs4.rbegin() != *ss4.rbegin()) + return 1; + if(*bs4.crbegin() != *ss4.rbegin()) + return 1; + if(*(bs4.end()-1) != *(ss4.end()-1)) + return 1; + if(*(bs4.cend()-1) != *(ss4.end()-1)) + return 1; + if(*(bs4.rend()-1) != *(ss4.rend()-1)) + return 1; + if(*(bs4.crend()-1) != *(ss4.rend()-1)) + return 1; + } + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //Chect Constructor Template Auto Deduction + { + auto gold = StdString(string_literals::String()); + auto test = basic_string(gold.begin(), gold.end()); + if(!StringEqual()(gold, test)) { + return 1; + } + } +#endif + + + //When done, delete vector + delete boostStringVect; + delete stdStringVect; + } + return 0; +} + +bool test_expand_bwd() +{ + //Now test all back insertion possibilities + typedef test::expand_bwd_test_allocator + allocator_type; + typedef basic_string, allocator_type> + string_type; + return test::test_all_expand_bwd(); +} + +struct boost_container_string; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::basic_string, Allocator> type; + }; +}; + + +}}} //namespace boost::container::test + + +int main() +{ + if(string_test()){ + return 1; + } + + if(string_test()){ + return 1; + } + + //////////////////////////////////// + // Backwards expansion test + //////////////////////////////////// + if(!test_expand_bwd()) + return 1; + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()) + return 1; + + //////////////////////////////////// + // Default init test + //////////////////////////////////// + if(!test::default_init_test< basic_string, test::default_init_allocator > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + if(!test::default_init_test< basic_string, test::default_init_allocator > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::basic_string cont_int; + cont_int a; a.push_back(char(1)); a.push_back(char(2)); a.push_back(char(3)); + boost::intrusive::test::test_iterator_random< cont_int >(a); + } + { + typedef boost::container::basic_string cont_int; + cont_int a; a.push_back(wchar_t(1)); a.push_back(wchar_t(2)); a.push_back(wchar_t(3)); + boost::intrusive::test::test_iterator_random< cont_int >(a); + } + + //////////////////////////////////// + // Comparison testing + //////////////////////////////////// + { + if(!boost::container::test::test_container_comparisons()) + return 1; + if(!boost::container::test::test_container_comparisons()) + return 1; + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::basic_string cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::basic_string, std::allocator > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return boost::report_errors(); +} + +#include diff --git a/src/boost/libs/container/test/string_view_compat_test.cpp b/src/boost/libs/container/test/string_view_compat_test.cpp new file mode 100644 index 00000000..f786b96c --- /dev/null +++ b/src/boost/libs/container/test/string_view_compat_test.cpp @@ -0,0 +1,275 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +void conversion_test() +{ + #ifndef BOOST_CONTAINER_TEMPLATED_CONVERSION_OPERATOR_BROKEN + { + const boost::container::string s = "some text"; + boost::string_view sv(s); + BOOST_TEST(s.data() == sv.data() && s.size() == sv.size()); + boost::string_view sv2; + sv2 = s; + BOOST_TEST(s.data() == sv2.data() && s.size() == sv2.size()); + const boost::string_view csv(s); + BOOST_TEST(s.data() == sv.data() && s.size() == csv.size()); + } + #endif +} + +void to_view_test() +{ + const boost::container::string s = "some text"; + boost::string_view sv(s.to_view()); + BOOST_TEST(s.data() == sv.data() && s.size() == sv.size()); + boost::string_view sv2; + sv2 = s.to_view(); + BOOST_TEST(s.data() == sv2.data() && s.size() == sv2.size()); + const boost::string_view csv(s.to_view()); + BOOST_TEST(s.data() == csv.data() && s.size() == csv.size()); +} + +void equal_test() +{ + const boost::string_view sv = "same text"; + const boost::string_view svd = "different text"; + const boost::container::string s = "same text"; + BOOST_TEST(sv == s); + BOOST_TEST(s == sv); + BOOST_TEST(!(svd == s)); + BOOST_TEST(!(s == svd)); +} + +void unequal_test() +{ + const boost::string_view sv = "same text"; + const boost::string_view svd = "different text"; + const boost::container::string s = "same text"; + BOOST_TEST(!(sv != s)); + BOOST_TEST(!(s != sv)); + BOOST_TEST(svd != s); + BOOST_TEST(s != svd); +} + +void less_test() +{ + boost::string_view sv = "0123456"; + boost::container::string s = "0123459"; + BOOST_TEST(sv < s); + BOOST_TEST(!(s < sv)); + + sv = "0123459"; + s = "0123456"; + BOOST_TEST(!(sv < s)); + BOOST_TEST(s < sv); + + sv = "0123456"; + BOOST_TEST(!(sv < s)); + BOOST_TEST(!(s < sv)); +} + +void greater_test() +{ + boost::string_view sv = "0123459"; + boost::container::string s = "0123456"; + BOOST_TEST(sv > s); + BOOST_TEST(!(s > sv)); + + sv = "0123456"; + s = "0123459"; + BOOST_TEST(!(sv > s)); + BOOST_TEST(s > sv); + + sv = "0123459"; + BOOST_TEST(!(sv > s)); + BOOST_TEST(!(s > sv)); +} + +void less_equal_test() +{ + boost::string_view sv = "0123456"; + boost::container::string s = "0123459"; + BOOST_TEST(sv <= s); + BOOST_TEST(!(s <= sv)); + + sv = "0123459"; + s = "0123456"; + BOOST_TEST(!(sv <= s)); + BOOST_TEST(s <= sv); + + sv = "0123456"; + BOOST_TEST(sv <= s); + BOOST_TEST(s <= sv); +} + +void greater_equal_test() +{ + boost::string_view sv = "0123459"; + boost::container::string s = "0123456"; + BOOST_TEST(sv >= s); + BOOST_TEST(!(s >= sv)); + + sv = "0123456"; + s = "0123459"; + BOOST_TEST(!(sv >= s)); + BOOST_TEST(s >= sv); + + sv = "0123459"; + BOOST_TEST(sv >= s); + BOOST_TEST(s >= sv); +} + +void constructor_test() +{ + boost::string_view sv = "0123459"; + boost::container::string s(sv); + BOOST_TEST(sv == s); + boost::container::string s2(sv, s.get_allocator()); + BOOST_TEST(sv == s); +} + +void assignment_test() +{ + boost::string_view sv = "0123459"; + boost::container::string s; + s = sv; + BOOST_TEST(sv == s); +} + +void assign_test() +{ + boost::string_view sv = "0123459"; + boost::container::string s; + s.assign(sv); + BOOST_TEST(sv == s); +} + +void plus_equal_test() +{ + boost::string_view sv = "23459"; + boost::container::string s("01"); + s += sv; + BOOST_TEST(s == "0123459"); +} + +void append_test() +{ + boost::string_view sv = "23459"; + boost::container::string s("01"); + s.append(sv); + BOOST_TEST(s == "0123459"); +} + +void insert_test() +{ + boost::string_view sv = "34"; + boost::container::string s("01259"); + s.insert(3u, sv); + BOOST_TEST(s == "0123459"); +} + +void replace_test() +{ + boost::string_view sv = "5678"; + boost::container::string s("01259"); + s.replace(2u, 2u, sv); + BOOST_TEST(s == "0156789"); + s.replace(s.begin()+3, s.begin()+6, sv); + BOOST_TEST(s == "01556789"); + s.replace(5u, 3u, sv, 2u, 2u); + BOOST_TEST(s == "0155678"); +} + +void find_test() +{ + const boost::string_view sv = "25"; + boost::container::string s("0125925123"); + BOOST_TEST(s.find(sv,4) == 5); +} + +void rfind_test() +{ + const boost::string_view sv = "25"; + boost::container::string s("0125925123"); + BOOST_TEST(s.rfind(sv,4) == 2); +} + +void find_first_of_test() +{ + const boost::string_view sv = "52"; + boost::container::string s("0125925123"); + BOOST_TEST(s.find_first_of(sv,4) == 5); +} + +void find_last_of_test() +{ + const boost::string_view sv = "52"; + boost::container::string s("520125925123"); + BOOST_TEST(s.find_last_of(sv,6) == 5); +} + +void find_first_not_of_test() +{ + const boost::string_view sv = "52"; + boost::container::string s("0125925123"); + BOOST_TEST(s.find_first_not_of(sv,2) == 4); +} + +void find_last_not_of_test() +{ + const boost::string_view sv = "52"; + boost::container::string s("0125925123"); + BOOST_TEST(s.find_last_not_of(sv,6) == 4); +} + +void compare_test() +{ + const boost::string_view sv = "52"; + boost::container::string s("0125925123"); + BOOST_TEST(s.compare(sv) < 0); + BOOST_TEST(s.compare(boost::string_view("0125925123")) == 0); + BOOST_TEST(s.compare(2u, s.size() - 2u, boost::string_view("25925123")) == 0); + boost::string_view sv2("5212592512389"); + BOOST_TEST(s.compare(2u, s.size() - 2u, sv2, 3, sv2.size()-5u) == 0); +} + +int main() +{ + conversion_test(); + to_view_test(); + equal_test(); + unequal_test(); + less_test(); + greater_test(); + less_equal_test(); + greater_equal_test(); + constructor_test(); + assignment_test(); + assign_test(); + plus_equal_test(); + append_test(); + insert_test(); + replace_test(); + find_test(); + rfind_test(); + find_first_of_test(); + find_last_of_test(); + find_first_not_of_test(); + find_last_not_of_test(); + compare_test(); + + return boost::report_errors(); +} + diff --git a/src/boost/libs/container/test/synchronized_pool_resource_test.cpp b/src/boost/libs/container/test/synchronized_pool_resource_test.cpp new file mode 100644 index 00000000..da1589a0 --- /dev/null +++ b/src/boost/libs/container/test/synchronized_pool_resource_test.cpp @@ -0,0 +1,19 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "pool_resource_test.hpp" + +int main() +{ + test_pool_resource(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/throw_exception_test.cpp b/src/boost/libs/container/test/throw_exception_test.cpp new file mode 100644 index 00000000..2cbabefc --- /dev/null +++ b/src/boost/libs/container/test/throw_exception_test.cpp @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS + +#include + +#include +#include + +using namespace boost::container; + +static bool bad_alloc_called = false; +static bool out_of_range_called = false; +static bool length_error_called = false; +static bool logic_error_called = false; +static bool runtime_error_called = false; + +//User defined throw implementations +namespace boost { +namespace container { + + void throw_bad_alloc() + { bad_alloc_called = true; } + + void throw_out_of_range(const char* str) + { (void)str; out_of_range_called = true; } + + void throw_length_error(const char* str) + { (void)str; length_error_called = true; } + + void throw_logic_error(const char* str) + { (void)str; logic_error_called = true; } + + void throw_runtime_error(const char* str) + { (void)str; runtime_error_called = true; } + +}} //boost::container + +int main() +{ + //Check user-defined throw callbacks are called + throw_bad_alloc(); + BOOST_TEST(bad_alloc_called == true); + throw_out_of_range("dummy"); + BOOST_TEST(out_of_range_called == true); + throw_length_error("dummy"); + BOOST_TEST(length_error_called == true); + throw_logic_error("dummy"); + BOOST_TEST(logic_error_called == true); + throw_runtime_error("dummy"); + BOOST_TEST(runtime_error_called == true); + return ::boost::report_errors(); +} + +#include diff --git a/src/boost/libs/container/test/tree_test.cpp b/src/boost/libs/container/test/tree_test.cpp new file mode 100644 index 00000000..e0755967 --- /dev/null +++ b/src/boost/libs/container/test/tree_test.cpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include + +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +using namespace boost::container; + +typedef std::pair pair_t; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +namespace dtl { + +//Instantiate base class as previous instantiations don't instantiate inherited members +template class tree + < pair_t + , select1st + , std::less + , test::simple_allocator + , tree_assoc_defaults + >; + +template class tree + < pair_t + , select1st + , std::less + , std::allocator + , tree_assoc_defaults + >; + +template class tree + < pair_t + , select1st + , std::less + , adaptive_pool + , tree_assoc_defaults + >; + +template class tree + < test::movable_and_copyable_int + , identity + , std::less + , test::simple_allocator + , tree_assoc_defaults + >; + +template class tree + < test::movable_and_copyable_int + , identity + , std::less + , std::allocator + , tree_assoc_defaults + >; + +template class tree + < test::movable_and_copyable_int + , identity + , std::less + , adaptive_pool + , tree_assoc_defaults + >; + +} //dtl { + +}} //boost::container + +int main () +{ + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default + { + typedef boost::container::dtl::tree, void, void> tree; + typedef tree::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::dtl::tree, std::allocator, void> tree; + typedef tree::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + typedef tree::key_compare key_compare; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/boost/libs/container/test/unsynchronized_pool_resource_test.cpp b/src/boost/libs/container/test/unsynchronized_pool_resource_test.cpp new file mode 100644 index 00000000..298607a8 --- /dev/null +++ b/src/boost/libs/container/test/unsynchronized_pool_resource_test.cpp @@ -0,0 +1,19 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "pool_resource_test.hpp" + +int main() +{ + test_pool_resource(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/uses_allocator_test.cpp b/src/boost/libs/container/test/uses_allocator_test.cpp new file mode 100644 index 00000000..39807f09 --- /dev/null +++ b/src/boost/libs/container/test/uses_allocator_test.cpp @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include +#include "propagation_test_allocator.hpp" + +struct not_uses_allocator +{}; + +struct uses_allocator_and_not_convertible_to_int +{ + typedef uses_allocator_and_not_convertible_to_int allocator_type; +}; + +struct uses_allocator_and_convertible_to_int +{ + typedef char allocator_type; +}; + +struct uses_erased_type_allocator +{ + typedef boost::container::erased_type allocator_type; +}; + + +int main() +{ + using namespace boost::container; + //Using dummy classes + BOOST_STATIC_ASSERT(( false == uses_allocator + < not_uses_allocator, int>::value )); + + BOOST_STATIC_ASSERT(( false == uses_allocator + < uses_allocator_and_not_convertible_to_int, int>::value )); + + BOOST_STATIC_ASSERT(( true == uses_allocator + < uses_allocator_and_convertible_to_int, int>::value )); + + BOOST_STATIC_ASSERT(( true == uses_allocator + < uses_erased_type_allocator, int>::value )); + + //Using an allocator-like class + BOOST_STATIC_ASSERT(( false == uses_allocator + < allocator_argument_tester + , propagation_test_allocator + >::value )); + BOOST_STATIC_ASSERT(( true == uses_allocator + < allocator_argument_tester + , propagation_test_allocator + >::value )); + BOOST_STATIC_ASSERT(( true == uses_allocator + < allocator_argument_tester + , propagation_test_allocator + >::value )); + BOOST_STATIC_ASSERT(( true == uses_allocator + < allocator_argument_tester + , propagation_test_allocator + >::value )); + BOOST_STATIC_ASSERT(( true == uses_allocator + < allocator_argument_tester + , propagation_test_allocator + >::value )); + BOOST_STATIC_ASSERT(( true == constructible_with_allocator_prefix + < allocator_argument_tester >::value )); + + BOOST_STATIC_ASSERT(( true == constructible_with_allocator_suffix + < allocator_argument_tester >::value )); + + BOOST_STATIC_ASSERT(( true == constructible_with_allocator_prefix + < allocator_argument_tester >::value )); + + BOOST_STATIC_ASSERT(( true == constructible_with_allocator_suffix + < allocator_argument_tester >::value )); + return 0; +} diff --git a/src/boost/libs/container/test/vector_options_test.cpp b/src/boost/libs/container/test/vector_options_test.cpp new file mode 100644 index 00000000..9b414fb8 --- /dev/null +++ b/src/boost/libs/container/test/vector_options_test.cpp @@ -0,0 +1,121 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +using namespace boost::container; + +template +void test_stored_size_type_impl() +{ + VectorType v; + typedef typename VectorType::size_type size_type; + typedef typename VectorType::value_type value_type; + size_type const max = Unsigned(-1); + v.resize(5); + v.resize(max); + BOOST_TEST_THROWS(v.resize(max+1), std::exception); + BOOST_TEST_THROWS(v.push_back(value_type(1)), std::exception); + BOOST_TEST_THROWS(v.insert(v.begin(), value_type(1)), std::exception); + BOOST_TEST_THROWS(v.emplace(v.begin(), value_type(1)),std::exception); + BOOST_TEST_THROWS(v.reserve(max+1), std::exception); + BOOST_TEST_THROWS(VectorType v2(max+1), std::exception); +} + +template +void test_stored_size_type() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = vector_options_t< stored_size >; + #else + typedef typename vector_options + < stored_size >::type options_t; + #endif + + //Test first with a typical allocator + { + typedef vector, options_t> vector_t; + test_stored_size_type_impl(); + } + //Test with a V2 allocator + { + typedef vector, options_t> vector_t; + test_stored_size_type_impl(); + } +} + +void test_growth_factor_50() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = vector_options_t< growth_factor >; + #else + typedef vector_options + < growth_factor >::type options_t; + #endif + + vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + old_capacity/2); +} + +void test_growth_factor_60() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = vector_options_t< growth_factor >; + #else + typedef vector_options + < growth_factor >::type options_t; + #endif + + vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + 3*old_capacity/5); +} + +void test_growth_factor_100() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = vector_options_t< growth_factor >; + #else + typedef vector_options + < growth_factor >::type options_t; + #endif + + vector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == 2*old_capacity); +} + +int main() +{ + test_growth_factor_50(); + test_growth_factor_60(); + test_growth_factor_100(); + test_stored_size_type(); + test_stored_size_type(); + return ::boost::report_errors(); +} diff --git a/src/boost/libs/container/test/vector_test.cpp b/src/boost/libs/container/test/vector_test.cpp new file mode 100644 index 00000000..c9b82cc3 --- /dev/null +++ b/src/boost/libs/container/test/vector_test.cpp @@ -0,0 +1,364 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +// the tests trigger deprecation warnings when compiled with msvc in C++17 mode +#if defined(_MSVC_LANG) && _MSVC_LANG > 201402 +// warning STL4009: std::allocator is deprecated in C++17 +# define _SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING +#endif + +#include +#include + +#include +#include + +#include +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "dummy_test_allocator.hpp" +#include "propagate_allocator_test.hpp" +#include "vector_test.hpp" +#include "default_init_test.hpp" +#include "../../intrusive/test/iterator_test.hpp" + +using namespace boost::container; + +int test_expand_bwd() +{ + //Now test all back insertion possibilities + + //First raw ints + typedef test::expand_bwd_test_allocator + int_allocator_type; + typedef vector + int_vector; + if(!test::test_all_expand_bwd()) + return 1; + + //Now user defined copyable int + typedef test::expand_bwd_test_allocator + copyable_int_allocator_type; + typedef vector + copyable_int_vector; + if(!test::test_all_expand_bwd()) + return 1; + + return 0; +} + +struct X; + +template +struct XRef +{ + explicit XRef(T* ptr) : ptr(ptr) {} + operator T*() const { return ptr; } + T* ptr; +}; + +struct X +{ + XRef operator&() const { return XRef(this); } + XRef operator&() { return XRef(this); } +}; + + +bool test_smart_ref_type() +{ + boost::container::vector x(5); + return x.empty(); +} + +class recursive_vector +{ + public: + recursive_vector & operator=(const recursive_vector &x) + { this->vector_ = x.vector_; return *this; } + + int id_; + vector vector_; + vector::iterator it_; + vector::const_iterator cit_; + vector::reverse_iterator rit_; + vector::const_reverse_iterator crit_; +}; + +void recursive_vector_test()//Test for recursive types +{ + vector recursive_vector_vector; +} + +enum Test +{ + zero, one, two, three, four, five, six +}; + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef vector< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +template +int test_cont_variants() +{ + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; + + return 0; +} + +struct boost_container_vector; + +namespace boost { namespace container { namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef boost::container::vector type; + }; +}; + +}}} //namespace boost::container::test + +template +class check_dealloc_allocator : public std::allocator +{ + public: + bool allocate_zero_called_; + bool deallocate_called_without_allocate_; + + check_dealloc_allocator() + : std::allocator() + , allocate_zero_called_(false) + , deallocate_called_without_allocate_(false) + {} + + T* allocate(std::size_t n) + { + if (n == 0) { + allocate_zero_called_ = true; + } + return std::allocator::allocate(n); + } + + void deallocate(T* p, std::size_t n) + { + if (n == 0 && !allocate_zero_called_) { + deallocate_called_without_allocate_ = true; + } + return std::allocator::deallocate(p, n); + } +}; + +bool test_merge_empty_free() +{ + vector source; + source.emplace_back(1); + + vector< int, check_dealloc_allocator > empty; + empty.merge(source.begin(), source.end()); + + return empty.get_stored_allocator().deallocate_called_without_allocate_; +} + +int main() +{ + { + const std::size_t positions_length = 10; + std::size_t positions[positions_length]; + vector vector_int; + vector vector_int2(positions_length); + for(std::size_t i = 0; i != positions_length; ++i){ + positions[i] = 0u; + } + for(std::size_t i = 0, max = vector_int2.size(); i != max; ++i){ + vector_int2[i] = (int)i; + } + + vector_int.insert(vector_int.begin(), 999); + + vector_int.insert_ordered_at(positions_length, positions + positions_length, vector_int2.end()); + + for(std::size_t i = 0, max = vector_int.size(); i != max; ++i){ + std::cout << vector_int[i] << std::endl; + } + } + recursive_vector_test(); + { + //Now test move semantics + vector original; + vector move_ctor(boost::move(original)); + vector move_assign; + move_assign = boost::move(move_ctor); + move_assign.swap(original); + } + + //////////////////////////////////// + // Testing allocator implementations + //////////////////////////////////// + // std:allocator + if(test_cont_variants< std::allocator >()){ + std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; + return 1; + } + // boost::container::allocator + if(test_cont_variants< allocator >()){ + std::cerr << "test_cont_variants< allocator > failed" << std::endl; + return 1; + } + + { + typedef vector > MyEnumCont; + MyEnumCont v; + Test t; + v.push_back(t); + v.push_back(::boost::move(t)); + v.push_back(Test()); + } + + if (test_smart_ref_type()) + return 1; + + //////////////////////////////////// + // Backwards expansion test + //////////////////////////////////// + if(test_expand_bwd()) + return 1; + + //////////////////////////////////// + // Default init test + //////////////////////////////////// + if(!test::default_init_test< vector > >()){ + std::cerr << "Default init test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // Emplace testing + //////////////////////////////////// + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::container::test::test_emplace< vector, Options>()){ + return 1; + } + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + if(!boost::container::test::test_propagate_allocator()){ + return 1; + } + + //////////////////////////////////// + // Initializer lists testing + //////////////////////////////////// + if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for< + boost::container::vector + >()) { + return 1; + } + + //////////////////////////////////// + // Iterator testing + //////////////////////////////////// + { + typedef boost::container::vector cont_int; + cont_int a; a.push_back(0); a.push_back(1); a.push_back(2); + boost::intrusive::test::test_iterator_random< cont_int >(a); + if(boost::report_errors() != 0) { + return 1; + } + } + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + //////////////////////////////////// + // Constructor Template Auto Deduction testing + //////////////////////////////////// + { + auto gold = std::vector{ 1, 2, 3 }; + auto test = boost::container::vector(gold.begin(), gold.end()); + if (test.size() != 3) { + return 1; + } + if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) { + return 1; + } + } + { + auto gold = std::vector{ 1, 2, 3 }; + auto test = boost::container::vector(gold.begin(), gold.end(), boost::container::new_allocator()); + if (test.size() != 3) { + return 1; + } + if (!(test[0] == 1 && test[1] == 2 && test[2] == 3)) { + return 1; + } + } +#endif + + if (test_merge_empty_free()) { + std::cerr << "Merge into empty vector test failed" << std::endl; + return 1; + } + + //////////////////////////////////// + // has_trivial_destructor_after_move testing + //////////////////////////////////// + // default allocator + { + typedef boost::container::vector cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl; + return 1; + } + } + // std::allocator + { + typedef boost::container::vector > cont; + typedef cont::allocator_type allocator_type; + typedef boost::container::allocator_traits::pointer pointer; + if (boost::has_trivial_destructor_after_move::value != + boost::has_trivial_destructor_after_move::value && + boost::has_trivial_destructor_after_move::value) { + std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/boost/libs/container/test/vector_test.hpp b/src/boost/libs/container/test/vector_test.hpp new file mode 100644 index 00000000..016da1a7 --- /dev/null +++ b/src/boost/libs/container/test/vector_test.hpp @@ -0,0 +1,563 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER +#define BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "print_container.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "emplace_test.hpp" +#include "input_from_forward_iterator.hpp" +#include "insert_test.hpp" +#include "container_common_tests.hpp" + +#include +#include +#include + + +namespace boost{ +namespace container { +namespace test{ + +template +struct vector_hash_function_capacity +{ + typedef typename Vector::size_type size_type; + template struct Check; + template static char func(Check *); + template static int func(...); + + public: + static const bool value = sizeof(func(0)) == sizeof(char); +}; + +template +bool vector_vector_hash_function_capacity_only(V1&, V2&, boost::container::dtl::false_type) +{ + return true; +} + +template +bool vector_vector_hash_function_capacity_only(MyBoostVector&boostvector, MyStdVector&stdvector, boost::container::dtl::true_type) +{ + //deque has no reserve + boostvector.reserve(boostvector.size()*2); + stdvector.reserve(stdvector.size()*2); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + std::size_t cap = boostvector.capacity(); + boostvector.reserve(cap*2); + stdvector.reserve(cap*2); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + boostvector.resize(0); + stdvector.resize(0); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + boostvector.resize(cap*2); + stdvector.resize(cap*2); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + boostvector.resize(cap*2); + stdvector.resize(cap*2); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + return true; +} + + +template +bool vector_copyable_only(V1&, V2&, boost::container::dtl::false_type) +{ + return true; +} + +//Function to check if both sets are equal +template +bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, boost::container::dtl::true_type) +{ + typedef typename MyBoostVector::value_type IntType; + std::size_t size = boostvector.size(); + boostvector.insert(boostvector.end(), 50, IntType(1)); + stdvector.insert(stdvector.end(), 50, 1); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + { + IntType move_me(1); + boostvector.insert(boostvector.begin()+size/2, 50, boost::move(move_me)); + stdvector.insert(stdvector.begin()+size/2, 50, 1); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + } + { + IntType move_me(2); + boostvector.assign(boostvector.size()/2, boost::move(move_me)); + stdvector.assign(stdvector.size()/2, 2); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + } + { + IntType move_me(3); + boostvector.assign(boostvector.size()*3-1, boost::move(move_me)); + stdvector.assign(stdvector.size()*3-1, 3); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + } + + { + IntType copy_me(3); + const IntType ccopy_me(3); + boostvector.push_back(copy_me); + stdvector.push_back(int(3)); + boostvector.push_back(ccopy_me); + stdvector.push_back(int(3)); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + } + { //Vector(const Vector &) + ::boost::movelib::unique_ptr const pv1 = + ::boost::movelib::make_unique(boostvector); + ::boost::movelib::unique_ptr const pv2 = + ::boost::movelib::make_unique(stdvector); + + MyBoostVector &v1 = *pv1; + MyStdVector &v2 = *pv2; + + boostvector.clear(); + stdvector.clear(); + boostvector.assign(v1.begin(), v1.end()); + stdvector.assign(v2.begin(), v2.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + { //Vector(const Vector &, alloc) + ::boost::movelib::unique_ptr const pv1 = + ::boost::movelib::make_unique(boostvector, typename MyBoostVector::allocator_type()); + ::boost::movelib::unique_ptr const pv2 = + ::boost::movelib::make_unique(stdvector); + + MyBoostVector &v1 = *pv1; + MyStdVector &v2 = *pv2; + + boostvector.clear(); + stdvector.clear(); + boostvector.assign(v1.begin(), v1.end()); + stdvector.assign(v2.begin(), v2.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + { //Vector(n, T) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100, int(5)); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100, IntType(5)); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + { //Vector(n, T, alloc) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100, int(5)); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100, IntType(5), typename MyBoostVector::allocator_type()); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + { //Vector(It, It) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(boostvectorp->begin(), boostvectorp->end()); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + { //Vector(It, It, alloc) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(boostvectorp->begin(), boostvectorp->end(), typename MyBoostVector::allocator_type()); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + { //resize(n, T) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(); + stdvectorp->resize(100, int(9)); + boostvectorp->resize(100, IntType(9)); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + //operator= + { + //Copy constructor test + MyBoostVector bcopy((const MyBoostVector&) boostvector); + MyStdVector scopy((const MyStdVector&) stdvector); + MyBoostVector bcopy2(boostvector); + MyStdVector scopy2(stdvector); + + if(!test::CheckEqualContainers(bcopy, scopy)) return false; + if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + + //Assignment from a smaller vector + bcopy2.erase(bcopy2.begin() + bcopy2.size()/2, bcopy2.end()); + scopy2.erase(scopy2.begin() + scopy2.size()/2, scopy2.end()); + bcopy = bcopy2; + scopy = scopy2; + if(!test::CheckEqualContainers(bcopy, scopy)) return false; + + //Assignment from a bigger vector with capacity + bcopy2 = boostvector; + scopy2 = stdvector; + if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + + //Assignment from bigger vector with no capacity + bcopy2.erase(bcopy2.begin() + bcopy2.size()/2, bcopy2.end()); + scopy2.erase(scopy2.begin() + scopy2.size()/2, scopy2.end()); + bcopy2.shrink_to_fit(); + MyStdVector(scopy2).swap(scopy2); + + bcopy2 = boostvector; + scopy2 = stdvector; + if(!test::CheckEqualContainers(bcopy, scopy)) return false; + + //Assignment with equal capacity + bcopy2 = boostvector; + scopy2 = stdvector; + if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + } + + return true; +} + +template +int vector_test() +{ + typedef std::vector MyStdVector; + typedef typename MyBoostVector::value_type IntType; + const int max = 100; + + if(!test_range_insertion()){ + return 1; + } + { //Vector(n) + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + { //Vector(n, alloc) + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100, typename MyBoostVector::allocator_type()); + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + { //Vector(Vector &&) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(::boost::move(*boostvectorp)); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + { //Vector(Vector &&, alloc) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique + (::boost::move(*boostvectorp), typename MyBoostVector::allocator_type()); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + { //Vector operator=(Vector &&) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(); + *boostvectorp2 = ::boost::move(*boostvectorp); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + { + ::boost::movelib::unique_ptr const boostvectorp = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const stdvectorp = ::boost::movelib::make_unique(); + + MyBoostVector & boostvector = *boostvectorp; + MyStdVector & stdvector = *stdvectorp; + + boostvector.resize(100); + stdvector.resize(100); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector.resize(200); + stdvector.resize(200); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector.resize(0); + stdvector.resize(0); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + for(int i = 0; i < max; ++i){ + IntType new_int(i); + boostvector.insert(boostvector.end(), boost::move(new_int)); + stdvector.insert(stdvector.end(), i); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + typename MyBoostVector::iterator boostit(boostvector.begin()); + typename MyStdVector::iterator stdit(stdvector.begin()); + typename MyBoostVector::const_iterator cboostit = boostit; + (void)cboostit; + ++boostit; ++stdit; + boostvector.erase(boostit); + stdvector.erase(stdit); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector.erase(boostvector.begin()); + stdvector.erase(stdvector.begin()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + { + //Initialize values + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType new_int(-1); + BOOST_STATIC_ASSERT((boost::container::test::is_copyable::value == false)); + aux_vect[i] = boost::move(new_int); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + typename MyBoostVector::iterator insert_it = + boostvector.insert(boostvector.end() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + if(std::size_t(boost::container::iterator_distance(insert_it, boostvector.end())) != 50) return 1; + stdvector.insert(stdvector.end(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + for(int i = 0, j = static_cast(boostvector.size()); i < j; ++i){ + boostvector.erase(boostvector.begin()); + stdvector.erase(stdvector.begin()); + } + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + { + boostvector.resize(100); + stdvector.resize(100); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType new_int(-i); + aux_vect[i] = boost::move(new_int); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -i; + } + typename MyBoostVector::size_type old_size = boostvector.size(); + typename MyBoostVector::iterator insert_it = + boostvector.insert(boostvector.begin() + old_size/2 + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + if(boostvector.begin() + old_size/2 != insert_it) return 1; + stdvector.insert(stdvector.begin() + old_size/2, aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + for(int i = 0; i < 50; ++i){ + IntType new_int(-i); + aux_vect[i] = boost::move(new_int); + } + + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -i; + } + old_size = boostvector.size(); + //Now try with input iterators instead + insert_it = boostvector.insert(boostvector.begin() + old_size/2 + ,boost::make_move_iterator(make_input_from_forward_iterator(&aux_vect[0])) + ,boost::make_move_iterator(make_input_from_forward_iterator(aux_vect + 50)) + ); + if(boostvector.begin() + old_size/2 != insert_it) return 1; + stdvector.insert(stdvector.begin() + old_size/2, aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + + boostvector.shrink_to_fit(); + MyStdVector(stdvector).swap(stdvector); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector.shrink_to_fit(); + MyStdVector(stdvector).swap(stdvector); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + { //push_back with not enough capacity + IntType push_back_this(1); + boostvector.push_back(boost::move(push_back_this)); + stdvector.push_back(int(1)); + boostvector.push_back(IntType(1)); + stdvector.push_back(int(1)); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + + { //test back() + const IntType test_this(1); + if(test_this != boostvector.back()) return 1; + } + { //pop_back with enough capacity + boostvector.pop_back(); + boostvector.pop_back(); + stdvector.pop_back(); + stdvector.pop_back(); + + IntType push_back_this(1); + boostvector.push_back(boost::move(push_back_this)); + stdvector.push_back(int(1)); + boostvector.push_back(IntType(1)); + stdvector.push_back(int(1)); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + + if(!vector_copyable_only(boostvector, stdvector + ,dtl::bool_::value>())){ + return 1; + } + + boostvector.erase(boostvector.begin()); + stdvector.erase(stdvector.begin()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + for(int i = 0; i < max; ++i){ + IntType insert_this(i); + boostvector.insert(boostvector.begin(), boost::move(insert_this)); + stdvector.insert(stdvector.begin(), i); + boostvector.insert(boostvector.begin(), IntType(i)); + stdvector.insert(stdvector.begin(), int(i)); + } + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + //some comparison operators + if(!(boostvector == boostvector)) + return 1; + if(boostvector != boostvector) + return 1; + if(boostvector < boostvector) + return 1; + if(boostvector > boostvector) + return 1; + if(!(boostvector <= boostvector)) + return 1; + if(!(boostvector >= boostvector)) + return 1; + + //Test insertion from list + { + std::list l(50, int(1)); + typename MyBoostVector::iterator it_insert = + boostvector.insert(boostvector.begin(), l.begin(), l.end()); + if(boostvector.begin() != it_insert) return 1; + stdvector.insert(stdvector.begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + boostvector.assign(l.begin(), l.end()); + stdvector.assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + + boostvector.clear(); + stdvector.clear(); + boostvector.assign(make_input_from_forward_iterator(l.begin()), make_input_from_forward_iterator(l.end())); + stdvector.assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; + } + + if(!vector_vector_hash_function_capacity_only(boostvector, stdvector, dtl::bool_::value>())) + return 1; + + boostvector.clear(); + stdvector.clear(); + boostvector.shrink_to_fit(); + MyStdVector(stdvector).swap(stdvector); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + boostvector.resize(100); + if(!test_nth_index_of(boostvector)) + return 1; + + } + std::cout << std::endl << "Test OK!" << std::endl; + return 0; +} + +template +bool test_vector_methods_with_initializer_list_as_argument_for() +{ +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename VectorContainerType::allocator_type allocator_type; + { + const VectorContainerType testedVector = {1, 2, 3}; + const std::vector expectedVector = {1, 2, 3}; + if(!test::CheckEqualContainers(testedVector, expectedVector)) return false; + } + { + const VectorContainerType testedVector( { 1, 2, 3 }, allocator_type() ); + const std::vector expectedVector = {1, 2, 3}; + if(!test::CheckEqualContainers(testedVector, expectedVector)) return false; + } + { + VectorContainerType testedVector = {1, 2, 3}; + testedVector = {11, 12, 13}; + + const std::vector expectedVector = {11, 12, 13}; + if(!test::CheckEqualContainers(testedVector, expectedVector)) return false; + } + + { + VectorContainerType testedVector = {1, 2, 3}; + testedVector.assign({5, 6, 7}); + + const std::vector expectedVector = {5, 6, 7}; + if(!test::CheckEqualContainers(testedVector, expectedVector)) return false; + } + + { + VectorContainerType testedVector = {1, 2, 3}; + testedVector.insert(testedVector.cend(), {5, 6, 7}); + + const std::vector expectedVector = {1, 2, 3, 5, 6, 7}; + if(!test::CheckEqualContainers(testedVector, expectedVector)) return false; + } + return true; +#else + return true; +#endif +} + +} //namespace test{ +} //namespace container { +} //namespace boost{ + +#include + +#endif //BOOST_CONTAINER_TEST_VECTOR_TEST_HEADER -- cgit v1.2.3