From 33d2f0f7afb93ae52346ee438d3ce340173776a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 7 Sep 2015 19:16:46 +0200 Subject: [PATCH] Add Polymorphic Memory Resource utilities and rework the separately compiled library: - Dlmalloc's based C function are boost_cont_xxx no longer exported, but wrapped into C++ linkage dlmalloc_xxx functions to effectively reuse Boost's dynamic library and autolink machinery instead of rewriting machinery to compile the C source file. - Refactored scoped_allocator_adaptor's construct logic as it was shared with polymorphic allocator's one. Moved common logic to detail/dispatch_uses_allocator.hpp. Refactored also scoped_allocator_adaptor test utilities to be reused with polymorphic_allocator tests. --- bench/bench_adaptive_node_pool.cpp | 14 +- bench/bench_alloc.cpp | 32 +- bench/bench_alloc_expand_bwd.cpp | 10 +- bench/bench_alloc_expand_fwd.cpp | 2 +- bench/bench_alloc_shrink_to_fit.cpp | 2 +- bench/bench_alloc_stable_vector_burst.cpp | 4 +- build/Jamfile.v2 | 5 +- doc/Jamfile.v2 | 3 + doc/container.qbk | 149 +++++- example/doc_pmr.cpp | 97 ++++ include/boost/container/adaptive_pool.hpp | 34 +- include/boost/container/allocator.hpp | 43 +- include/boost/container/container_fwd.hpp | 40 +- .../container/detail/adaptive_node_pool.hpp | 1 - include/boost/container/detail/alloc_lib.h | 122 ++--- .../container/detail/alloc_lib_auto_link.hpp | 24 - include/boost/container/detail/auto_link.hpp | 11 +- include/boost/container/detail/block_list.hpp | 139 +++++ .../boost/container/detail/block_slist.hpp | 157 ++++++ .../boost/container/detail/config_begin.hpp | 1 + .../detail/dispatch_uses_allocator.hpp | 293 +++++++++++ include/boost/container/detail/dlmalloc.hpp | 103 ++++ .../container/detail/pool_common_alloc.hpp | 12 +- .../boost/container/detail/pool_resource.hpp | 191 +++++++ .../boost/container/detail/type_traits.hpp | 2 + include/boost/container/detail/workaround.hpp | 21 +- include/boost/container/node_allocator.hpp | 24 +- include/boost/container/pmr/deque.hpp | 43 ++ include/boost/container/pmr/flat_map.hpp | 63 +++ include/boost/container/pmr/flat_set.hpp | 59 +++ .../boost/container/pmr/global_resource.hpp | 66 +++ include/boost/container/pmr/list.hpp | 43 ++ include/boost/container/pmr/map.hpp | 63 +++ .../boost/container/pmr/memory_resource.hpp | 101 ++++ .../pmr/monotonic_buffer_resource.hpp | 180 +++++++ .../container/pmr/polymorphic_allocator.hpp | 166 ++++++ include/boost/container/pmr/pool_options.hpp | 52 ++ .../boost/container/pmr/resource_adaptor.hpp | 193 +++++++ include/boost/container/pmr/set.hpp | 59 +++ include/boost/container/pmr/slist.hpp | 43 ++ include/boost/container/pmr/small_vector.hpp | 43 ++ include/boost/container/pmr/stable_vector.hpp | 43 ++ include/boost/container/pmr/string.hpp | 48 ++ .../pmr/synchronized_pool_resource.hpp | 138 +++++ .../pmr/unsynchronized_pool_resource.hpp | 194 +++++++ include/boost/container/pmr/vector.hpp | 43 ++ include/boost/container/scoped_allocator.hpp | 452 +--------------- .../boost/container/scoped_allocator_fwd.hpp | 31 +- include/boost/container/uses_allocator.hpp | 169 ++++++ .../boost/container/uses_allocator_fwd.hpp | 73 +++ proj/vc7ide/alloc_lib.vcproj | 57 +- proj/vc7ide/container.sln | 176 ++++++- proj/vc7ide/container.vcproj | 122 ++++- proj/vc7ide/doc_pmr.vcproj | 136 +++++ proj/vc7ide/global_resource.vcproj | 135 +++++ proj/vc7ide/memory_resource_test.vcproj | 135 +++++ .../monotonic_buffer_resource_test.vcproj | 137 +++++ proj/vc7ide/pmr_deque_test.vcproj | 136 +++++ proj/vc7ide/pmr_flat_map_test.vcproj | 136 +++++ proj/vc7ide/pmr_flat_set_test.vcproj | 136 +++++ proj/vc7ide/pmr_list_test.vcproj | 136 +++++ proj/vc7ide/pmr_map_test.vcproj | 136 +++++ proj/vc7ide/pmr_set_test.vcproj | 136 +++++ proj/vc7ide/pmr_slist_test.vcproj | 136 +++++ proj/vc7ide/pmr_small_vector_test.vcproj | 136 +++++ proj/vc7ide/pmr_stable_vector_test.vcproj | 136 +++++ proj/vc7ide/pmr_string_test.vcproj | 136 +++++ proj/vc7ide/pmr_vector_test.vcproj | 136 +++++ proj/vc7ide/polymorphic_allocator_test.vcproj | 135 +++++ proj/vc7ide/resource_adaptor.vcproj | 136 +++++ ...j => scoped_allocator_adaptor_test.vcproj} | 0 .../synchronized_pool_resource_test.vcproj | 136 +++++ .../unsynchronized_pool_resource_test.vcproj | 136 +++++ proj/vc7ide/uses_allocator_test.vcproj | 134 +++++ src/dlmalloc.cpp | 108 ++++ src/dlmalloc_ext_2_8_6.c | 83 ++- src/global_resource.cpp | 106 ++++ src/monotonic_buffer_resource.cpp | 154 ++++++ src/pool_resource.cpp | 291 +++++++++++ src/synchronized_pool_resource.cpp | 123 +++++ src/unsynchronized_pool_resource.cpp | 79 +++ test/Jamfile.v2 | 6 + test/alloc_basic_test.cpp | 46 +- test/alloc_full_test.cpp | 182 +++---- test/allocator_argument_tester.hpp | 233 +++++++++ test/derived_from_memory_resource.hpp | 87 ++++ test/global_resource_test.cpp | 116 +++++ test/memory_resource_logger.hpp | 86 +++ test/memory_resource_test.cpp | 135 +++++ test/monotonic_buffer_resource_test.cpp | 462 ++++++++++++++++ test/pmr_deque_test.cpp | 26 + test/pmr_flat_map_test.cpp | 26 + test/pmr_flat_set_test.cpp | 26 + test/pmr_list_test.cpp | 26 + test/pmr_map_test.cpp | 26 + test/pmr_set_test.cpp | 26 + test/pmr_slist_test.cpp | 26 + test/pmr_small_vector_test.cpp | 26 + test/pmr_stable_vector_test.cpp | 26 + test/pmr_static_vector_test.cpp | 26 + test/pmr_string_test.cpp | 31 ++ test/pmr_vector_test.cpp | 26 + test/polymorphic_allocator_test.cpp | 198 +++++++ test/pool_resource_test.hpp | 493 ++++++++++++++++++ test/propagation_test_allocator.hpp | 268 ++++++++++ test/resource_adaptor_test.cpp | 186 +++++++ test/scoped_allocator_adaptor_test.cpp | 450 ++++------------ test/synchronized_pool_resource_test.cpp | 19 + test/unsynchronized_pool_resource_test.cpp | 19 + test/uses_allocator_test.cpp | 84 +++ 110 files changed, 10143 insertions(+), 1160 deletions(-) create mode 100644 example/doc_pmr.cpp delete mode 100644 include/boost/container/detail/alloc_lib_auto_link.hpp create mode 100644 include/boost/container/detail/block_list.hpp create mode 100644 include/boost/container/detail/block_slist.hpp create mode 100644 include/boost/container/detail/dispatch_uses_allocator.hpp create mode 100644 include/boost/container/detail/dlmalloc.hpp create mode 100644 include/boost/container/detail/pool_resource.hpp create mode 100644 include/boost/container/pmr/deque.hpp create mode 100644 include/boost/container/pmr/flat_map.hpp create mode 100644 include/boost/container/pmr/flat_set.hpp create mode 100644 include/boost/container/pmr/global_resource.hpp create mode 100644 include/boost/container/pmr/list.hpp create mode 100644 include/boost/container/pmr/map.hpp create mode 100644 include/boost/container/pmr/memory_resource.hpp create mode 100644 include/boost/container/pmr/monotonic_buffer_resource.hpp create mode 100644 include/boost/container/pmr/polymorphic_allocator.hpp create mode 100644 include/boost/container/pmr/pool_options.hpp create mode 100644 include/boost/container/pmr/resource_adaptor.hpp create mode 100644 include/boost/container/pmr/set.hpp create mode 100644 include/boost/container/pmr/slist.hpp create mode 100644 include/boost/container/pmr/small_vector.hpp create mode 100644 include/boost/container/pmr/stable_vector.hpp create mode 100644 include/boost/container/pmr/string.hpp create mode 100644 include/boost/container/pmr/synchronized_pool_resource.hpp create mode 100644 include/boost/container/pmr/unsynchronized_pool_resource.hpp create mode 100644 include/boost/container/pmr/vector.hpp create mode 100644 include/boost/container/uses_allocator.hpp create mode 100644 include/boost/container/uses_allocator_fwd.hpp create mode 100644 proj/vc7ide/doc_pmr.vcproj create mode 100644 proj/vc7ide/global_resource.vcproj create mode 100644 proj/vc7ide/memory_resource_test.vcproj create mode 100644 proj/vc7ide/monotonic_buffer_resource_test.vcproj create mode 100644 proj/vc7ide/pmr_deque_test.vcproj create mode 100644 proj/vc7ide/pmr_flat_map_test.vcproj create mode 100644 proj/vc7ide/pmr_flat_set_test.vcproj create mode 100644 proj/vc7ide/pmr_list_test.vcproj create mode 100644 proj/vc7ide/pmr_map_test.vcproj create mode 100644 proj/vc7ide/pmr_set_test.vcproj create mode 100644 proj/vc7ide/pmr_slist_test.vcproj create mode 100644 proj/vc7ide/pmr_small_vector_test.vcproj create mode 100644 proj/vc7ide/pmr_stable_vector_test.vcproj create mode 100644 proj/vc7ide/pmr_string_test.vcproj create mode 100644 proj/vc7ide/pmr_vector_test.vcproj create mode 100644 proj/vc7ide/polymorphic_allocator_test.vcproj create mode 100644 proj/vc7ide/resource_adaptor.vcproj rename proj/vc7ide/{scoped_allocator_adaptor.vcproj => scoped_allocator_adaptor_test.vcproj} (100%) create mode 100644 proj/vc7ide/synchronized_pool_resource_test.vcproj create mode 100644 proj/vc7ide/unsynchronized_pool_resource_test.vcproj create mode 100644 proj/vc7ide/uses_allocator_test.vcproj create mode 100644 src/dlmalloc.cpp create mode 100644 src/global_resource.cpp create mode 100644 src/monotonic_buffer_resource.cpp create mode 100644 src/pool_resource.cpp create mode 100644 src/synchronized_pool_resource.cpp create mode 100644 src/unsynchronized_pool_resource.cpp create mode 100644 test/allocator_argument_tester.hpp create mode 100644 test/derived_from_memory_resource.hpp create mode 100644 test/global_resource_test.cpp create mode 100644 test/memory_resource_logger.hpp create mode 100644 test/memory_resource_test.cpp create mode 100644 test/monotonic_buffer_resource_test.cpp create mode 100644 test/pmr_deque_test.cpp create mode 100644 test/pmr_flat_map_test.cpp create mode 100644 test/pmr_flat_set_test.cpp create mode 100644 test/pmr_list_test.cpp create mode 100644 test/pmr_map_test.cpp create mode 100644 test/pmr_set_test.cpp create mode 100644 test/pmr_slist_test.cpp create mode 100644 test/pmr_small_vector_test.cpp create mode 100644 test/pmr_stable_vector_test.cpp create mode 100644 test/pmr_static_vector_test.cpp create mode 100644 test/pmr_string_test.cpp create mode 100644 test/pmr_vector_test.cpp create mode 100644 test/polymorphic_allocator_test.cpp create mode 100644 test/pool_resource_test.hpp create mode 100644 test/propagation_test_allocator.hpp create mode 100644 test/resource_adaptor_test.cpp create mode 100644 test/synchronized_pool_resource_test.cpp create mode 100644 test/unsynchronized_pool_resource_test.cpp create mode 100644 test/uses_allocator_test.cpp diff --git a/bench/bench_adaptive_node_pool.cpp b/bench/bench_adaptive_node_pool.cpp index 2085c07..eee5ac2 100644 --- a/bench/bench_adaptive_node_pool.cpp +++ b/bench/bench_adaptive_node_pool.cpp @@ -129,7 +129,7 @@ void list_test_template(std::size_t num_iterations, std::size_t num_elements, bo { typedef typename Allocator::template rebind::other IntAllocator; nanosecond_type tinsert, terase; - boost_cont_malloc_stats_t insert_stats, erase_stats; + 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); @@ -145,8 +145,8 @@ void list_test_template(std::size_t num_iterations, std::size_t num_elements, bo timer.stop(); tinsert = timer.elapsed().wall; - insert_inuse = boost_cont_in_use_memory(); - insert_stats = boost_cont_malloc_stats(); + insert_inuse = bc::dlmalloc_in_use_memory(); + insert_stats = bc::dlmalloc_malloc_stats(); /* iterator_t it(l.begin()); iterator_t last(--l.end()); @@ -175,8 +175,8 @@ void list_test_template(std::size_t num_iterations, std::size_t num_elements, bo } timer.stop(); terase = timer.elapsed().wall; - erase_inuse = boost_cont_in_use_memory(); - erase_stats = boost_cont_malloc_stats(); + erase_inuse = bc::dlmalloc_in_use_memory(); + erase_stats = bc::dlmalloc_malloc_stats(); } @@ -214,7 +214,7 @@ void list_test_template(std::size_t num_iterations, std::size_t num_elements, bo << " / " << (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' << boost_cont_in_use_memory() + << " system MB/inuse bytes after: " << (float)erase_stats.system_bytes/(1024*1024) << '\t' << bc::dlmalloc_in_use_memory() << std::endl << std::endl; } @@ -243,7 +243,7 @@ void list_test_template(std::size_t num_iterations, std::size_t num_elements, bo boost::container::container_detail::singleton_default ::instance().deallocate_free_blocks(); //Release dlmalloc memory - boost_cont_trim(0); + bc::dlmalloc_trim(0); } void print_header() diff --git a/bench/bench_alloc.cpp b/bench/bench_alloc.cpp index 689d75f..0ead0aa 100644 --- a/bench/bench_alloc.cpp +++ b/bench/bench_alloc.cpp @@ -12,7 +12,7 @@ #pragma warning (disable : 4512) #endif -#include +#include #define BOOST_INTERPROCESS_VECTOR_ALLOC_STATS @@ -24,6 +24,8 @@ 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) { @@ -50,23 +52,23 @@ void allocation_timing_test(unsigned int num_iterations, unsigned int num_elemen for(unsigned int r = 0; r != num_iterations; ++r){ void *first_mem = 0; if(m_mode != BOOST_CONTAINER_EXPAND_FWD) - first_mem = boost_cont_malloc(sizeof(POD)*num_elements*3/2); - void *addr = boost_cont_malloc(1*sizeof(POD)); + 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 = boost_cont_malloc(sizeof(POD)*num_elements*3/2); - capacity = boost_cont_size(addr)/sizeof(POD); - boost_cont_free(first_mem); + first_mem = dlmalloc_malloc(sizeof(POD)*num_elements*3/2); + capacity = dlmalloc_size(addr)/sizeof(POD); + dlmalloc_free(first_mem); ++numalloc; try{ - boost_cont_command_ret_t ret; + 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 = boost_cont_allocation_command + ret = dlmalloc_allocation_command ( m_mode, sizeof(POD) , min, max, &received_size, addr); if(!ret.first){ @@ -79,7 +81,7 @@ void allocation_timing_test(unsigned int num_iterations, unsigned int num_elemen std::cout << "m_mode != BOOST_CONTAINER_ALLOCATE_NEW!" << std::endl; return; } - boost_cont_free(addr); + dlmalloc_free(addr); addr = ret.first; ++numalloc; } @@ -95,16 +97,16 @@ void allocation_timing_test(unsigned int num_iterations, unsigned int num_elemen addr = ret.first; e = capacity + 1; } - boost_cont_free(addr); + dlmalloc_free(addr); } catch(...){ - boost_cont_free(addr); + dlmalloc_free(addr); throw; } } - assert( boost_cont_allocated_memory() == 0); - if(boost_cont_allocated_memory()!= 0){ + assert( dlmalloc_allocated_memory() == 0); + if(dlmalloc_allocated_memory()!= 0){ std::cout << "Memory leak!" << std::endl; return; } @@ -122,7 +124,7 @@ void allocation_timing_test(unsigned int num_iterations, unsigned int num_elemen << (float(numalloc) + float(numexpand))/num_iterations << "(" << float(numalloc)/num_iterations << "/" << float(numexpand)/num_iterations << ")" << std::endl << std::endl; - boost_cont_trim(0); + dlmalloc_trim(0); } } @@ -169,7 +171,7 @@ int allocation_loop() int main() { - boost_cont_mallopt( (-3)//M_MMAP_THRESHOLD + dlmalloc_mallopt( (-3)//M_MMAP_THRESHOLD , 100*10000000); //allocation_loop >(); //allocation_loop >(); diff --git a/bench/bench_alloc_expand_bwd.cpp b/bench/bench_alloc_expand_bwd.cpp index b598ede..42b6f81 100644 --- a/bench/bench_alloc_expand_bwd.cpp +++ b/bench/bench_alloc_expand_bwd.cpp @@ -109,9 +109,9 @@ void vector_test_template(unsigned int num_iterations, unsigned int num_elements v.reset_alloc_stats(); void *first_mem = 0; try{ - first_mem = boost_cont_malloc(sizeof(MyInt)*num_elements*3/2); + first_mem = bc::dlmalloc_malloc(sizeof(MyInt)*num_elements*3/2); v.push_back(MyInt(0)); - boost_cont_free(first_mem); + bc::dlmalloc_free(first_mem); for(unsigned int e = 0; e != num_elements; ++e){ v.push_back(MyInt(e)); @@ -121,12 +121,12 @@ void vector_test_template(unsigned int num_iterations, unsigned int num_elements capacity = static_cast(v.capacity()); } catch(...){ - boost_cont_free(first_mem); + bc::dlmalloc_free(first_mem); throw; } } - assert(boost_cont_allocated_memory() == 0); + assert(bc::dlmalloc_allocated_memory() == 0); timer.stop(); nanosecond_type nseconds = timer.elapsed().wall; @@ -165,7 +165,7 @@ void vector_test_template(unsigned int num_iterations, unsigned int num_elements << " ----------------------------------- " << std::endl; } - boost_cont_trim(0); + bc::dlmalloc_trim(0); } int main(int argc, const char *argv[]) diff --git a/bench/bench_alloc_expand_fwd.cpp b/bench/bench_alloc_expand_fwd.cpp index b3108bc..4a0b1ee 100644 --- a/bench/bench_alloc_expand_fwd.cpp +++ b/bench/bench_alloc_expand_fwd.cpp @@ -223,7 +223,7 @@ void vector_test_template(unsigned int num_iterations, unsigned int num_elements << "(" << float(numalloc)/num_iterations << "/" << float(numexpand)/num_iterations << ")" << std::endl << std::endl; } - boost_cont_trim(0); + bc::dlmalloc_trim(0); } void print_header() diff --git a/bench/bench_alloc_shrink_to_fit.cpp b/bench/bench_alloc_shrink_to_fit.cpp index d8a9404..696f29b 100644 --- a/bench/bench_alloc_shrink_to_fit.cpp +++ b/bench/bench_alloc_shrink_to_fit.cpp @@ -126,7 +126,7 @@ void vector_test_template(unsigned int num_iterations, unsigned int num_elements << float(nseconds)/(num_iterations*num_elements) << std::endl << std::endl; } - boost_cont_trim(0); + bc::dlmalloc_trim(0); } int main(int argc, const char *argv[]) diff --git a/bench/bench_alloc_stable_vector_burst.cpp b/bench/bench_alloc_stable_vector_burst.cpp index cbbde70..c1984ba 100644 --- a/bench/bench_alloc_stable_vector_burst.cpp +++ b/bench/bench_alloc_stable_vector_burst.cpp @@ -174,8 +174,8 @@ void stable_vector_test_template(unsigned int num_iterations, unsigned int num_e << " (" << (float(top_capacity)/float(num_iterations*num_elements) - 1)*100 << " %)"*/ << std::endl << std::endl; } - assert(boost_cont_all_deallocated()); - boost_cont_trim(0); + assert(bc::dlmalloc_all_deallocated()); + bc::dlmalloc_trim(0); } void print_header() diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 6d3e9fd..d6494ea 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -11,11 +11,8 @@ project boost/container static:BOOST_CONTAINER_STATIC_LINK=1 ; -# Base names of the source files for libboost_container -CPP_SOURCES = alloc_lib ; - lib boost_container - : $(CPP_SOURCES).c + : alloc_lib.c [ glob *.cpp ] : shared:BOOST_CONTAINER_DYN_LINK=1 static:BOOST_CONTAINER_STATIC_LINK=1 ; diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index c684eaa..63cdb55 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -18,6 +18,7 @@ path-constant here : . ; doxygen autodoc : [ glob ../../../boost/container/*.hpp ] + [ glob ../../../boost/container/pmr/*.hpp ] : EXTRACT_ALL=NO HIDE_UNDOC_MEMBERS=YES @@ -26,6 +27,7 @@ doxygen autodoc EXPAND_ONLY_PREDEF=YES MACRO_EXPANSION=YES "PREDEFINED=\"insert_const_ref_type= const T&\" \\ + \"BOOST_CONSTEXPR_OR_CONST=constexpr\" \\ \"BOOST_CONTAINER_DOXYGEN_INVOKED\" \\ \"BOOST_CONTAINER_IMPDEF(T)=implementation_defined\" \\ \"BOOST_CONTAINER_SEEDOC(T)=see_documentation\" \\ @@ -42,6 +44,7 @@ doxygen autodoc \"BOOST_CONTAINER_DOCONLY(T)=T\"\\ \"BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE=\"\\ \"BOOST_CONTAINER_SCOPEDALLOC_ALLINNER=InnerAllocs...\"\\ + \"BOOST_CONTAINER_DECL=\"\\ " "boost.doxygen.reftitle=Boost.Container Header Reference" ; diff --git a/doc/container.qbk b/doc/container.qbk index b86deb8..a92b783 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -8,7 +8,7 @@ [library Boost.Container [quickbook 1.5] [authors [Gaztanaga, Ion]] - [copyright 2009-2013 Ion Gaztanaga] + [copyright 2009-2015 Ion Gaztanaga] [id container] [dirname container] [purpose Containers library] @@ -27,7 +27,7 @@ [*Boost.Container] library implements several well-known containers, including STL containers. The aim of the library is to offers advanced features not present in standard containers or to offer the latest standard draft features for compilers -that comply with C++03. +that don't comply with the latest C++ standard. In short, what does [*Boost.Container] offer? @@ -49,13 +49,16 @@ In short, what does [*Boost.Container] offer? [section:introduction_building_container Building Boost.Container] -There is no need to compile [*Boost.Container] if you don't use [link container.extended_functionality.extended_allocators Extended Allocators] -since in that case it's a header-only library. Just include your Boost header directory in your compiler include path. +There is no need to compile [*Boost.Container], since it's a header-only library, +just include your Boost header directory in your compiler include path *except if you use*: -[link container.extended_functionality.extended_allocators Extended Allocators] are -implemented as a separately compiled library, so you must install binaries in a location that can be found by your linker -when using these classes. If you followed the [@http://www.boost.org/doc/libs/release/more/getting_started/index.html Boost Getting Started] instructions, -that's already been done for you. +* [link container.extended_functionality.extended_allocators Extended Allocators] +* Some [link container.extended_functionality.polymorphic_memory_resources Polymorphic Memory Resources] classes. + +Those exceptions are are implemented as a separately compiled library, so in those cases you must install binaries +in a location that can be found by your linker. +If you followed the [@http://www.boost.org/doc/libs/release/more/getting_started/index.html Boost Getting Started] +instructions, that's already been done for you. [endsect] @@ -672,11 +675,7 @@ allocator and offers an C API to implement memory expansion and burst allocation and speed efficient, and this allocator is used as the basis of many malloc implementations, including multithreaded allocators built above DLmalloc (See [@http://www.malloc.de/en/ ptmalloc2, ptmalloc3] or [@http://www.nedprod.com/programs/portable/nedmalloc/ nedmalloc]). This low-level allocator is implemented as -a separately compiled library whereas [classref boost::container::allocator allocator], -[classref boost::container::adaptive_pool adaptive_pool] and [classref boost::container::node_allocator node_allocator] -are header-only classes. - -The following extended allocators are provided: +a separately compiled library and the following extended allocators depend on the library: * [classref boost::container::allocator allocator]: This extended allocator offers expansion, shrink-in place and burst allocation capabilities implemented as a thin wrapper around the modified DLMalloc. @@ -702,6 +701,124 @@ Use them simply specifying the new allocator in the corresponding template argum [endsect] +[section:polymorphic_memory_resources Polymorphic Memory Resources ] + +The document +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html C++ Extensions for Library Fundamentals (Final draft: N4480)] +includes classes that provide allocator type erasure and runtime polymorphism. As Pablo Halpern, the author of the proposal, +explains in the paper ([@https://isocpp.org/files/papers/N3916.pdf N3916 Polymorphic Memory Resources (r2)]): + +["['A significant impediment to effective memory management in C++ has been the +inability to use allocators in non-generic contexts. In large software systems, +most of the application program consists of non-generic procedural or +object-oriented code that is compiled once and linked many times.]] + +["['Allocators in C++, however, have historically relied solely on +compile-time polymorphism, and therefore have not been suitable for use in vocabulary +types, which are passed through interfaces between separately-compiled modules, +because the allocator type necessarily affects the type of the object that uses it. +This proposal builds upon the improvements made to allocators in +C++11 and describes a set of facilities for runtime polymorphic memory +resources that interoperate with the existing compile-time polymorphic +allocators.]] + +[*Boost.Container] implements nearly all classes of the proposal under +the namespace `boost::container::pmr`. There are two groups, + +* Header only utilities (these don't require the separately compiled library): + * [classref boost::container::pmr::memory_resource memory_resource]. + * [classref boost::container::pmr::resource_adaptor resource_adaptor]. + +* Utilities that require the the separately compiled library: + * [classref boost::container::pmr::polymorphic_allocator polymorphic_allocator]. + * [classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource]. + * [classref boost::container::pmr::unsynchronized_pool_resource unsynchronized_pool_resource]. + * [classref boost::container::pmr::synchronized_pool_resource synchronized_pool_resource]. + * Global resource functions: [funcref boost::container::pmr::get_default_resource get_default_resource]/ + [funcref boost::container::pmr::set_default_resource set_default_resource]/ + [funcref boost::container::pmr::new_delete_resource new_delete_resource]/ + [funcref boost::container::pmr::null_memory_resource null_memory_resource] + * Aliases for boost containers using the polymorphic allocator + (like [classref boost::container::pmr::vector pmr::vector], etc.) + +[*Boost.Container]'s polymorphic resource library is usable from C++03 containers, +and offers some alternative utilities if the required C++11 features of the +['Library Fundamentals] specification are not available. + +[import ../example/doc_pmr.cpp] + +Let's review the usage example given in +[@https://isocpp.org/files/papers/N3916.pdf N3916] and see how it can be implemented +using [*Boost.Container]: ['Suppose we are processing a series of shopping lists, where a shopping list is a +container of strings, and storing them in a collection (a list) of shopping lists. +Each shopping list being processed uses a bounded amount of memory that is needed for +a short period of time, while the collection of shopping lists uses an unbounded +amount of memory and will exist for a longer period of time. For efficiency, we can +use a more time-efficient memory allocator based on a finite buffer for the temporary +shopping lists.] + +Let's see how `ShoppingList` can be defined to support an polymorphic memory resource +that can allocate memory from different underlying mechanisms. The most important +details are: + +* It should declare that supports an allocator defining an `allocator_type` typedef. + This `allocator_type` will be of type [classref boost::container::pmr::memory_resource memory_resource *], + which is a base class for polymorphic resources. +* It must define constructors that take the + the allocator as argument. It can be implemented in two ways: + * `ShoppingList` has constructors taking + [classref boost::container::pmr::memory_resource memory_resource*] as the last argument. + * `ShoppingList` has constructors taking + [classref boost::container::allocator_arg_t allocator_arg_t] as the first argument + and [classref boost::container::pmr::memory_resource memory_resource*] as the second argument. + +[*Note:] ['In C++03 compilers, it is required that the programmer specializes as `true` +[classref boost::container::constructible_with_allocator_suffix constructible_with_allocator_suffix] or +[classref boost::container::constructible_with_allocator_prefix constructible_with_allocator_prefix] +as in C++03 there is no way to automatically detect the chosen option at compile time. If +no specialization is done, [*Boost.Container] assumes the suffix option]. + +[doc_pmr_ShoppingList_hpp] + +['However, this time-efficient allocator is not appropriate for the longer +lived collection of shopping lists. This example shows how those temporary shopping +lists, using a time-efficient allocator, can be used to populate the long lived collection +of shopping lists, using a general purpose allocator, something that would be +annoyingly difficult without the polymorphic allocators.] + +In [*Boost.Container] for the time-efficient allocation we can use +[classref boost::container::pmr::monotonic_buffer_resource monotonic_buffer_resource], +providing an external buffer that will be used until it's exhausted. In the default +configuration, when the buffer is exhausted, the default memory resource will be used +instead. + +[doc_pmr_main_cpp] + +['Notice that the shopping lists within `folder` use the default allocator resource +whereas the shopping list `temporaryShoppingList` uses the short-lived but very fast +`buf_rsrc`. Despite using different allocators, you can insert +`temporaryShoppingList` into folder because they have the same `ShoppingList` +type. Also, while `ShoppingList` uses memory_resource directly, +[classref boost::container::pmr::list pmr::list], +[classref boost::container::pmr::vector pmr::vector] +and [classref boost::container::pmr::string pmr::string] all use +[classref boost::container::pmr::polymorphic_allocator polymorphic_allocator].] + +['The resource passed to the `ShoppingList` constructor is propagated to the vector and +each string within that `ShoppingList`. Similarly, the resource used to construct +`folder` is propagated to the constructors of the ShoppingLists that are inserted into +the list (and to the strings within those `ShoppingLists`). The +[classref boost::container::pmr::polymorphic_allocator polymorphic_allocator] +template is designed to be almost interchangeable with a pointer to +[classref boost::container::pmr::memory_resource memory_resource], +thus producing a ['bridge] between the template-policy +style of allocator and the polymorphic-base-class style of allocator.] + +This example actually shows how easy is to use [*Boost.Container] to write +type-erasured allocator-capable classes even in C++03 compilers. + +[endsect] + [/ /a__section:previous_element_slist Previous element for slist__a / @@ -1096,6 +1213,12 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_60_00 Boost 1.60 Release] + +* Implemented [link container.extended_functionality.polymorphic_memory_resources Polymorphic Memory Resources]. + +[endsect] + [section:release_notes_boost_1_59_00 Boost 1.59 Release] * [@https://github.com/boostorg/container/pull/26 GitHub #26: ['Fix bug in stable_vector::capacity()]]. Thanks to timsong-cpp/Arindam Mukerjee. diff --git a/example/doc_pmr.cpp b/example/doc_pmr.cpp new file mode 100644 index 0000000..e7fea00 --- /dev/null +++ b/example/doc_pmr.cpp @@ -0,0 +1,97 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/include/boost/container/adaptive_pool.hpp b/include/boost/container/adaptive_pool.hpp index 59ba37b..ac3d867 100644 --- a/include/boost/container/adaptive_pool.hpp +++ b/include/boost/container/adaptive_pool.hpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -164,7 +164,7 @@ class adaptive_pool return pointer(static_cast(singleton_t::instance().allocate_node())); } else{ - return static_cast(boost_cont_malloc(count*sizeof(T))); + return static_cast(dlmalloc_malloc(count*sizeof(T))); } } @@ -180,7 +180,7 @@ class adaptive_pool singleton_t::instance().deallocate_node(ptr); } else{ - boost_cont_free(ptr); + dlmalloc_free(ptr); } } @@ -198,7 +198,7 @@ class adaptive_pool //!Returns maximum the number of objects the previously allocated memory //!pointed by p can hold. size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW - { return boost_cont_size(p); } + { return dlmalloc_size(p); } //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -251,17 +251,17 @@ class adaptive_pool void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) { BOOST_STATIC_ASSERT(( Version > 1 ));/* - boost_cont_memchain ch; + dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(BOOST_UNLIKELY(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ - if(BOOST_UNLIKELY(!boost_cont_multialloc_nodes - (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes + (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ boost::container::throw_bad_alloc(); } } @@ -271,29 +271,29 @@ class adaptive_pool void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) { BOOST_STATIC_ASSERT(( Version > 1 ));/* - boost_cont_memchain ch; + dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(BOOST_UNLIKELY(!boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ - if(BOOST_UNLIKELY(!boost_cont_multialloc_arrays - (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays + (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ boost::container::throw_bad_alloc(); } } void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW {/* - boost_cont_memchain ch; + dlmalloc_memchain ch; void *beg(&*chain.begin()), *last(&*chain.last()); size_t size(chain.size()); BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); - boost_cont_multidealloc(&ch);*/ - boost_cont_multidealloc(reinterpret_cast(&chain)); + dlmalloc_multidealloc(&ch);*/ + dlmalloc_multidealloc(reinterpret_cast(&chain)); } //!Deallocates all free blocks of the pool @@ -326,7 +326,7 @@ class adaptive_pool ,size_type &prefer_in_recvd_out_size, pointer &reuse_ptr) { std::size_t const preferred_size = prefer_in_recvd_out_size; - boost_cont_command_ret_t ret = {0 , 0}; + dlmalloc_command_ret_t ret = {0 , 0}; if(BOOST_UNLIKELY(limit_size > this->max_size() || preferred_size > this->max_size())){ return pointer(); } @@ -335,7 +335,7 @@ class adaptive_pool std::size_t r_size; { void* reuse_ptr_void = reuse_ptr; - ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); + ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); reuse_ptr = ret.second ? static_cast(reuse_ptr_void) : 0; } prefer_in_recvd_out_size = r_size/sizeof(T); diff --git a/include/boost/container/allocator.hpp b/include/boost/container/allocator.hpp index 9f757c7..2fb44b7 100644 --- a/include/boost/container/allocator.hpp +++ b/include/boost/container/allocator.hpp @@ -24,12 +24,14 @@ #include #include #include -#include +#include #include #include #include #include +//!\file + namespace boost { namespace container { @@ -86,21 +88,18 @@ class allocator #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -//!\file //! This class is an extended STL-compatible that offers advanced allocation mechanism //!(in-place expansion, shrinking, burst-allocation...) //! //! This allocator is a wrapper around a modified DLmalloc. -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template -#else //! If Version is 1, the allocator is a STL conforming allocator. If Version is 2, //! the allocator offers advanced expand in place and burst allocation capabilities. -// +//! //! AllocationDisableMask works only if Version is 2 and it can be an inclusive OR //! of allocation types the user wants to disable. -template -#endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +template< class T + , unsigned Version BOOST_CONTAINER_DOCONLY(=2) + , unsigned int AllocationDisableMask BOOST_CONTAINER_DOCONLY(=0)> class allocator { typedef unsigned int allocation_type; @@ -186,7 +185,7 @@ class allocator (void)hint; if(count > this->max_size()) boost::container::throw_bad_alloc(); - void *ret = boost_cont_malloc(count*sizeof(T)); + void *ret = dlmalloc_malloc(count*sizeof(T)); if(!ret) boost::container::throw_bad_alloc(); return static_cast(ret); @@ -195,7 +194,7 @@ class allocator //!Deallocates previously allocated memory. //!Never throws void deallocate(pointer ptr, size_type) BOOST_NOEXCEPT_OR_NOTHROW - { boost_cont_free(ptr); } + { dlmalloc_free(ptr); } //!Returns the maximum number of elements that could be allocated. //!Never throws @@ -243,7 +242,7 @@ class allocator size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_STATIC_ASSERT(( Version > 1 )); - return boost_cont_size(p); + return dlmalloc_size(p); } //!Allocates just one object. Memory allocated with this function @@ -289,16 +288,16 @@ class allocator void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) { BOOST_STATIC_ASSERT(( Version > 1 ));/* - boost_cont_memchain ch; + dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ + if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ - if(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ + if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ boost::container::throw_bad_alloc(); } } @@ -309,9 +308,9 @@ class allocator void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) { BOOST_STATIC_ASSERT(( Version > 1 )); - boost_cont_memchain ch; + dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(!boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ + if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ boost::container::throw_bad_alloc(); } chain.incorporate_after(chain.before_begin() @@ -319,7 +318,7 @@ class allocator ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); /* - if(!boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ + if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ boost::container::throw_bad_alloc(); }*/ } @@ -330,12 +329,12 @@ class allocator void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_STATIC_ASSERT(( Version > 1 )); - boost_cont_memchain ch; + dlmalloc_memchain ch; void *beg(&*chain.begin()), *last(&*chain.last()); size_t size(chain.size()); BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); - boost_cont_multidealloc(&ch); - //boost_cont_multidealloc(reinterpret_cast(&chain)); + dlmalloc_multidealloc(&ch); + //dlmalloc_multidealloc(reinterpret_cast(&chain)); } private: @@ -346,7 +345,7 @@ class allocator ,pointer &reuse_ptr) { std::size_t const preferred_size = prefer_in_recvd_out_size; - boost_cont_command_ret_t ret = {0 , 0}; + dlmalloc_command_ret_t ret = {0 , 0}; if((limit_size > this->max_size()) | (preferred_size > this->max_size())){ return pointer(); } @@ -355,7 +354,7 @@ class allocator std::size_t r_size; { void* reuse_ptr_void = reuse_ptr; - ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); + ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); reuse_ptr = ret.second ? static_cast(reuse_ptr_void) : 0; } prefer_in_recvd_out_size = r_size/sizeof(T); diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index a9b421c..e85a6ce 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -24,6 +24,7 @@ //! - boost::container::vector //! - boost::container::stable_vector //! - boost::container::static_vector +//! - boost::container::small_vector //! - boost::container::slist //! - boost::container::list //! - boost::container::set @@ -38,11 +39,19 @@ //! - boost::container::string //! - boost::container::wstring //! -//! It forward declares the following allocators: +//! Forward declares the following allocators: //! - boost::container::allocator //! - boost::container::node_allocator //! - boost::container::adaptive_pool //! +//! Forward declares the following polymorphic resource classes: +//! - boost::container::pmr::memory_resource +//! - boost::container::pmr::polymorphic_allocator +//! - boost::container::pmr::monotonic_buffer_resource +//! - boost::container::pmr::pool_options +//! - boost::container::pmr::unsynchronized_pool_resource +//! - boost::container::pmr::synchronized_pool_resource +//! //! And finally it defines the following types #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -54,11 +63,18 @@ namespace boost{ namespace intrusive{ +namespace detail{ //Create namespace to avoid compilation errors -}} +}}} namespace boost{ namespace container{ namespace container_detail{ namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +namespace boost{ namespace container{ namespace pmr{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; }}} #include @@ -210,6 +226,26 @@ template , std::size_t Version = 2> class node_allocator; +namespace pmr { + +class memory_resource; + +template +class polymorphic_allocator; + +class monotonic_buffer_resource; + +struct pool_options; + +template +class resource_adaptor_imp; + +class unsynchronized_pool_resource; + +class synchronized_pool_resource; + +} //namespace pmr { + #else //! Default options for tree-based associative containers diff --git a/include/boost/container/detail/adaptive_node_pool.hpp b/include/boost/container/detail/adaptive_node_pool.hpp index 4a1f07c..2069610 100644 --- a/include/boost/container/detail/adaptive_node_pool.hpp +++ b/include/boost/container/detail/adaptive_node_pool.hpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/include/boost/container/detail/alloc_lib.h b/include/boost/container/detail/alloc_lib.h index 4802d9d..950ff72 100644 --- a/include/boost/container/detail/alloc_lib.h +++ b/include/boost/container/detail/alloc_lib.h @@ -15,27 +15,6 @@ #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable : 4127) - -/* - we need to import/export our code only if the user has specifically - asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost - libraries to be dynamically linked, or BOOST_CONTAINER_DYN_LINK - if they want just this one to be dynamically liked: -*/ -#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) - -/* export if this is our own source, otherwise import: */ -#ifdef BOOST_CONTAINER_SOURCE -# define BOOST_CONTAINER_DECL __declspec(dllexport) -#else -# define BOOST_CONTAINER_DECL __declspec(dllimport) -#endif /* BOOST_CONTAINER_SOURCE */ -#endif /* DYN_LINK */ -#endif /* _MSC_VER */ - -/* if BOOST_CONTAINER_DECL isn't defined yet define it now: */ -#ifndef BOOST_CONTAINER_DECL -#define BOOST_CONTAINER_DECL #endif #ifdef __cplusplus @@ -215,14 +194,6 @@ typedef struct boost_cont_memchain_impl }while(0)\ /**/ -BOOST_CONTAINER_DECL size_t boost_cont_size(const void *p); - -BOOST_CONTAINER_DECL void* boost_cont_malloc(size_t bytes); - -BOOST_CONTAINER_DECL void boost_cont_free(void* mem); - -BOOST_CONTAINER_DECL void* boost_cont_memalign(size_t bytes, size_t alignment); - /*!Indicates the all elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays must be contiguous.*/ #define DL_MULTIALLOC_ALL_CONTIGUOUS ((size_t)(-1)) @@ -231,22 +202,6 @@ BOOST_CONTAINER_DECL void* boost_cont_memalign(size_t bytes, size_t alignment); should be selected by those functions.*/ #define DL_MULTIALLOC_DEFAULT_CONTIGUOUS ((size_t)(0)) -BOOST_CONTAINER_DECL int boost_cont_multialloc_nodes - (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain); - -BOOST_CONTAINER_DECL int boost_cont_multialloc_arrays - (size_t n_elements, const size_t *sizes, size_t sizeof_element, size_t contiguous_elements, boost_cont_memchain *pchain); - -BOOST_CONTAINER_DECL void boost_cont_multidealloc(boost_cont_memchain *pchain); - -BOOST_CONTAINER_DECL size_t boost_cont_footprint(); - -BOOST_CONTAINER_DECL size_t boost_cont_allocated_memory(); - -BOOST_CONTAINER_DECL size_t boost_cont_chunksize(const void *p); - -BOOST_CONTAINER_DECL int boost_cont_all_deallocated(); - typedef struct boost_cont_malloc_stats_impl { size_t max_system_bytes; @@ -254,26 +209,6 @@ typedef struct boost_cont_malloc_stats_impl size_t in_use_bytes; } boost_cont_malloc_stats_t; -BOOST_CONTAINER_DECL boost_cont_malloc_stats_t boost_cont_malloc_stats(); - -BOOST_CONTAINER_DECL size_t boost_cont_in_use_memory(); - -BOOST_CONTAINER_DECL int boost_cont_trim(size_t pad); - -BOOST_CONTAINER_DECL int boost_cont_mallopt - (int parameter_number, int parameter_value); - -BOOST_CONTAINER_DECL int boost_cont_grow - (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received); - -BOOST_CONTAINER_DECL int boost_cont_shrink - (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit); - -BOOST_CONTAINER_DECL void* boost_cont_alloc - (size_t minbytes, size_t preferred_bytes, size_t *received_bytes); - -BOOST_CONTAINER_DECL int boost_cont_malloc_check(); - typedef unsigned int allocation_type; enum @@ -303,7 +238,50 @@ typedef struct boost_cont_command_ret_impl int second; }boost_cont_command_ret_t; -BOOST_CONTAINER_DECL boost_cont_command_ret_t boost_cont_allocation_command +size_t boost_cont_size(const void *p); + +void* boost_cont_malloc(size_t bytes); + +void boost_cont_free(void* mem); + +void* boost_cont_memalign(size_t bytes, size_t alignment); + +int boost_cont_multialloc_nodes + (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain); + +int boost_cont_multialloc_arrays + (size_t n_elements, const size_t *sizes, size_t sizeof_element, size_t contiguous_elements, boost_cont_memchain *pchain); + +void boost_cont_multidealloc(boost_cont_memchain *pchain); + +size_t boost_cont_footprint(); + +size_t boost_cont_allocated_memory(); + +size_t boost_cont_chunksize(const void *p); + +int boost_cont_all_deallocated(); + +boost_cont_malloc_stats_t boost_cont_malloc_stats(); + +size_t boost_cont_in_use_memory(); + +int boost_cont_trim(size_t pad); + +int boost_cont_mallopt(int parameter_number, int parameter_value); + +int boost_cont_grow + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received); + +int boost_cont_shrink + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit); + +void* boost_cont_alloc + (size_t minbytes, size_t preferred_bytes, size_t *received_bytes); + +int boost_cont_malloc_check(); + +boost_cont_command_ret_t boost_cont_allocation_command ( allocation_type command , size_t sizeof_object , size_t limit_objects @@ -312,7 +290,17 @@ BOOST_CONTAINER_DECL boost_cont_command_ret_t boost_cont_allocation_command , void *reuse_ptr ); -BOOST_CONTAINER_DECL int boost_cont_mallopt(int param_number, int value); +void *boost_cont_sync_create(); + +void boost_cont_sync_destroy(void *sync); + +int boost_cont_sync_lock(void *sync); + +void boost_cont_sync_unlock(void *sync); + +int boost_cont_global_sync_lock(); + +void boost_cont_global_sync_unlock(); #ifdef __cplusplus } //extern "C" { diff --git a/include/boost/container/detail/alloc_lib_auto_link.hpp b/include/boost/container/detail/alloc_lib_auto_link.hpp deleted file mode 100644 index aea99a6..0000000 --- a/include/boost/container/detail/alloc_lib_auto_link.hpp +++ /dev/null @@ -1,24 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_DETAIL_BOOST_CONT_EXT_AUTO_LINK_HPP -#define BOOST_CONTAINER_DETAIL_BOOST_CONT_EXT_AUTO_LINK_HPP - -#ifndef BOOST_CONFIG_HPP -# include -#endif - -#if defined(BOOST_HAS_PRAGMA_ONCE) -# pragma once -#endif - -#include -#include - -#endif //#ifndef BOOST_CONTAINER_DETAIL_BOOST_CONT_EXT_AUTO_LINK_HPP diff --git a/include/boost/container/detail/auto_link.hpp b/include/boost/container/detail/auto_link.hpp index da078e8..264b1ba 100644 --- a/include/boost/container/detail/auto_link.hpp +++ b/include/boost/container/detail/auto_link.hpp @@ -18,6 +18,13 @@ # pragma once #endif +//Define BOOST_CONTAINER_DYNAMIC_LINKING which is independent from BOOST_*_NO_LIB +//and is needed is some tests that need to disable some checks (like operator new replacements) +//that don't work across DLL boundaries +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) +# define BOOST_CONTAINER_DYNAMIC_LINKING +#endif + // // Automatically link to the correct build variant where possible. // @@ -27,12 +34,14 @@ // once it's done with it: // #define BOOST_LIB_NAME boost_container + // // If we're importing code from a dll, then tell auto_link.hpp about it: // -#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) +#if defined(BOOST_CONTAINER_DYNAMIC_LINKING) # define BOOST_DYN_LINK #endif + // // And include the header that does the work: // diff --git a/include/boost/container/detail/block_list.hpp b/include/boost/container/detail/block_list.hpp new file mode 100644 index 0000000..1a6057c --- /dev/null +++ b/include/boost/container/detail/block_list.hpp @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_DETAIL_BLOCK_LIST_HEADER +#define BOOST_CONTAINER_DETAIL_BLOCK_LIST_HEADER + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +struct list_node +{ + list_node *next; + list_node *previous; +}; + +struct list_node_traits +{ + typedef list_node node; + typedef list_node* node_ptr; + typedef const list_node* const_node_ptr; + + static node_ptr get_next(const_node_ptr n) + { return n->next; } + + static node_ptr get_previous(const_node_ptr n) + { return n->previous; } + + static void set_next(const node_ptr & n, const node_ptr & next) + { n->next = next; } + + static void set_previous(const node_ptr & n, const node_ptr & previous) + { n->previous = previous; } +}; + +struct block_list_header + : public list_node +{ + std::size_t size; +}; + +typedef bi::circular_list_algorithms list_algo; + + +template +class block_list_base +{ + list_node m_list; + + static const std::size_t MaxAlignMinus1 = memory_resource::max_align-1u; + + public: + + static const std::size_t header_size = std::size_t(sizeof(DerivedFromBlockListHeader) + MaxAlignMinus1) & std::size_t(~MaxAlignMinus1); + + explicit block_list_base() + { list_algo::init_header(&m_list); } + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + block_list_base(const block_list_base&) = delete; + block_list_base operator=(const block_list_base&) = delete; + #else + private: + block_list_base (const block_list_base&); + block_list_base operator=(const block_list_base&); + public: + #endif + + ~block_list_base() + {} + + void *allocate(std::size_t size, memory_resource &mr) + { + if((size_t(-1) - header_size) < size) + throw_bad_alloc(); + void *p = mr.allocate(size+header_size); + block_list_header &mb = *::new((void*)p) DerivedFromBlockListHeader; + mb.size = size+header_size; + list_algo::link_after(&m_list, &mb); + return (char *)p + header_size; + } + + void deallocate(void *p, memory_resource &mr) BOOST_NOEXCEPT + { + DerivedFromBlockListHeader *pheader = static_cast + (static_cast((char*)p - header_size)); + list_algo::unlink(pheader); + const std::size_t size = pheader->size; + static_cast(pheader)->~DerivedFromBlockListHeader(); + mr.deallocate(pheader, size, memory_resource::max_align); + } + + void release(memory_resource &mr) BOOST_NOEXCEPT + { + list_node *n = list_algo::node_traits::get_next(&m_list); + while(n != &m_list){ + DerivedFromBlockListHeader &d = static_cast(*n); + n = list_algo::node_traits::get_next(n); + std::size_t size = d.size; + d.~DerivedFromBlockListHeader(); + mr.deallocate(reinterpret_cast(&d), size, memory_resource::max_align); + } + list_algo::init_header(&m_list); + } +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_DETAIL_BLOCK_LIST_HEADER diff --git a/include/boost/container/detail/block_slist.hpp b/include/boost/container/detail/block_slist.hpp new file mode 100644 index 0000000..278e641 --- /dev/null +++ b/include/boost/container/detail/block_slist.hpp @@ -0,0 +1,157 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_DETAIL_BLOCK_SLIST_HEADER +#define BOOST_CONTAINER_DETAIL_BLOCK_SLIST_HEADER + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +struct slist_node +{ + slist_node *next; +}; + +struct slist_node_traits +{ + typedef slist_node node; + typedef slist_node* node_ptr; + typedef const slist_node* const_node_ptr; + + static node_ptr get_next(const_node_ptr n) + { return n->next; } + + static void set_next(const node_ptr & n, const node_ptr & next) + { n->next = next; } +}; + +struct block_slist_header + : public slist_node +{ + std::size_t size; +}; + +typedef bi::linear_slist_algorithms slist_algo; + +template +class block_slist_base +{ + slist_node m_slist; + + static const std::size_t MaxAlignMinus1 = memory_resource::max_align-1u; + + public: + + static const std::size_t header_size = std::size_t(sizeof(DerivedFromBlockSlistHeader) + MaxAlignMinus1) & std::size_t(~MaxAlignMinus1); + + explicit block_slist_base() + { slist_algo::init_header(&m_slist); } + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + block_slist_base(const block_slist_base&) = delete; + block_slist_base operator=(const block_slist_base&) = delete; + #else + private: + block_slist_base (const block_slist_base&); + block_slist_base operator=(const block_slist_base&); + public: + #endif + + ~block_slist_base() + {} + + void *allocate(std::size_t size, memory_resource &mr) + { + if((size_t(-1) - header_size) < size) + throw_bad_alloc(); + void *p = mr.allocate(size+header_size); + block_slist_header &mb = *::new((void*)p) DerivedFromBlockSlistHeader; + mb.size = size+header_size; + slist_algo::link_after(&m_slist, &mb); + return (char *)p + header_size; + } + + void release(memory_resource &mr) BOOST_NOEXCEPT + { + slist_node *n = slist_algo::node_traits::get_next(&m_slist); + while(n){ + DerivedFromBlockSlistHeader &d = static_cast(*n); + n = slist_algo::node_traits::get_next(n); + std::size_t size = d.block_slist_header::size; + d.~DerivedFromBlockSlistHeader(); + mr.deallocate(reinterpret_cast(&d), size, memory_resource::max_align); + } + slist_algo::init_header(&m_slist); + } +}; + +class block_slist + : public block_slist_base<> +{ + memory_resource &m_upstream_rsrc; + + public: + + explicit block_slist(memory_resource &upstream_rsrc) + : block_slist_base<>(), m_upstream_rsrc(upstream_rsrc) + {} + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + block_slist(const block_slist&) = delete; + block_slist operator=(const block_slist&) = delete; + #else + private: + block_slist (const block_slist&); + block_slist operator=(const block_slist&); + public: + #endif + + ~block_slist() + { this->release(); } + + void *allocate(std::size_t size) + { return this->block_slist_base<>::allocate(size, m_upstream_rsrc); } + + void release() BOOST_NOEXCEPT + { return this->block_slist_base<>::release(m_upstream_rsrc); } + + memory_resource& upstream_resource() const BOOST_NOEXCEPT + { return m_upstream_rsrc; } +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_DETAIL_BLOCK_SLIST_HEADER diff --git a/include/boost/container/detail/config_begin.hpp b/include/boost/container/detail/config_begin.hpp index 3f509e3..7e3e03f 100644 --- a/include/boost/container/detail/config_begin.hpp +++ b/include/boost/container/detail/config_begin.hpp @@ -25,6 +25,7 @@ #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) #pragma warning (disable : 4324) // structure was padded due to __declspec(align( #pragma warning (disable : 4345) // behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized #pragma warning (disable : 4355) // "this" : used in base member initializer list diff --git a/include/boost/container/detail/dispatch_uses_allocator.hpp b/include/boost/container/detail/dispatch_uses_allocator.hpp new file mode 100644 index 0000000..3000f7c --- /dev/null +++ b/include/boost/container/detail/dispatch_uses_allocator.hpp @@ -0,0 +1,293 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_DISPATCH_USES_ALLOCATOR_HPP +#define BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include + +#include + +namespace boost { namespace container { + +namespace container_detail { + + +// Check if we can detect is_convertible using advanced SFINAE expressions +#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //! Code inspired by Mathias Gaunard's is_convertible.cpp found in the Boost mailing list + //! http://boost.2283326.n4.nabble.com/type-traits-is-constructible-when-decltype-is-supported-td3575452.html + //! Thanks Mathias! + + //With variadic templates, we need a single class to implement the trait + template + struct is_constructible + { + typedef char yes_type; + struct no_type + { char padding[2]; }; + + template + struct dummy; + + template + static decltype(X(boost::move_detail::declval()...), true_type()) test(int); + + template + static no_type test(...); + + static const bool value = sizeof(test(0)) == sizeof(yes_type); + }; + + template + struct is_constructible_with_allocator_prefix + : is_constructible + {}; + +#else // #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //Without advanced SFINAE expressions, we can't use is_constructible + //so backup to constructible_with_allocator_xxx + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + struct is_constructible_with_allocator_prefix + : constructible_with_allocator_prefix + {}; + + template + struct is_constructible_with_allocator_suffix + : constructible_with_allocator_suffix + {}; + + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + struct is_constructible_with_allocator_prefix + : constructible_with_allocator_prefix + {}; + + template + struct is_constructible_with_allocator_suffix + : constructible_with_allocator_suffix + {}; + + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // #if !defined(BOOST_NO_SFINAE_EXPR) + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template < typename ConstructAlloc + , typename ArgAlloc + , typename T + , class ...Args + > +inline typename container_detail::enable_if_and + < void + , container_detail::is_not_pair + , container_detail::not_< uses_allocator > + >::type dispatch_uses_allocator + ( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args)...args) +{ + (void)arg_alloc; + allocator_traits::construct(construct_alloc, p, ::boost::forward(args)...); +} + +// allocator_arg_t +template < typename ConstructAlloc + , typename ArgAlloc + , typename T + , class ...Args + > +inline typename container_detail::enable_if_and + < void + , container_detail::is_not_pair + , uses_allocator + , is_constructible_with_allocator_prefix + >::type dispatch_uses_allocator + ( ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args) ...args) +{ + allocator_traits::construct + ( construct_alloc, p, allocator_arg + , ::boost::forward(arg_alloc), ::boost::forward(args)...); +} + +// allocator suffix +template < typename ConstructAlloc + , typename ArgAlloc + , typename T + , class ...Args + > +inline typename container_detail::enable_if_and + < void + , container_detail::is_not_pair + , uses_allocator + , container_detail::not_ > + >::type dispatch_uses_allocator + ( ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args)...args) +{ + allocator_traits::construct + (construct_alloc, p, ::boost::forward(args)..., ::boost::forward(arg_alloc)); +} + +#else //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ + template \ + inline typename container_detail::enable_if_and\ + < void\ + , container_detail::is_not_pair\ + , container_detail::not_ >\ + >::type\ + dispatch_uses_allocator\ + (ConstructAlloc &construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + (void)arg_alloc;\ + allocator_traits::construct(construct_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ + template < typename ConstructAlloc, typename ArgAlloc, typename T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ + inline typename container_detail::enable_if_and\ + < void\ + , container_detail::is_not_pair\ + , uses_allocator\ + , is_constructible_with_allocator_prefix\ + >::type\ + dispatch_uses_allocator\ + (ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + allocator_traits::construct\ + (construct_alloc, p, allocator_arg, ::boost::forward(arg_alloc) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ + template < typename ConstructAlloc, typename ArgAlloc, typename T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ + inline typename container_detail::enable_if_and\ + < void\ + , container_detail::is_not_pair\ + , uses_allocator\ + , container_detail::not_ >\ + >::type\ + dispatch_uses_allocator\ + (ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + allocator_traits::construct\ + (construct_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N, ::boost::forward(arg_alloc));\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE + +#endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template < typename ConstructAlloc + , typename ArgAlloc + , typename Pair + > inline +BOOST_CONTAINER_DOC1ST(void, typename container_detail::enable_if >::type) + dispatch_uses_allocator + ( ConstructAlloc & construct_alloc + , ArgAlloc & arg_alloc + , Pair* p) +{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, container_detail::addressof(p->first)); + BOOST_TRY{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, container_detail::addressof(p->second)); + } + BOOST_CATCH(...) { + allocator_traits::destroy(construct_alloc, container_detail::addressof(p->first)); + BOOST_RETHROW + } + BOOST_CATCH_END +} + + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class U, class V> +BOOST_CONTAINER_DOC1ST(void, typename container_detail::enable_if >::type) + dispatch_uses_allocator + ( ConstructAlloc & construct_alloc + , ArgAlloc & arg_alloc + , Pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) +{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, container_detail::addressof(p->first), ::boost::forward(x)); + BOOST_TRY{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, container_detail::addressof(p->second), ::boost::forward(y)); + } + BOOST_CATCH(...){ + allocator_traits::destroy(construct_alloc, container_detail::addressof(p->first)); + BOOST_RETHROW + } + BOOST_CATCH_END +} + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class Pair2> +BOOST_CONTAINER_DOC1ST(void, typename container_detail::enable_if< container_detail::is_pair >::type) + dispatch_uses_allocator + (ConstructAlloc & construct_alloc + , ArgAlloc & arg_alloc + , Pair* p, Pair2& x) +{ (dispatch_uses_allocator)(construct_alloc, arg_alloc, p, x.first, x.second); } + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class Pair2> +typename container_detail::enable_if_and + < void + , container_detail::is_pair + , container_detail::not_ > >::type //This is needed for MSVC10 and ambiguous overloads + dispatch_uses_allocator + (ConstructAlloc & construct_alloc + , ArgAlloc & arg_alloc + , Pair* p, BOOST_RV_REF_BEG Pair2 BOOST_RV_REF_END x) +{ (dispatch_uses_allocator)(construct_alloc, arg_alloc, p, ::boost::move(x.first), ::boost::move(x.second)); } + +//template +//void dispatch_uses_allocator( ConstructAlloc & construct_alloc, ArgAlloc & arg_alloc +// , pair* p, piecewise_construct_t, tuple x, tuple y); + +} //namespace container_detail + +}} // namespace boost { namespace container { + +#include + +#endif // BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_HPP diff --git a/include/boost/container/detail/dlmalloc.hpp b/include/boost/container/detail/dlmalloc.hpp new file mode 100644 index 0000000..15086c3 --- /dev/null +++ b/include/boost/container/detail/dlmalloc.hpp @@ -0,0 +1,103 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_DETAIL_ALLOC_LIB_HPP +#define BOOST_CONTAINER_DETAIL_ALLOC_LIB_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +#include + +namespace boost{ +namespace container{ + +typedef boost_cont_command_ret_t dlmalloc_command_ret_t; +typedef boost_cont_memchain dlmalloc_memchain; +typedef boost_cont_memchain_it dlmalloc_memchain_it; +typedef boost_cont_malloc_stats_t dlmalloc_malloc_stats_t; + +BOOST_CONTAINER_DECL size_t dlmalloc_size(const void *p); + +BOOST_CONTAINER_DECL void* dlmalloc_malloc(size_t bytes); + +BOOST_CONTAINER_DECL void dlmalloc_free(void* mem); + +BOOST_CONTAINER_DECL void* dlmalloc_memalign(size_t bytes, size_t alignment); + +BOOST_CONTAINER_DECL int dlmalloc_multialloc_nodes + (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *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); + +BOOST_CONTAINER_DECL void dlmalloc_multidealloc(boost_cont_memchain *pchain); + +BOOST_CONTAINER_DECL size_t dlmalloc_footprint(); + +BOOST_CONTAINER_DECL size_t dlmalloc_allocated_memory(); + +BOOST_CONTAINER_DECL size_t dlmalloc_chunksize(const void *p); + +BOOST_CONTAINER_DECL int dlmalloc_all_deallocated(); + +BOOST_CONTAINER_DECL boost_cont_malloc_stats_t dlmalloc_malloc_stats(); + +BOOST_CONTAINER_DECL size_t dlmalloc_in_use_memory(); + +BOOST_CONTAINER_DECL int dlmalloc_trim(size_t pad); + +BOOST_CONTAINER_DECL int dlmalloc_mallopt(int parameter_number, int parameter_value); + +BOOST_CONTAINER_DECL int dlmalloc_grow(void* oldmem, size_t minbytes, size_t maxbytes, size_t *received); + +BOOST_CONTAINER_DECL int dlmalloc_shrink(void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit); + +BOOST_CONTAINER_DECL void* dlmalloc_alloc(size_t minbytes, size_t preferred_bytes, size_t *received_bytes); + +BOOST_CONTAINER_DECL int dlmalloc_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 + ); + +BOOST_CONTAINER_DECL int dlmalloc_mallopt(int param_number, int value); + +BOOST_CONTAINER_DECL void *dlmalloc_sync_create(); + +BOOST_CONTAINER_DECL void dlmalloc_sync_destroy(void *sync); + +BOOST_CONTAINER_DECL bool dlmalloc_sync_lock(void *sync); + +BOOST_CONTAINER_DECL void dlmalloc_sync_unlock(void *sync); + +BOOST_CONTAINER_DECL bool dlmalloc_global_sync_lock(); + +BOOST_CONTAINER_DECL void dlmalloc_global_sync_unlock(); + +} //namespace container{ +} //namespace boost{ + +#include + +#endif //BOOST_CONTAINER_DETAIL_ALLOC_LIB_HPP diff --git a/include/boost/container/detail/pool_common_alloc.hpp b/include/boost/container/detail/pool_common_alloc.hpp index 72e9c8d..3a3c80a 100644 --- a/include/boost/container/detail/pool_common_alloc.hpp +++ b/include/boost/container/detail/pool_common_alloc.hpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include namespace boost{ @@ -44,15 +44,15 @@ struct fake_segment_manager typedef boost::container::container_detail:: basic_multiallocation_chain multiallocation_chain; static void deallocate(void_pointer p) - { boost_cont_free(p); } + { dlmalloc_free(p); } static void deallocate_many(multiallocation_chain &chain) { std::size_t size = chain.size(); std::pair ptrs = chain.extract_data(); - boost_cont_memchain dlchain; + dlmalloc_memchain dlchain; BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&dlchain, ptrs.first, ptrs.second, size); - boost_cont_multidealloc(&dlchain); + dlmalloc_multidealloc(&dlchain); } typedef std::ptrdiff_t difference_type; @@ -60,7 +60,7 @@ struct fake_segment_manager static void *allocate_aligned(std::size_t nbytes, std::size_t alignment) { - void *ret = boost_cont_memalign(nbytes, alignment); + void *ret = dlmalloc_memalign(nbytes, alignment); if(!ret) boost::container::throw_bad_alloc(); return ret; @@ -68,7 +68,7 @@ struct fake_segment_manager static void *allocate(std::size_t nbytes) { - void *ret = boost_cont_malloc(nbytes); + void *ret = dlmalloc_malloc(nbytes); if(!ret) boost::container::throw_bad_alloc(); return ret; diff --git a/include/boost/container/detail/pool_resource.hpp b/include/boost/container/detail/pool_resource.hpp new file mode 100644 index 0000000..e5f59f5 --- /dev/null +++ b/include/boost/container/detail/pool_resource.hpp @@ -0,0 +1,191 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_POOL_RESOURCE_HPP +#define BOOST_CONTAINER_POOL_RESOURCE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +class pool_data_t; + +static const std::size_t pool_options_minimum_max_blocks_per_chunk = 1u; +static const std::size_t pool_options_default_max_blocks_per_chunk = 32u; +static const std::size_t pool_options_minimum_largest_required_pool_block = + memory_resource::max_align > 2*sizeof(void*) ? memory_resource::max_align : 2*sizeof(void*); +static const std::size_t pool_options_default_largest_required_pool_block = + pool_options_minimum_largest_required_pool_block > 4096u + ? pool_options_minimum_largest_required_pool_block : 4096u; + +#endif //BOOST_CONTAINER_DOXYGEN_INVOKED + +class pool_resource +{ + typedef block_list_base<> block_list_base_t; + + pool_options m_options; + memory_resource& m_upstream; + block_list_base_t m_oversized_list; + pool_data_t *m_pool_data; + std::size_t m_pool_count; + + static void priv_limit_option(std::size_t &val, std::size_t min, std::size_t max); + static std::size_t priv_pool_index(std::size_t block_size); + static std::size_t priv_pool_block(std::size_t index); + + void priv_fix_options(); + void priv_init_pools(); + void priv_constructor_body(); + + public: + + //! Requires: `upstream` is the address of a valid memory resource. + //! + //! Effects: Constructs a pool resource object that will obtain memory + //! from upstream whenever the pool resource is unable to satisfy a memory + //! request from its own internal data structures. The resulting object will hold + //! a copy of upstream, but will not own the resource to which upstream points. + //! [ Note: The intention is that calls to upstream->allocate() will be + //! substantially fewer than calls to this->allocate() in most cases. - end note + //! The behavior of the pooling mechanism is tuned according to the value of + //! the opts argument. + //! + //! Throws: Nothing unless upstream->allocate() throws. It is unspecified if + //! or under what conditions this constructor calls upstream->allocate(). + pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT; + + //! Effects: Same as + //! `pool_resource(pool_options(), get_default_resource())`. + pool_resource() BOOST_NOEXCEPT; + + //! Effects: Same as + //! `pool_resource(pool_options(), upstream)`. + explicit pool_resource(memory_resource* upstream) BOOST_NOEXCEPT; + + //! Effects: Same as + //! `pool_resource(opts, get_default_resource())`. + explicit pool_resource(const pool_options& opts) BOOST_NOEXCEPT; + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + pool_resource(const pool_resource&) = delete; + pool_resource operator=(const pool_resource&) = delete; + #else + private: + pool_resource (const pool_resource&); + pool_resource operator=(const pool_resource&); + public: + #endif + + //! Effects: Calls + //! `this->release()`. + virtual ~pool_resource(); + + //! Effects: Calls Calls `upstream_resource()->deallocate()` as necessary + //! to release all allocated memory. [ Note: memory is released back to + //! `upstream_resource()` even if deallocate has not been called for some + //! of the allocated blocks. - end note ] + void release(); + + //! Returns: The value of the upstream argument provided to the + //! constructor of this object. + memory_resource* upstream_resource() const; + + //! Returns: The options that control the pooling behavior of this resource. + //! The values in the returned struct may differ from those supplied to the pool + //! resource constructor in that values of zero will be replaced with + //! implementation-defined defaults and sizes may be rounded to unspecified granularity. + pool_options options() const; + + public: //public so that [un]synchronized_pool_resource can use them + + //! Returns: A pointer to allocated storage with a size of at least `bytes`. + //! The size and alignment of the allocated memory shall meet the requirements for + //! a class derived from `memory_resource`. + //! + //! Effects: If the pool selected for a block of size bytes is unable to + //! satisfy the memory request from its own internal data structures, it will call + //! `upstream_resource()->allocate()` to obtain more memory. If `bytes` is larger + //! than that which the largest pool can handle, then memory will be allocated + //! using `upstream_resource()->allocate()`. + //! + //! Throws: Nothing unless `upstream_resource()->allocate()` throws. + virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + + //! Effects: Return the memory at p to the pool. It is unspecified if or under + //! what circumstances this operation will result in a call to + //! `upstream_resource()->deallocate()`. + //! + //! Throws: Nothing. + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); + + //! Returns: + //! `this == dynamic_cast(&other)`. + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; + + //Non-standard observers + public: + //! Returns: The number of pools that will be used in the pool resource. + //! + //! Note: Non-standard extension. + std::size_t pool_count() const; + + //! Returns: The index of the pool that will be used to serve the allocation of `bytes`. + //! from the pool specified by `pool_index`. Returns `pool_count()` if `bytes` is bigger + //! than `options().largest_required_pool_block` (no pool will be used to serve this). + //! + //! Note: Non-standard extension. + std::size_t pool_index(std::size_t bytes) const; + + //! Requires: `pool_idx < pool_index()` + //! + //! Returns: The number blocks that will be allocated in the next chunk + //! from the pool specified by `pool_idx`. + //! + //! Note: Non-standard extension. + std::size_t pool_next_blocks_per_chunk(std::size_t pool_idx) const; + + //! Requires: `pool_idx < pool_index()` + //! + //! Returns: The number of bytes of the block that the specified `pool_idx` pool manages. + //! + //! Note: Non-standard extension. + std::size_t pool_block(std::size_t pool_idx) const; + + //! Requires: `pool_idx < pool_index()` + //! + //! Returns: The number of blocks that the specified `pool_idx` pool has cached + //! and will be served without calling the upstream_allocator. + //! + //! Note: Non-standard extension. + std::size_t pool_cached_blocks(std::size_t pool_idx) const; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_POOL_RESOURCE_HPP diff --git a/include/boost/container/detail/type_traits.hpp b/include/boost/container/detail/type_traits.hpp index e02709a..e1453a6 100644 --- a/include/boost/container/detail/type_traits.hpp +++ b/include/boost/container/detail/type_traits.hpp @@ -30,6 +30,8 @@ namespace boost { namespace container { namespace container_detail { +using ::boost::move_detail::enable_if; +using ::boost::move_detail::enable_if_and; using ::boost::move_detail::is_same; using ::boost::move_detail::is_different; using ::boost::move_detail::is_pointer; diff --git a/include/boost/container/detail/workaround.hpp b/include/boost/container/detail/workaround.hpp index 026e65d..e1f6156 100644 --- a/include/boost/container/detail/workaround.hpp +++ b/include/boost/container/detail/workaround.hpp @@ -19,8 +19,6 @@ # pragma once #endif -#include - #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)\ && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) #define BOOST_CONTAINER_PERFECT_FORWARDING @@ -59,6 +57,23 @@ #define BOOST_CONTAINER_DOCIGN(T) T #define BOOST_CONTAINER_DOCONLY(T) -#include +/* + we need to import/export our code only if the user has specifically + asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost + libraries to be dynamically linked, or BOOST_CONTAINER_DYN_LINK + if they want just this one to be dynamically liked: +*/ +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) + + /* export if this is our own source, otherwise import: */ + #ifdef BOOST_CONTAINER_SOURCE + # define BOOST_CONTAINER_DECL BOOST_SYMBOL_EXPORT + #else + # define BOOST_CONTAINER_DECL BOOST_SYMBOL_IMPORT + + #endif /* BOOST_CONTAINER_SOURCE */ +#else + #define BOOST_CONTAINER_DECL +#endif /* DYN_LINK */ #endif //#ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP diff --git a/include/boost/container/node_allocator.hpp b/include/boost/container/node_allocator.hpp index c3d8090..d92577e 100644 --- a/include/boost/container/node_allocator.hpp +++ b/include/boost/container/node_allocator.hpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -157,7 +157,7 @@ class node_allocator return pointer(static_cast(singleton_t::instance().allocate_node())); } else{ - void *ret = boost_cont_malloc(count*sizeof(T)); + void *ret = dlmalloc_malloc(count*sizeof(T)); if(BOOST_UNLIKELY(!ret)) boost::container::throw_bad_alloc(); return static_cast(ret); @@ -176,7 +176,7 @@ class node_allocator singleton_t::instance().deallocate_node(ptr); } else{ - boost_cont_free(ptr); + dlmalloc_free(ptr); } } @@ -204,7 +204,7 @@ class node_allocator size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_STATIC_ASSERT(( Version > 1 )); - return boost_cont_size(p); + return dlmalloc_size(p); } //!Allocates just one object. Memory allocated with this function @@ -259,9 +259,9 @@ class node_allocator void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) { BOOST_STATIC_ASSERT(( Version > 1 )); - boost_cont_memchain ch; + dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT(&ch); - if(BOOST_UNLIKELY(!boost_cont_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ boost::container::throw_bad_alloc(); } chain.incorporate_after( chain.before_begin() @@ -275,8 +275,8 @@ class node_allocator void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) { BOOST_STATIC_ASSERT(( Version > 1 )); - boost_cont_memchain ch; - boost_cont_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch); + dlmalloc_memchain ch; + dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch); if(BOOST_UNLIKELY(BOOST_CONTAINER_MEMCHAIN_EMPTY(&ch))){ boost::container::throw_bad_alloc(); } @@ -292,9 +292,9 @@ class node_allocator void *first = &*chain.begin(); void *last = &*chain.last(); size_t num = chain.size(); - boost_cont_memchain ch; + dlmalloc_memchain ch; BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, first, last, num); - boost_cont_multidealloc(&ch); + dlmalloc_multidealloc(&ch); } //!Swaps allocators. Does not throw. If each allocator is placed in a @@ -319,7 +319,7 @@ class node_allocator ,pointer &reuse) { std::size_t const preferred_size = prefer_in_recvd_out_size; - boost_cont_command_ret_t ret = {0 , 0}; + dlmalloc_command_ret_t ret = {0 , 0}; if((limit_size > this->max_size()) | (preferred_size > this->max_size())){ return pointer(); } @@ -328,7 +328,7 @@ class node_allocator std::size_t r_size; { void* reuse_ptr_void = reuse; - ret = boost_cont_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); + ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); reuse = static_cast(reuse_ptr_void); } prefer_in_recvd_out_size = r_size/sizeof(T); diff --git a/include/boost/container/pmr/deque.hpp b/include/boost/container/pmr/deque.hpp new file mode 100644 index 0000000..7447586 --- /dev/null +++ b/include/boost/container/pmr/deque.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_DEQUE_HPP +#define BOOST_CONTAINER_PMR_DEQUE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using deque = boost::container::deque>; + +#endif + +template +struct deque_of +{ + typedef boost::container::deque + < T, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_DEQUE_HPP diff --git a/include/boost/container/pmr/flat_map.hpp b/include/boost/container/pmr/flat_map.hpp new file mode 100644 index 0000000..786c190 --- /dev/null +++ b/include/boost/container/pmr/flat_map.hpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_FLAT_MAP_HPP +#define BOOST_CONTAINER_PMR_FLAT_MAP_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template + ,class Options = tree_assoc_defaults > +using flat_map = boost::container::flat_map > >; + +template + ,class Options = tree_assoc_defaults > +using flat_multimap = boost::container::flat_multimap > >; + +#endif + +template + ,class Options = tree_assoc_defaults > +struct flat_map_of +{ + typedef boost::container::flat_map > > type; +}; + +template + ,class Options = tree_assoc_defaults > +struct flat_multimap_of +{ + typedef boost::container::flat_multimap > > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_FLAT_MAP_HPP diff --git a/include/boost/container/pmr/flat_set.hpp b/include/boost/container/pmr/flat_set.hpp new file mode 100644 index 0000000..5c3ad1e --- /dev/null +++ b/include/boost/container/pmr/flat_set.hpp @@ -0,0 +1,59 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_SET_HPP +#define BOOST_CONTAINER_PMR_SET_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template + ,class Options = tree_assoc_defaults > +using flat_set = boost::container::flat_set >; + +template + ,class Options = tree_assoc_defaults > +using flat_multiset = boost::container::flat_multiset >; + +#endif + +template + ,class Options = tree_assoc_defaults > +struct flat_set_of +{ + typedef boost::container::flat_set > type; +}; + +template + ,class Options = tree_assoc_defaults > +struct flat_multiset_of +{ + typedef boost::container::flat_multiset > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_SET_HPP diff --git a/include/boost/container/pmr/global_resource.hpp b/include/boost/container/pmr/global_resource.hpp new file mode 100644 index 0000000..219309b --- /dev/null +++ b/include/boost/container/pmr/global_resource.hpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_GLOBAL_RESOURCE_HPP +#define BOOST_CONTAINER_PMR_GLOBAL_RESOURCE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +/// @cond +class memory_resource; +/// @endcond + +//! Returns: A pointer to a static-duration object of a type derived from +//! memory_resource that can serve as a resource for allocating memory using +//! global `operator new` and global `operator delete`. The same value is returned every time this function +//! is called. For return value p and memory resource r, p->is_equal(r) returns &r == p. +BOOST_CONTAINER_DECL memory_resource* new_delete_resource() BOOST_NOEXCEPT; + +//! Returns: A pointer to a static-duration object of a type derived from +//! memory_resource for which allocate() always throws bad_alloc and for which +//! deallocate() has no effect. The same value is returned every time this function +//! is called. For return value p and memory resource r, p->is_equal(r) returns &r == p. +BOOST_CONTAINER_DECL memory_resource* null_memory_resource() BOOST_NOEXCEPT; + +//! Effects: If r is non-null, sets the value of the default memory resource +//! pointer to r, otherwise sets the default memory resource pointer to new_delete_resource(). +//! +//! Postconditions: get_default_resource() == r. +//! +//! Returns: The previous value of the default memory resource pointer. +//! +//! Remarks: Calling the set_default_resource and get_default_resource functions shall +//! not incur a data race. A call to the set_default_resource function shall synchronize +//! with subsequent calls to the set_default_resource and get_default_resource functions. +BOOST_CONTAINER_DECL memory_resource* set_default_resource(memory_resource* r) BOOST_NOEXCEPT; + +//! Returns: The current value of the default +//! memory resource pointer. +BOOST_CONTAINER_DECL memory_resource* get_default_resource() BOOST_NOEXCEPT; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_PMR_GLOBAL_RESOURCE_HPP diff --git a/include/boost/container/pmr/list.hpp b/include/boost/container/pmr/list.hpp new file mode 100644 index 0000000..5967f45 --- /dev/null +++ b/include/boost/container/pmr/list.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_LIST_HPP +#define BOOST_CONTAINER_PMR_LIST_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using list = boost::container::list>; + +#endif + +template +struct list_of +{ + typedef boost::container::list + < T, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_VECTOR_HPP diff --git a/include/boost/container/pmr/map.hpp b/include/boost/container/pmr/map.hpp new file mode 100644 index 0000000..fdada0e --- /dev/null +++ b/include/boost/container/pmr/map.hpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_MAP_HPP +#define BOOST_CONTAINER_PMR_MAP_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template + ,class Options = tree_assoc_defaults > +using map = boost::container::map >, Options>; + +template + ,class Options = tree_assoc_defaults > +using multimap = boost::container::multimap >, Options>; + +#endif + +template + ,class Options = tree_assoc_defaults > +struct map_of +{ + typedef boost::container::map >, Options> type; +}; + +template + ,class Options = tree_assoc_defaults > +struct multimap_of +{ + typedef boost::container::multimap >, Options> type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_MAP_HPP diff --git a/include/boost/container/pmr/memory_resource.hpp b/include/boost/container/pmr/memory_resource.hpp new file mode 100644 index 0000000..72338a7 --- /dev/null +++ b/include/boost/container/pmr/memory_resource.hpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_MEMORY_RESOURCE_HPP +#define BOOST_CONTAINER_PMR_MEMORY_RESOURCE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +//! The memory_resource class is an abstract interface to an +//! unbounded set of classes encapsulating memory resources. +class memory_resource +{ + public: + // For exposition only + static BOOST_CONSTEXPR_OR_CONST std::size_t max_align = + boost::move_detail::alignment_of::value; + + //! Effects: Destroys + //! this memory_resource. + virtual ~memory_resource(){} + + //! Effects: Equivalent to + //! `return do_allocate(bytes, alignment);` + void* allocate(std::size_t bytes, std::size_t alignment = max_align) + { return this->do_allocate(bytes, alignment); } + + //! Effects: Equivalent to + //! `return do_deallocate(bytes, alignment);` + void deallocate(void* p, std::size_t bytes, std::size_t alignment = max_align) + { return this->do_deallocate(p, bytes, alignment); } + + //! Effects: Equivalent to + //! `return return do_is_equal(other);` + bool is_equal(const memory_resource& other) const BOOST_NOEXCEPT + { return this->do_is_equal(other); } + + //! Returns: + //! `&a == &b || a.is_equal(b)`. + friend bool operator==(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT + { return &a == &b || a.is_equal(b); } + + //! Returns: + //! !(a == b). + friend bool operator!=(const memory_resource& a, const memory_resource& b) BOOST_NOEXCEPT + { return !(a == b); } + + protected: + //! Requires: Alignment shall be a power of two. + //! + //! Returns: A derived class shall implement this function to return a pointer + //! to allocated storage with a size of at least bytes. The returned storage is + //! aligned to the specified alignment, if such alignment is supported; otherwise + //! it is aligned to max_align. + //! + //! Throws: A derived class implementation shall throw an appropriate exception if + //! it is unable to allocate memory with the requested size and alignment. + virtual void* do_allocate(std::size_t bytes, std::size_t alignment) = 0; + + //! Requires: p shall have been returned from a prior call to + //! `allocate(bytes, alignment)` on a memory resource equal to *this, and the storage + //! at p shall not yet have been deallocated. + //! + //! Effects: A derived class shall implement this function to dispose of allocated storage. + //! + //! Throws: Nothing. + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) = 0; + + //! Returns: A derived class shall implement this function to return true if memory + //! allocated from this can be deallocated from other and vice-versa; otherwise it shall + //! return false. [Note: The most-derived type of other might not match the type of this. + //! For a derived class, D, a typical implementation of this function will compute + //! `dynamic_cast(&other)` and go no further (i.e., return false) + //! if it returns nullptr. - end note]. + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT = 0; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_PMR_MEMORY_RESOURCE_HPP diff --git a/include/boost/container/pmr/monotonic_buffer_resource.hpp b/include/boost/container/pmr/monotonic_buffer_resource.hpp new file mode 100644 index 0000000..dfffe87 --- /dev/null +++ b/include/boost/container/pmr/monotonic_buffer_resource.hpp @@ -0,0 +1,180 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_MONOTONIC_BUFFER_RESOURCE_HPP +#define BOOST_CONTAINER_PMR_MONOTONIC_BUFFER_RESOURCE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +//! A monotonic_buffer_resource is a special-purpose memory resource intended for +//! very fast memory allocations in situations where memory is used to build up a +//! few objects and then is released all at once when the memory resource object +//! is destroyed. It has the following qualities: +//! +//! - A call to deallocate has no effect, thus the amount of memory consumed +//! increases monotonically until the resource is destroyed. +//! +//! - The program can supply an initial buffer, which the allocator uses to satisfy +//! memory requests. +//! +//! - When the initial buffer (if any) is exhausted, it obtains additional buffers +//! from an upstream memory resource supplied at construction. Each additional +//! buffer is larger than the previous one, following a geometric progression. +//! +//! - It is intended for access from one thread of control at a time. Specifically, +//! calls to allocate and deallocate do not synchronize with one another. +//! +//! - It owns the allocated memory and frees it on destruction, even if deallocate has +//! not been called for some of the allocated blocks. +class BOOST_CONTAINER_DECL monotonic_buffer_resource + : public memory_resource +{ + block_slist m_memory_blocks; + void* m_current_buffer; + std::size_t m_current_buffer_size; + std::size_t m_next_buffer_size; + + /// @cond + void increase_next_buffer(); + void increase_next_buffer_at_least_to(std::size_t minimum_size); + void *allocate_from_current(std::size_t aligner, std::size_t bytes); + /// @endcond + + public: + + //! The number of bytes that will be requested by the default in the first call + //! to the upstream allocator + //! + //! Note: Non-standard extension. + static const std::size_t initial_next_buffer_size = 32u*sizeof(void*); + + //! Requires: `upstream` shall be the address of a valid memory resource or `nullptr` + //! + //! Effects: If `upstream` is not nullptr, sets the internal resource to `upstream`, + //! to get_default_resource() otherwise. + //! Sets the internal `current_buffer` to `nullptr` and the internal `next_buffer_size` to an + //! implementation-defined size. + explicit monotonic_buffer_resource(memory_resource* upstream = 0) BOOST_NOEXCEPT; + + //! Requires: `upstream` shall be the address of a valid memory resource or `nullptr` + //! and `initial_size` shall be greater than zero. + //! + //! Effects: If `upstream` is not nullptr, sets the internal resource to `upstream`, + //! to get_default_resource() otherwise. Sets the internal `current_buffer` to `nullptr` and + //! `next_buffer_size` to at least `initial_size`. + explicit monotonic_buffer_resource(std::size_t initial_size, memory_resource* upstream = 0) BOOST_NOEXCEPT; + + //! Requires: `upstream` shall be the address of a valid memory resource or `nullptr`, + //! `buffer_size` shall be no larger than the number of bytes in buffer. + //! + //! Effects: If `upstream` is not nullptr, sets the internal resource to `upstream`, + //! to get_default_resource() otherwise. Sets the internal `current_buffer` to `buffer`, + //! and `next_buffer_size` to `buffer_size` (but not less than an implementation-defined size), + //! then increases `next_buffer_size` by an implementation-defined growth factor (which need not be integral). + monotonic_buffer_resource(void* buffer, std::size_t buffer_size, memory_resource* upstream = 0) BOOST_NOEXCEPT; + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; + monotonic_buffer_resource operator=(const monotonic_buffer_resource&) = delete; + #else + private: + monotonic_buffer_resource (const monotonic_buffer_resource&); + monotonic_buffer_resource operator=(const monotonic_buffer_resource&); + public: + #endif + + //! Effects: Calls + //! `this->release()`. + virtual ~monotonic_buffer_resource(); + + //! Effects: `upstream_resource()->deallocate()` as necessary to release all allocated memory. + //! [Note: memory is released back to `upstream_resource()` even if some blocks that were allocated + //! from this have not been deallocated from this. - end note] + void release() BOOST_NOEXCEPT; + + //! Returns: The value of + //! the internal resource. + memory_resource* upstream_resource() const BOOST_NOEXCEPT; + + //! Returns: + //! The number of bytes of storage available for the specified alignment and + //! the number of bytes wasted due to the requested alignment. + //! + //! Note: Non-standard extension. + std::size_t remaining_storage(std::size_t alignment, std::size_t &wasted_due_to_alignment) const BOOST_NOEXCEPT; + + //! Returns: + //! The number of bytes of storage available for the specified alignment. + //! + //! Note: Non-standard extension. + std::size_t remaining_storage(std::size_t alignment = 1u) const BOOST_NOEXCEPT; + + //! Returns: + //! The number of bytes of storage available for the specified alignment. + //! + //! Note: Non-standard extension. + const void *current_buffer() const BOOST_NOEXCEPT; + + //! Returns: + //! The number of bytes that will be requested for the next buffer once the + //! current one is exhausted. + //! + //! Note: Non-standard extension. + std::size_t next_buffer_size() const BOOST_NOEXCEPT; + + protected: + + //! Returns: A pointer to allocated storage with a size of at least `bytes`. The size + //! and alignment of the allocated memory shall meet the requirements for a class derived + //! from `memory_resource`. + //! + //! Effects: If the unused space in the internal `current_buffer` can fit a block with the specified + //! bytes and alignment, then allocate the return block from the internal `current_buffer`; otherwise sets + //! the internal `current_buffer` to `upstream_resource()->allocate(n, m)`, where `n` is not less than + //! `max(bytes, next_buffer_size)` and `m` is not less than alignment, and increase + //! `next_buffer_size` by an implementation-defined growth factor (which need not be integral), + //! then allocate the return block from the newly-allocated internal `current_buffer`. + //! + //! Throws: Nothing unless `upstream_resource()->allocate()` throws. + virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + + //! Effects: None + //! + //! Throws: Nothing + //! + //! Remarks: Memory used by this resource increases monotonically until its destruction. + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_NOEXCEPT; + + //! Returns: + //! `this == dynamic_cast(&other)`. + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_PMR_MONOTONIC_BUFFER_RESOURCE_HPP diff --git a/include/boost/container/pmr/polymorphic_allocator.hpp b/include/boost/container/pmr/polymorphic_allocator.hpp new file mode 100644 index 0000000..d189b3a --- /dev/null +++ b/include/boost/container/pmr/polymorphic_allocator.hpp @@ -0,0 +1,166 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_POLYMORPHIC_ALLOCATOR_HPP +#define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +//! A specialization of class template `polymorphic_allocator` conforms to the Allocator requirements. +//! Constructed with different memory resources, different instances of the same specialization of +//! `polymorphic_allocator` can exhibit entirely different allocation behavior. This runtime +//! polymorphism allows objects that use polymorphic_allocator to behave as if they used different +//! allocator types at run time even though they use the same static allocator type. +template +class polymorphic_allocator +{ + public: + typedef T value_type; + + //! Effects: Sets m_resource to + //! `get_default_resource()`. + polymorphic_allocator() BOOST_NOEXCEPT + : m_resource(::boost::container::pmr::get_default_resource()) + {} + + //! Requires: r is non-null. + //! + //! Effects: Sets m_resource to r. + //! + //! Throws: Nothing + //! + //! Notes: This constructor provides an implicit conversion from memory_resource*. + //! Non-standard extension: if r is null m_resource is set to get_default_resource(). + polymorphic_allocator(memory_resource* r) + : m_resource(r ? r : ::boost::container::pmr::get_default_resource()) + {} + + //! Effects: Sets m_resource to + //! other.resource(). + polymorphic_allocator(const polymorphic_allocator& other) + : m_resource(other.m_resource) + {} + + //! Effects: Sets m_resource to + //! other.resource(). + template + polymorphic_allocator(const polymorphic_allocator& other) BOOST_NOEXCEPT + : m_resource(other.resource()) + {} + + //! Effects: Sets m_resource to + //! other.resource(). + polymorphic_allocator& operator=(const polymorphic_allocator& other) + { m_resource = other.m_resource; return *this; } + + //! Returns: Equivalent to + //! `static_cast(m_resource->allocate(n * sizeof(T), alignof(T)))`. + T* allocate(size_t n) + { return static_cast(m_resource->allocate(n*sizeof(T), ::boost::move_detail::alignment_of::value)); } + + //! Requires: p was allocated from a memory resource, x, equal to *m_resource, + //! using `x.allocate(n * sizeof(T), alignof(T))`. + //! + //! Effects: Equivalent to m_resource->deallocate(p, n * sizeof(T), alignof(T)). + //! + //! Throws: Nothing. + void deallocate(T* p, size_t n) + { m_resource->deallocate(p, n*sizeof(T), ::boost::move_detail::alignment_of::value); } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Requires: Uses-allocator construction of T with allocator + //! `this->resource()` and constructor arguments `std::forward(args)...` + //! is well-formed. [Note: uses-allocator construction is always well formed for + //! types that do not use allocators. - end note] + //! + //! Effects: Construct a T object at p by uses-allocator construction with allocator + //! `this->resource()` and constructor arguments `std::forward(args)...`. + //! + //! Throws: Nothing unless the constructor for T throws. + template < typename U, class ...Args> + void construct(U* p, BOOST_FWD_REF(Args)...args) + { + new_allocator na; + container_detail::dispatch_uses_allocator + (na, this->resource(), p, ::boost::forward(args)...); + } + + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //Disable this overload if the first argument is pair as some compilers have + //overload selection problems when the first parameter is a pair. + #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE(N) \ + template < typename U BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\ + void construct(U* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ + {\ + new_allocator na;\ + container_detail::dispatch_uses_allocator\ + (na, this->resource(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE) + #undef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE + + #endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: + //! p->~U(). + template + void destroy(U* p) + { (void)p; p->~U(); } + + //! Returns: Equivalent to + //! `polymorphic_allocator()`. + polymorphic_allocator select_on_container_copy_construction() const + { return polymorphic_allocator(); } + + //! Returns: + //! m_resource. + memory_resource* resource() const + { return m_resource; } + + private: + memory_resource* m_resource; +}; + +//! Returns: +//! `*a.resource() == *b.resource()`. +template +bool operator==(const polymorphic_allocator& a, const polymorphic_allocator& b) BOOST_NOEXCEPT +{ return *a.resource() == *b.resource(); } + + +//! Returns: +//! `! (a == b)`. +template +bool operator!=(const polymorphic_allocator& a, const polymorphic_allocator& b) BOOST_NOEXCEPT +{ return *a.resource() != *b.resource(); } + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP diff --git a/include/boost/container/pmr/pool_options.hpp b/include/boost/container/pmr/pool_options.hpp new file mode 100644 index 0000000..e9f7289 --- /dev/null +++ b/include/boost/container/pmr/pool_options.hpp @@ -0,0 +1,52 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_POOL_OPTIONS_HPP +#define BOOST_CONTAINER_PMR_POOL_OPTIONS_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include + +namespace boost { +namespace container { +namespace pmr { + +//! The members of pool_options comprise a set of constructor options for pool resources. +//! The effect of each option on the pool resource behavior is described below: +//! +//! - `std::size_t max_blocks_per_chunk`: The maximum number of blocks that will be allocated +//! at once from the upstream memory resource to replenish a pool. If the value of +//! `max_blocks_per_chunk` is zero or is greater than an implementation-defined limit, +//! that limit is used instead. The implementation may choose to use a smaller value +//! than is specified in this field and may use different values for different pools. +//! +//! - `std::size_t largest_required_pool_block`: The largest allocation size that is required +//! to be fulfilled using the pooling mechanism. Attempts to allocate a single block +//! larger than this threshold will be allocated directly from the upstream memory +//! resource. If largest_required_pool_block is zero or is greater than an +//! implementation-defined limit, that limit is used instead. The implementation may +//! choose a pass-through threshold larger than specified in this field. +struct pool_options +{ + pool_options() + : max_blocks_per_chunk(0u), largest_required_pool_block(0u) + {} + std::size_t max_blocks_per_chunk; + std::size_t largest_required_pool_block; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_POOL_OPTIONS_HPP diff --git a/include/boost/container/pmr/resource_adaptor.hpp b/include/boost/container/pmr/resource_adaptor.hpp new file mode 100644 index 0000000..deece63 --- /dev/null +++ b/include/boost/container/pmr/resource_adaptor.hpp @@ -0,0 +1,193 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_RESOURCE_ADAPTOR_HPP +#define BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +//! An instance of resource_adaptor is an adaptor that wraps a memory_resource interface +//! around Allocator. In order that resource_adaptor> and resource_adaptor> are the same +//! type for any allocator template X and types T and U, resource_adaptor is rendered as +//! an alias to this class template such that Allocator is rebound to a char value type in every +//! specialization of the class template. The requirements on this class template are defined below. +//! In addition to the Allocator requirements, the parameter to resource_adaptor shall meet +//! the following additional requirements: +//! +//! - `typename allocator_traits:: pointer` shall be identical to +//! `typename allocator_traits:: value_type*`. +//! +//! - `typename allocator_traits:: const_pointer` shall be identical to +//! `typename allocator_traits:: value_type const*`. +//! +//! - `typename allocator_traits:: void_pointer` shall be identical to `void*`. +//! +//! - `typename allocator_traits:: const_void_pointer` shall be identical to `void const*`. +template +class resource_adaptor_imp + : public memory_resource + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + , private ::boost::intrusive::detail::ebo_functor_holder + #endif +{ + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + Allocator m_alloc; + #else + BOOST_COPYABLE_AND_MOVABLE(resource_adaptor_imp) + typedef ::boost::intrusive::detail::ebo_functor_holder ebo_alloc_t; + void static_assert_if_not_char_allocator() const + { + //This class can only be used with allocators type char + BOOST_STATIC_ASSERT((container_detail::is_same::value)); + } + #endif + + public: + typedef Allocator allocator_type; + + //! Effects: Default constructs + //! m_alloc. + resource_adaptor_imp() + { this->static_assert_if_not_char_allocator(); } + + //! Effects: Copy constructs + //! m_alloc. + resource_adaptor_imp(const resource_adaptor_imp &other) + : ebo_alloc_t(other.ebo_alloc_t::get()) + {} + + //! Effects: Move constructs + //! m_alloc. + resource_adaptor_imp(BOOST_RV_REF(resource_adaptor_imp) other) + : ebo_alloc_t(::boost::move(other.get())) + {} + + //! Effects: Initializes m_alloc with + //! a2. + explicit resource_adaptor_imp(const Allocator& a2) + : ebo_alloc_t(a2) + { this->static_assert_if_not_char_allocator(); } + + //! Effects: Initializes m_alloc with + //! a2. + explicit resource_adaptor_imp(BOOST_RV_REF(Allocator) a2) + : ebo_alloc_t(::boost::move(a2)) + { this->static_assert_if_not_char_allocator(); } + + //! Effects: Copy assigns + //! m_alloc. + resource_adaptor_imp& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor_imp) other) + { this->ebo_alloc_t::get() = other.ebo_alloc_t::get(); return *this; } + + //! Effects: Move assigns + //! m_alloc. + resource_adaptor_imp& operator=(BOOST_RV_REF(resource_adaptor_imp) other) + { this->ebo_alloc_t::get() = ::boost::move(other.ebo_alloc_t::get()); return *this; } + + //! Effects: Returns m_alloc. + allocator_type &get_allocator() + { return this->ebo_alloc_t::get(); } + + //! Effects: Returns m_alloc. + const allocator_type &get_allocator() const + { return this->ebo_alloc_t::get(); } + + protected: + //! Returns: Allocated memory obtained by calling m_alloc.allocate. The size and alignment + //! of the allocated memory shall meet the requirements for a class derived from memory_resource. + virtual void* do_allocate(size_t bytes, size_t alignment) + { (void)alignment; return this->ebo_alloc_t::get().allocate(bytes); } + + //! Requires: p was previously allocated using A.allocate, where A == m_alloc, and not + //! subsequently deallocated. + //! + //! Effects: Returns memory to the allocator using m_alloc.deallocate(). + virtual void do_deallocate(void* p, size_t bytes, size_t alignment) + { (void)alignment; this->ebo_alloc_t::get().deallocate((char*)p, bytes); } + + //! Let p be dynamic_cast(&other). + //! + //! Returns: false if p is null, otherwise the value of m_alloc == p->m_alloc. + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT + { + const resource_adaptor_imp* p = dynamic_cast(&other); + return p && p->ebo_alloc_t::get() == this->ebo_alloc_t::get(); + } +}; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +//! `resource_adaptor` is rendered as an alias to resource_adaptor_imp class template +//! such that Allocator is rebound to a char value type. +template +using resource_adaptor = resource_adaptor_imp + ::template rebind_alloc >; + +#else + +template +class resource_adaptor + : public resource_adaptor_imp + ::template portable_rebind_alloc::type> +{ + typedef resource_adaptor_imp + ::template portable_rebind_alloc::type> base_t; + + BOOST_COPYABLE_AND_MOVABLE(resource_adaptor) + + public: + resource_adaptor() + : base_t() + {} + + resource_adaptor(const resource_adaptor &other) + : base_t(other) + {} + + resource_adaptor(BOOST_RV_REF(resource_adaptor) other) + : base_t(BOOST_MOVE_BASE(base_t, other)) + {} + + explicit resource_adaptor(const Allocator& a2) + : base_t(a2) + {} + + explicit resource_adaptor(BOOST_RV_REF(Allocator) a2) + : base_t(BOOST_MOVE_BASE(base_t, a2)) + {} + + resource_adaptor& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor) other) + { return static_cast(this->base_t::operator=(other)); } + + resource_adaptor& operator=(BOOST_RV_REF(resource_adaptor) other) + { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, other))); } + + //get_allocator and protected functions are properly inherited +}; + +#endif + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP diff --git a/include/boost/container/pmr/set.hpp b/include/boost/container/pmr/set.hpp new file mode 100644 index 0000000..6f2c3bf --- /dev/null +++ b/include/boost/container/pmr/set.hpp @@ -0,0 +1,59 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_SET_HPP +#define BOOST_CONTAINER_PMR_SET_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template + ,class Options = tree_assoc_defaults > +using set = boost::container::set, Options>; + +template + ,class Options = tree_assoc_defaults > +using multiset = boost::container::multiset, Options>; + +#endif + +template + ,class Options = tree_assoc_defaults > +struct set_of +{ + typedef boost::container::set, Options> type; +}; + +template + ,class Options = tree_assoc_defaults > +struct multiset_of +{ + typedef boost::container::multiset, Options> type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_SET_HPP diff --git a/include/boost/container/pmr/slist.hpp b/include/boost/container/pmr/slist.hpp new file mode 100644 index 0000000..4ee76c6 --- /dev/null +++ b/include/boost/container/pmr/slist.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_SLIST_HPP +#define BOOST_CONTAINER_PMR_SLIST_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using slist = boost::container::slist>; + +#endif + +template +struct slist_of +{ + typedef boost::container::slist + < T, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_VECTOR_HPP diff --git a/include/boost/container/pmr/small_vector.hpp b/include/boost/container/pmr/small_vector.hpp new file mode 100644 index 0000000..a79d5a0 --- /dev/null +++ b/include/boost/container/pmr/small_vector.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_SMALL_VECTOR_HPP +#define BOOST_CONTAINER_PMR_SMALL_VECTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using small_vector = boost::container::small_vector>; + +#endif + +template +struct small_vector_of +{ + typedef boost::container::small_vector + < T, N, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_SMALL_VECTOR_HPP diff --git a/include/boost/container/pmr/stable_vector.hpp b/include/boost/container/pmr/stable_vector.hpp new file mode 100644 index 0000000..07a2059 --- /dev/null +++ b/include/boost/container/pmr/stable_vector.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_STABLE_VECTOR_HPP +#define BOOST_CONTAINER_PMR_STABLE_VECTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using stable_vector = boost::container::stable_vector>; + +#endif + +template +struct stable_vector_of +{ + typedef boost::container::stable_vector + < T, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_STABLE_VECTOR_HPP diff --git a/include/boost/container/pmr/string.hpp b/include/boost/container/pmr/string.hpp new file mode 100644 index 0000000..2e879e3 --- /dev/null +++ b/include/boost/container/pmr/string.hpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_STRING_HPP +#define BOOST_CONTAINER_PMR_STRING_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template > +using basic_string = + boost::container::basic_string >; + +#endif + +template > +struct basic_string_of +{ + typedef boost::container::basic_string + > type; +}; + +typedef basic_string_of::type string; + +typedef basic_string_of::type wstring; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_STRING_HPP diff --git a/include/boost/container/pmr/synchronized_pool_resource.hpp b/include/boost/container/pmr/synchronized_pool_resource.hpp new file mode 100644 index 0000000..e4d4dd5 --- /dev/null +++ b/include/boost/container/pmr/synchronized_pool_resource.hpp @@ -0,0 +1,138 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_SYNCHRONIZED_POOL_RESOURCE_HPP +#define BOOST_CONTAINER_PMR_SYNCHRONIZED_POOL_RESOURCE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +//! A synchronized_pool_resource is a general-purpose memory resources having +//! the following qualities: +//! +//! - Each resource owns the allocated memory, and frees it on destruction, +//! even if deallocate has not been called for some of the allocated blocks. +//! +//! - A pool resource consists of a collection of pools, serving +//! requests for different block sizes. Each individual pool manages a +//! collection of chunks that are in turn divided into blocks of uniform size, +//! returned via calls to do_allocate. Each call to do_allocate(size, alignment) +//! is dispatched to the pool serving the smallest blocks accommodating at +//! least size bytes. +//! +//! - When a particular pool is exhausted, allocating a block from that pool +//! results in the allocation of an additional chunk of memory from the upstream +//! allocator (supplied at construction), thus replenishing the pool. With +//! each successive replenishment, the chunk size obtained increases +//! geometrically. [ Note: By allocating memory in chunks, the pooling strategy +//! increases the chance that consecutive allocations will be close together +//! in memory. - end note ] +//! +//! - Allocation requests that exceed the largest block size of any pool are +//! fulfilled directly from the upstream allocator. +//! +//! - A pool_options struct may be passed to the pool resource constructors to +//! tune the largest block size and the maximum chunk size. +//! +//! A synchronized_pool_resource may be accessed from multiple threads without +//! external synchronization and may have thread-specific pools to reduce +//! synchronization costs. +class BOOST_CONTAINER_DECL synchronized_pool_resource + : public memory_resource +{ + pool_resource m_pool_resource; + void *m_opaque_sync; + + public: + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::unsynchronized_pool_resource(const pool_options&,memory_resource*) + synchronized_pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::unsynchronized_pool_resource() + synchronized_pool_resource() BOOST_NOEXCEPT; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::unsynchronized_pool_resource(memory_resource*) + explicit synchronized_pool_resource(memory_resource* upstream) BOOST_NOEXCEPT; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::unsynchronized_pool_resource(const pool_options&) + explicit synchronized_pool_resource(const pool_options& opts) BOOST_NOEXCEPT; + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + synchronized_pool_resource(const synchronized_pool_resource&) = delete; + synchronized_pool_resource operator=(const synchronized_pool_resource&) = delete; + #else + private: + synchronized_pool_resource (const synchronized_pool_resource&); + synchronized_pool_resource operator=(const synchronized_pool_resource&); + public: + #endif + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::~unsynchronized_pool_resource() + virtual ~synchronized_pool_resource(); + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::release() + void release(); + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::upstream_resource()const + memory_resource* upstream_resource() const; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::options()const + pool_options options() const; + + protected: + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::do_allocate() + virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::do_deallocate(void*,std::size_t,std::size_t) + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::do_is_equal(const memory_resource&)const + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; + + //Non-standard observers + public: + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::pool_count() + std::size_t pool_count() const; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::pool_index(std::size_t)const + std::size_t pool_index(std::size_t bytes) const; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::pool_next_blocks_per_chunk(std::size_t)const + std::size_t pool_next_blocks_per_chunk(std::size_t pool_idx) const; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::pool_block(std::size_t)const + std::size_t pool_block(std::size_t pool_idx) const; + + //! @copydoc ::boost::container::pmr::unsynchronized_pool_resource::pool_cached_blocks(std::size_t)const + std::size_t pool_cached_blocks(std::size_t pool_idx) const; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_PMR_SYNCHRONIZED_POOL_RESOURCE_HPP diff --git a/include/boost/container/pmr/unsynchronized_pool_resource.hpp b/include/boost/container/pmr/unsynchronized_pool_resource.hpp new file mode 100644 index 0000000..21d30b1 --- /dev/null +++ b/include/boost/container/pmr/unsynchronized_pool_resource.hpp @@ -0,0 +1,194 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_UNSYNCHRONIZED_POOL_RESOURCE_HPP +#define BOOST_CONTAINER_PMR_UNSYNCHRONIZED_POOL_RESOURCE_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +//! A unsynchronized_pool_resource is a general-purpose memory resources having +//! the following qualities: +//! +//! - Each resource owns the allocated memory, and frees it on destruction, +//! even if deallocate has not been called for some of the allocated blocks. +//! +//! - A pool resource consists of a collection of pools, serving +//! requests for different block sizes. Each individual pool manages a +//! collection of chunks that are in turn divided into blocks of uniform size, +//! returned via calls to do_allocate. Each call to do_allocate(size, alignment) +//! is dispatched to the pool serving the smallest blocks accommodating at +//! least size bytes. +//! +//! - When a particular pool is exhausted, allocating a block from that pool +//! results in the allocation of an additional chunk of memory from the upstream +//! allocator (supplied at construction), thus replenishing the pool. With +//! each successive replenishment, the chunk size obtained increases +//! geometrically. [ Note: By allocating memory in chunks, the pooling strategy +//! increases the chance that consecutive allocations will be close together +//! in memory. - end note ] +//! +//! - Allocation requests that exceed the largest block size of any pool are +//! fulfilled directly from the upstream allocator. +//! +//! - A pool_options struct may be passed to the pool resource constructors to +//! tune the largest block size and the maximum chunk size. +//! +//! An unsynchronized_pool_resource class may not be accessed from multiple threads +//! simultaneously and thus avoids the cost of synchronization entirely in +//! single-threaded applications. +class BOOST_CONTAINER_DECL unsynchronized_pool_resource + : public memory_resource +{ + pool_resource m_resource; + + public: + + //! Requires: `upstream` is the address of a valid memory resource. + //! + //! Effects: Constructs a pool resource object that will obtain memory + //! from upstream whenever the pool resource is unable to satisfy a memory + //! request from its own internal data structures. The resulting object will hold + //! a copy of upstream, but will not own the resource to which upstream points. + //! [ Note: The intention is that calls to upstream->allocate() will be + //! substantially fewer than calls to this->allocate() in most cases. - end note + //! The behavior of the pooling mechanism is tuned according to the value of + //! the opts argument. + //! + //! Throws: Nothing unless upstream->allocate() throws. It is unspecified if + //! or under what conditions this constructor calls upstream->allocate(). + unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT; + + //! Effects: Same as + //! `unsynchronized_pool_resource(pool_options(), get_default_resource())`. + unsynchronized_pool_resource() BOOST_NOEXCEPT; + + //! Effects: Same as + //! `unsynchronized_pool_resource(pool_options(), upstream)`. + explicit unsynchronized_pool_resource(memory_resource* upstream) BOOST_NOEXCEPT; + + //! Effects: Same as + //! `unsynchronized_pool_resource(opts, get_default_resource())`. + explicit unsynchronized_pool_resource(const pool_options& opts) BOOST_NOEXCEPT; + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; + unsynchronized_pool_resource operator=(const unsynchronized_pool_resource&) = delete; + #else + private: + unsynchronized_pool_resource (const unsynchronized_pool_resource&); + unsynchronized_pool_resource operator=(const unsynchronized_pool_resource&); + public: + #endif + + //! Effects: Calls + //! `this->release()`. + virtual ~unsynchronized_pool_resource(); + + //! Effects: Calls Calls `upstream_resource()->deallocate()` as necessary + //! to release all allocated memory. [ Note: memory is released back to + //! `upstream_resource()` even if deallocate has not been called for some + //! of the allocated blocks. - end note ] + void release(); + + //! Returns: The value of the upstream argument provided to the + //! constructor of this object. + memory_resource* upstream_resource() const; + + //! Returns: The options that control the pooling behavior of this resource. + //! The values in the returned struct may differ from those supplied to the pool + //! resource constructor in that values of zero will be replaced with + //! implementation-defined defaults and sizes may be rounded to unspecified granularity. + pool_options options() const; + + protected: + + //! Returns: A pointer to allocated storage with a size of at least `bytes`. + //! The size and alignment of the allocated memory shall meet the requirements for + //! a class derived from `memory_resource`. + //! + //! Effects: If the pool selected for a block of size bytes is unable to + //! satisfy the memory request from its own internal data structures, it will call + //! `upstream_resource()->allocate()` to obtain more memory. If `bytes` is larger + //! than that which the largest pool can handle, then memory will be allocated + //! using `upstream_resource()->allocate()`. + //! + //! Throws: Nothing unless `upstream_resource()->allocate()` throws. + virtual void* do_allocate(std::size_t bytes, std::size_t alignment); + + //! Effects: Return the memory at p to the pool. It is unspecified if or under + //! what circumstances this operation will result in a call to + //! `upstream_resource()->deallocate()`. + //! + //! Throws: Nothing. + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); + + //! Returns: + //! `this == dynamic_cast(&other)`. + virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT; + + //Non-standard observers + public: + //! Returns: The number of pools that will be used in the pool resource. + //! + //! Note: Non-standard extension. + std::size_t pool_count() const; + + //! Returns: The index of the pool that will be used to serve the allocation of `bytes`. + //! Returns `pool_count()` if `bytes` is bigger + //! than `options().largest_required_pool_block` (no pool will be used to serve this). + //! + //! Note: Non-standard extension. + std::size_t pool_index(std::size_t bytes) const; + + //! Requires: `pool_idx < pool_index()` + //! + //! Returns: The number blocks that will be allocated in the next chunk + //! from the pool specified by `pool_idx`. + //! + //! Note: Non-standard extension. + std::size_t pool_next_blocks_per_chunk(std::size_t pool_idx) const; + + //! Requires: `pool_idx < pool_index()` + //! + //! Returns: The number of bytes of the block that the specified `pool_idx` pool manages. + //! + //! Note: Non-standard extension. + std::size_t pool_block(std::size_t pool_idx) const; + + //! Requires: `pool_idx < pool_index()` + //! + //! Returns: The number of blocks that the specified `pool_idx` pool has cached + //! and will be served without calling the upstream_allocator. + //! + //! Note: Non-standard extension. + std::size_t pool_cached_blocks(std::size_t pool_idx) const; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_PMR_UNSYNCHRONIZED_POOL_RESOURCE_HPP diff --git a/include/boost/container/pmr/vector.hpp b/include/boost/container/pmr/vector.hpp new file mode 100644 index 0000000..cef6ae5 --- /dev/null +++ b/include/boost/container/pmr/vector.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PMR_VECTOR_HPP +#define BOOST_CONTAINER_PMR_VECTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using vector = boost::container::vector>; + +#endif + +template +struct vector_of +{ + typedef boost::container::vector + < T, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_VECTOR_HPP diff --git a/include/boost/container/scoped_allocator.hpp b/include/boost/container/scoped_allocator.hpp index 0724f94..6a041a6 100644 --- a/include/boost/container/scoped_allocator.hpp +++ b/include/boost/container/scoped_allocator.hpp @@ -18,7 +18,7 @@ #define BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP #if defined (_MSC_VER) -# pragma once +# pragma once #endif #include @@ -26,8 +26,8 @@ #include #include +#include -#include #include #include #include @@ -42,143 +42,6 @@ namespace boost { namespace container { -//! Remark: if a specialization constructible_with_allocator_suffix::value is true, indicates that T may be constructed -//! with an allocator as its last constructor argument. Ideally, all constructors of T (including the -//! copy and move constructors) should have a variant that accepts a final argument of -//! allocator_type. -//! -//! Requires: if a specialization constructible_with_allocator_suffix::value is true, T must have a nested type, -//! allocator_type and at least one constructor for which allocator_type is the last -//! parameter. If not all constructors of T can be called with a final allocator_type argument, -//! and if T is used in a context where a container must call such a constructor, then the program is -//! ill-formed. -//! -//! -//! template > -//! class Z { -//! public: -//! typedef Allocator allocator_type; -//! -//! // Default constructor with optional allocator suffix -//! Z(const allocator_type& a = allocator_type()); -//! -//! // Copy constructor and allocator-extended copy constructor -//! Z(const Z& zz); -//! Z(const Z& zz, const allocator_type& a); -//! }; -//! -//! // Specialize trait for class template Z -//! template > -//! struct constructible_with_allocator_suffix > -//! { static const bool value = true; }; -//! -//! -//! Note: This trait is a workaround inspired by "N2554: The Scoped A Model (Rev 2)" -//! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as -//! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. -//! Applications aiming portability with several compilers should always define this trait. -//! -//! In conforming C++11 compilers or compilers supporting SFINAE expressions -//! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used -//! to detect if a type should be constructed with suffix or prefix allocator arguments. -template -struct constructible_with_allocator_suffix -{ static const bool value = false; }; - -//! Remark: if a specialization constructible_with_allocator_prefix::value is true, indicates that T may be constructed -//! with allocator_arg and T::allocator_type as its first two constructor arguments. -//! Ideally, all constructors of T (including the copy and move constructors) should have a variant -//! that accepts these two initial arguments. -//! -//! Requires: specialization constructible_with_allocator_prefix::value is true, T must have a nested type, -//! allocator_type and at least one constructor for which allocator_arg_t is the first -//! parameter and allocator_type is the second parameter. If not all constructors of T can be -//! called with these initial arguments, and if T is used in a context where a container must call such -//! a constructor, then the program is ill-formed. -//! -//! -//! template > -//! class Y { -//! public: -//! typedef Allocator allocator_type; -//! -//! // Default constructor with and allocator-extended default constructor -//! Y(); -//! Y(allocator_arg_t, const allocator_type& a); -//! -//! // Copy constructor and allocator-extended copy constructor -//! Y(const Y& yy); -//! Y(allocator_arg_t, const allocator_type& a, const Y& yy); -//! -//! // Variadic constructor and allocator-extended variadic constructor -//! template Y(Args&& args...); -//! template -//! Y(allocator_arg_t, const allocator_type& a, BOOST_FWD_REF(Args)... args); -//! }; -//! -//! // Specialize trait for class template Y -//! template > -//! struct constructible_with_allocator_prefix > -//! { static const bool value = true; }; -//! -//! -//! -//! Note: This trait is a workaround inspired by "N2554: The Scoped Allocator Model (Rev 2)" -//! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as -//! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. -//! Applications aiming portability with several compilers should always define this trait. -//! -//! In conforming C++11 compilers or compilers supporting SFINAE expressions -//! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used -//! to detect if a type should be constructed with suffix or prefix allocator arguments. -template -struct constructible_with_allocator_prefix -{ static const bool value = false; }; - -#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -namespace container_detail { - -template -struct uses_allocator_imp -{ - // Use SFINAE (Substitution Failure Is Not An Error) to detect the - // presence of an 'allocator_type' nested type convertilble from Allocator. - private: - typedef char yes_type; - struct no_type{ char dummy[2]; }; - - // Match this function if TypeT::allocator_type exists and is - // implicitly convertible from Allocator - template - static yes_type test(typename U::allocator_type); - - // Match this function if TypeT::allocator_type does not exist or is - // not convertible from Allocator. - template - static no_type test(...); - static Allocator alloc; // Declared but not defined - - public: - static const bool value = sizeof(test(alloc)) == sizeof(yes_type); -}; - -} //namespace container_detail { - -#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -//! Remark: Automatically detects if T has a nested allocator_type that is convertible from -//! Allocator. Meets the BinaryTypeTrait requirements ([meta.rqmts] 20.4.1). A program may -//! specialize this type to define uses_allocator::value as true for a T of user-defined type if T does not -//! have a nested allocator_type but is nonetheless constructible using the specified Allocator. -//! -//! Result: uses_allocator::value== true if Convertible, -//! false otherwise. -template -struct uses_allocator - : container_detail::uses_allocator_imp -{}; - #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED namespace container_detail { @@ -249,198 +112,17 @@ struct outermost_allocator {}; template -typename container_detail::outermost_allocator_imp::type & +typename outermost_allocator::type & get_outermost_allocator(Allocator &a) -{ return container_detail::outermost_allocator_imp::get(a); } +{ return outermost_allocator::get(a); } template -const typename container_detail::outermost_allocator_imp::type & +const typename outermost_allocator::type & get_outermost_allocator(const Allocator &a) -{ return container_detail::outermost_allocator_imp::get(a); } +{ return outermost_allocator::get(a); } namespace container_detail { -// Check if we can detect is_convertible using advanced SFINAE expressions -#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - //! Code inspired by Mathias Gaunard's is_convertible.cpp found in the Boost mailing list - //! http://boost.2283326.n4.nabble.com/type-traits-is-constructible-when-decltype-is-supported-td3575452.html - //! Thanks Mathias! - - //With variadic templates, we need a single class to implement the trait - template - struct is_constructible - { - typedef char yes_type; - struct no_type - { char padding[2]; }; - - template - struct dummy; - - template - static decltype(X(boost::move_detail::declval()...), true_type()) test(int); - - template - static no_type test(...); - - static const bool value = sizeof(test(0)) == sizeof(yes_type); - }; - - template - struct is_constructible_with_allocator_prefix - : is_constructible - {}; - -#else // #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - //Without advanced SFINAE expressions, we can't use is_constructible - //so backup to constructible_with_allocator_xxx - - #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template - struct is_constructible_with_allocator_prefix - : constructible_with_allocator_prefix - {}; - - template - struct is_constructible_with_allocator_suffix - : constructible_with_allocator_suffix - {}; - - #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - template - struct is_constructible_with_allocator_prefix - : constructible_with_allocator_prefix - {}; - - template - struct is_constructible_with_allocator_suffix - : constructible_with_allocator_suffix - {}; - - #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -#endif // #if !defined(BOOST_NO_SFINAE_EXPR) - -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -// allocator_arg_t -template < typename OutermostAlloc - , typename InnerAlloc - , typename T - , class ...Args - > -inline void dispatch_allocator_prefix_suffix - ( true_type use_alloc_prefix, OutermostAlloc& outermost_alloc - , InnerAlloc& inner_alloc, T* p, BOOST_FWD_REF(Args) ...args) -{ - (void)use_alloc_prefix; - allocator_traits::construct - ( outermost_alloc, p, allocator_arg, inner_alloc, ::boost::forward(args)...); -} - -// allocator suffix -template < typename OutermostAlloc - , typename InnerAlloc - , typename T - , class ...Args - > -inline void dispatch_allocator_prefix_suffix - ( false_type use_alloc_prefix, OutermostAlloc& outermost_alloc - , InnerAlloc &inner_alloc, T* p, BOOST_FWD_REF(Args)...args) -{ - (void)use_alloc_prefix; - allocator_traits::construct - (outermost_alloc, p, ::boost::forward(args)..., inner_alloc); -} - -template < typename OutermostAlloc - , typename InnerAlloc - , typename T - , class ...Args - > -inline void dispatch_uses_allocator - ( true_type uses_allocator, OutermostAlloc& outermost_alloc - , InnerAlloc& inner_alloc, T* p, BOOST_FWD_REF(Args)...args) -{ - (void)uses_allocator; - //BOOST_STATIC_ASSERT((is_constructible_with_allocator_prefix::value || - // is_constructible_with_allocator_suffix::value )); - dispatch_allocator_prefix_suffix - ( bool_< is_constructible_with_allocator_prefix::value>() - , outermost_alloc, inner_alloc, p, ::boost::forward(args)...); -} - -template < typename OutermostAlloc - , typename InnerAlloc - , typename T - , class ...Args - > -inline void dispatch_uses_allocator - ( false_type uses_allocator, OutermostAlloc & outermost_alloc - , InnerAlloc & inner_alloc - ,T* p, BOOST_FWD_REF(Args)...args) -{ - (void)uses_allocator; (void)inner_alloc; - allocator_traits::construct - (outermost_alloc, p, ::boost::forward(args)...); -} - -#else //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - -#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ -template < typename OutermostAlloc, typename InnerAlloc, typename T\ - BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \ -inline void dispatch_allocator_prefix_suffix\ - (true_type use_alloc_prefix, OutermostAlloc& outermost_alloc,\ - InnerAlloc& inner_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ -{\ - (void)use_alloc_prefix,\ - allocator_traits::construct\ - (outermost_alloc, p, allocator_arg, inner_alloc BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ -}\ -\ -template < typename OutermostAlloc, typename InnerAlloc, typename T\ - BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ -inline void dispatch_allocator_prefix_suffix\ - (false_type use_alloc_prefix, OutermostAlloc& outermost_alloc,\ - InnerAlloc& inner_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ -{\ - (void)use_alloc_prefix;\ - allocator_traits::construct\ - (outermost_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N, inner_alloc);\ -}\ -\ -template < typename OutermostAlloc, typename InnerAlloc, typename T\ - BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ -inline void dispatch_uses_allocator\ - (true_type uses_allocator, OutermostAlloc& outermost_alloc,\ - InnerAlloc& inner_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ -{\ - (void)uses_allocator;\ - dispatch_allocator_prefix_suffix\ - ( bool_< is_constructible_with_allocator_prefix::value >()\ - , outermost_alloc, inner_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ -}\ -\ -template < typename OutermostAlloc, typename InnerAlloc, typename T\ - BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ -inline void dispatch_uses_allocator\ - (false_type uses_allocator, OutermostAlloc &outermost_alloc,\ - InnerAlloc &inner_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ -{\ - (void)uses_allocator; (void)inner_alloc;\ - allocator_traits::construct(outermost_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ -}\ -// -BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) -#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE - -#endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template @@ -923,24 +605,24 @@ class scoped_allocator_adaptor typedef typename outer_traits_type::void_pointer void_pointer; typedef typename outer_traits_type::const_void_pointer const_void_pointer; //! Type: A type with a constant boolean value == true if - //!`allocator_traits::propagate_on_container_copy_assignment::value` is + //!`allocator_traits:: propagate_on_container_copy_assignment::value` is //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: propagate_on_container_copy_assignment propagate_on_container_copy_assignment; //! Type: A type with a constant boolean value == true if - //!`allocator_traits::propagate_on_container_move_assignment::value` is + //!`allocator_traits:: propagate_on_container_move_assignment::value` is //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: propagate_on_container_move_assignment propagate_on_container_move_assignment; //! Type: A type with a constant boolean value == true if - //! `allocator_traits::propagate_on_container_swap::value` is + //! `allocator_traits:: propagate_on_container_swap::value` is //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: propagate_on_container_swap propagate_on_container_swap; //! Type: A type with a constant boolean value == true if - //!`allocator_traits::is_always_equal::value` is + //!`allocator_traits:: is_always_equal::value` is //! true for all Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. typedef typename base_type:: is_always_equal is_always_equal; @@ -1053,12 +735,12 @@ class scoped_allocator_adaptor #endif //BOOST_CONTAINER_DOXYGEN_INVOKED //! Returns: - //! allocator_traits::max_size(outer_allocator()). + //! allocator_traits:: max_size(outer_allocator()). size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW { return outer_traits_type::max_size(this->outer_allocator()); } //! Effects: - //! calls OUTERMOST_ALLOC_TRAITS(*this)::destroy(OUTERMOST(*this), p). + //! calls OUTERMOST_ALLOC_TRAITS(*this):: destroy(OUTERMOST(*this), p). template void destroy(T* p) BOOST_NOEXCEPT_OR_NOTHROW { @@ -1099,12 +781,12 @@ class scoped_allocator_adaptor //! Effects: //! 1) If uses_allocator::value is false calls - //! OUTERMOST_ALLOC_TRAITS(*this)::construct - //! (OUTERMOST(*this), p, std::forward(args)...). + //! OUTERMOST_ALLOC_TRAITS(*this):: + //! construct(OUTERMOST(*this), p, std::forward(args)...). //! //! 2) Otherwise, if uses_allocator::value is true and - //! is_constructible::value is true, calls - //! OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST(*this), p, allocator_arg, + //! is_constructible:: value is true, calls + //! OUTERMOST_ALLOC_TRAITS(*this):: construct(OUTERMOST(*this), p, allocator_arg, //! inner_allocator(), std::forward(args)...). //! //! [Note: In compilers without advanced decltype SFINAE support, is_constructible can't @@ -1112,13 +794,13 @@ class scoped_allocator_adaptor //! constructible_with_allocator_prefix::value. -end note] //! //! 3) Otherwise, if uses_allocator::value is true and - //! is_constructible::value is true, calls - //! OUTERMOST_ALLOC_TRAITS(*this)::construct(OUTERMOST(*this), p, + //! is_constructible:: value is true, calls + //! OUTERMOST_ALLOC_TRAITS(*this):: construct(OUTERMOST(*this), p, //! std::forward(args)..., inner_allocator()). //! //! [Note: In compilers without advanced decltype SFINAE support, is_constructible can't be //! implemented so that condition will be replaced by - //! constructible_with_allocator_suffix::value. -end note] + //! constructible_with_allocator_suffix:: value. -end note] //! //! 4) Otherwise, the program is ill-formed. //! @@ -1126,18 +808,11 @@ class scoped_allocator_adaptor //! to true but the specific constructor does not take an allocator. This definition prevents a silent //! failure to pass an inner allocator to a contained element. -end note] template < typename T, class ...Args> - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - void - #else - typename container_detail::enable_if >::type - #endif - construct(T* p, BOOST_FWD_REF(Args)...args) + void construct(T* p, BOOST_FWD_REF(Args)...args) { container_detail::dispatch_uses_allocator - ( container_detail::bool_::value>() - , get_outermost_allocator(this->outer_allocator()) - , this->inner_allocator() - , p, ::boost::forward(args)...); + ( (get_outermost_allocator)(this->outer_allocator()) + , this->inner_allocator(), p, ::boost::forward(args)...); } #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1146,12 +821,10 @@ class scoped_allocator_adaptor //overload selection problems when the first parameter is a pair. #define BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE(N) \ template < typename T BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\ - typename container_detail::enable_if< container_detail::is_not_pair >::type\ - construct(T* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ + void construct(T* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ {\ container_detail::dispatch_uses_allocator\ - ( container_detail::bool_::value>()\ - , get_outermost_allocator(this->outer_allocator())\ + ( (get_outermost_allocator)(this->outer_allocator())\ , this->inner_allocator(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\ }\ // @@ -1160,81 +833,7 @@ class scoped_allocator_adaptor #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - template - void construct(std::pair* p) - { this->construct_pair(p); } - - template - void construct(container_detail::pair* p) - { this->construct_pair(p); } - - template - void construct(std::pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) - { this->construct_pair(p, ::boost::forward(x), ::boost::forward(y)); } - - template - void construct(container_detail::pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) - { this->construct_pair(p, ::boost::forward(x), ::boost::forward(y)); } - - template - void construct(std::pair* p, const std::pair& x) - { this->construct_pair(p, x); } - - template - void construct( container_detail::pair* p - , const container_detail::pair& x) - { this->construct_pair(p, x); } - - template - void construct( std::pair* p - , BOOST_RV_REF_BEG std::pair BOOST_RV_REF_END x) - { this->construct_pair(p, ::boost::move(x)); } - - template - void construct( container_detail::pair* p - , BOOST_RV_REF_BEG container_detail::pair BOOST_RV_REF_END x) - { this->construct_pair(p, ::boost::move(x)); } - #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - private: - template - void construct_pair(Pair* p) - { - this->construct(container_detail::addressof(p->first)); - BOOST_TRY{ - this->construct(container_detail::addressof(p->second)); - } - BOOST_CATCH(...){ - this->destroy(container_detail::addressof(p->first)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void construct_pair(Pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) - { - this->construct(container_detail::addressof(p->first), ::boost::forward(x)); - BOOST_TRY{ - this->construct(container_detail::addressof(p->second), ::boost::forward(y)); - } - BOOST_CATCH(...){ - this->destroy(container_detail::addressof(p->first)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void construct_pair(Pair* p, const Pair2& pr) - { this->construct_pair(p, pr.first, pr.second); } - - template - void construct_pair(Pair* p, BOOST_RV_REF(Pair2) pr) - { this->construct_pair(p, ::boost::move(pr.first), ::boost::move(pr.second)); } - - //template - //void construct(pair* p, piecewise_construct_t, tuple x, tuple y); public: //Internal function @@ -1246,6 +845,8 @@ class scoped_allocator_adaptor #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; +/// @cond + template struct scoped_allocator_operator_equal { @@ -1278,6 +879,7 @@ struct scoped_allocator_operator_equal { return true; } }; +/// @endcond template inline bool operator==(const scoped_allocator_adaptor& a diff --git a/include/boost/container/scoped_allocator_fwd.hpp b/include/boost/container/scoped_allocator_fwd.hpp index 003ed9f..cddf7fa 100644 --- a/include/boost/container/scoped_allocator_fwd.hpp +++ b/include/boost/container/scoped_allocator_fwd.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// (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) // @@ -13,7 +13,6 @@ //! \file //! This header file forward declares boost::container::scoped_allocator_adaptor -//! and defines the following types: #ifndef BOOST_CONFIG_HPP # include @@ -26,6 +25,7 @@ #include #include #include +#include #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include @@ -59,38 +59,11 @@ namespace boost { namespace container { #endif - template - struct std_allocator_arg_holder - { - static ::std::allocator_arg_t *dummy; - }; - - template - ::std::allocator_arg_t *std_allocator_arg_holder::dummy; #else //BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -//! The allocator_arg_t struct is an empty structure type used as a unique type to -//! disambiguate constructor and function overloading. Specifically, several types -//! have constructors with allocator_arg_t as the first argument, immediately followed -//! by an argument of a type that satisfies Allocator requirements -typedef const std::allocator_arg_t & allocator_arg_t; - -//! A instance of type allocator_arg_t -//! -static allocator_arg_t allocator_arg = BOOST_CONTAINER_DOC1ST(unspecified, *std_allocator_arg_holder<>::dummy); - -template -struct constructible_with_allocator_suffix; - -template -struct constructible_with_allocator_prefix; - -template -struct uses_allocator; - }} // namespace boost { namespace container { #include diff --git a/include/boost/container/uses_allocator.hpp b/include/boost/container/uses_allocator.hpp new file mode 100644 index 0000000..2bcc465 --- /dev/null +++ b/include/boost/container/uses_allocator.hpp @@ -0,0 +1,169 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_USES_ALLOCATOR_HPP +#define BOOST_CONTAINER_USES_ALLOCATOR_HPP + +#include +#include + +namespace boost { +namespace container { + +//! Remark: if a specialization constructible_with_allocator_suffix::value is true, indicates that T may be constructed +//! with an allocator as its last constructor argument. Ideally, all constructors of T (including the +//! copy and move constructors) should have a variant that accepts a final argument of +//! allocator_type. +//! +//! Requires: if a specialization constructible_with_allocator_suffix::value is true, T must have a nested type, +//! allocator_type and at least one constructor for which allocator_type is the last +//! parameter. If not all constructors of T can be called with a final allocator_type argument, +//! and if T is used in a context where a container must call such a constructor, then the program is +//! ill-formed. +//! +//! +//! template > +//! class Z { +//! public: +//! typedef Allocator allocator_type; +//! +//! // Default constructor with optional allocator suffix +//! Z(const allocator_type& a = allocator_type()); +//! +//! // Copy constructor and allocator-extended copy constructor +//! Z(const Z& zz); +//! Z(const Z& zz, const allocator_type& a); +//! }; +//! +//! // Specialize trait for class template Z +//! template > +//! struct constructible_with_allocator_suffix > +//! { static const bool value = true; }; +//! +//! +//! Note: This trait is a workaround inspired by "N2554: The Scoped A Model (Rev 2)" +//! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as +//! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. +//! Applications aiming portability with several compilers should always define this trait. +//! +//! In conforming C++11 compilers or compilers supporting SFINAE expressions +//! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used +//! to detect if a type should be constructed with suffix or prefix allocator arguments. +template +struct constructible_with_allocator_suffix +{ static const bool value = false; }; + +//! Remark: if a specialization constructible_with_allocator_prefix::value is true, indicates that T may be constructed +//! with allocator_arg and T::allocator_type as its first two constructor arguments. +//! Ideally, all constructors of T (including the copy and move constructors) should have a variant +//! that accepts these two initial arguments. +//! +//! Requires: specialization constructible_with_allocator_prefix::value is true, T must have a nested type, +//! allocator_type and at least one constructor for which allocator_arg_t is the first +//! parameter and allocator_type is the second parameter. If not all constructors of T can be +//! called with these initial arguments, and if T is used in a context where a container must call such +//! a constructor, then the program is ill-formed. +//! +//! +//! template > +//! class Y { +//! public: +//! typedef Allocator allocator_type; +//! +//! // Default constructor with and allocator-extended default constructor +//! Y(); +//! Y(allocator_arg_t, const allocator_type& a); +//! +//! // Copy constructor and allocator-extended copy constructor +//! Y(const Y& yy); +//! Y(allocator_arg_t, const allocator_type& a, const Y& yy); +//! +//! // Variadic constructor and allocator-extended variadic constructor +//! template Y(Args&& args...); +//! template +//! Y(allocator_arg_t, const allocator_type& a, BOOST_FWD_REF(Args)... args); +//! }; +//! +//! // Specialize trait for class template Y +//! template > +//! struct constructible_with_allocator_prefix > +//! { static const bool value = true; }; +//! +//! +//! +//! Note: This trait is a workaround inspired by "N2554: The Scoped Allocator Model (Rev 2)" +//! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as +//! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. +//! Applications aiming portability with several compilers should always define this trait. +//! +//! In conforming C++11 compilers or compilers supporting SFINAE expressions +//! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used +//! to detect if a type should be constructed with suffix or prefix allocator arguments. +template +struct constructible_with_allocator_prefix +{ static const bool value = false; }; + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace container_detail { + +template +struct uses_allocator_imp +{ + // Use SFINAE (Substitution Failure Is Not An Error) to detect the + // presence of an 'allocator_type' nested type convertilble from Allocator. + private: + typedef char yes_type; + struct no_type{ char dummy[2]; }; + + // Match this function if T::allocator_type exists and is + // implicitly convertible from Allocator + template + static yes_type test(typename U::allocator_type); + + // Match this function if T::allocator_type exists and it's type is `erased_type`. + template + static typename container_detail::enable_if + < container_detail::is_same + , yes_type + >::type test(const V&); + + // Match this function if TypeT::allocator_type does not exist or is + // not convertible from Allocator. + template + static no_type test(...); + static Allocator alloc; // Declared but not defined + + public: + static const bool value = sizeof(test(alloc)) == sizeof(yes_type); +}; + +} //namespace container_detail { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Remark: Automatically detects whether T has a nested allocator_type that is convertible from +//! Allocator. Meets the BinaryTypeTrait requirements ([meta.rqmts] 20.4.1). A program may +//! specialize this type to define uses_allocator::value as true for a T of user-defined type if T does not +//! have a nested allocator_type but is nonetheless constructible using the specified Allocator where either: +//! the first argument of a constructor has type allocator_arg_t and the second argument has type Alloc or +//! the last argument of a constructor has type Alloc. +//! +//! Result: uses_allocator::value== true if a type T::allocator_type +//! exists and either is_convertible::value != false or T::allocator_type +//! is an alias `erased_type`. False otherwise. +template +struct uses_allocator + : container_detail::uses_allocator_imp +{}; + +}} //namespace boost::container + +#endif //BOOST_CONTAINER_USES_ALLOCATOR_HPP diff --git a/include/boost/container/uses_allocator_fwd.hpp b/include/boost/container/uses_allocator_fwd.hpp new file mode 100644 index 0000000..d8fe67f --- /dev/null +++ b/include/boost/container/uses_allocator_fwd.hpp @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_USES_ALLOCATOR_FWD_HPP +#define BOOST_CONTAINER_USES_ALLOCATOR_FWD_HPP + +#include +#include + +//! \file +//! This header forward declares boost::container::constructible_with_allocator_prefix, +//! boost::container::constructible_with_allocator_suffix and +//! boost::container::uses_allocator. Also defines the following types: + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + struct std_allocator_arg_holder + { + static ::std::allocator_arg_t *dummy; + }; + + template + ::std::allocator_arg_t *std_allocator_arg_holder::dummy; + +typedef const std::allocator_arg_t & allocator_arg_t; + +#else + +//! The allocator_arg_t struct is an empty structure type used as a unique type to +//! disambiguate constructor and function overloading. Specifically, several types +//! have constructors with allocator_arg_t as the first argument, immediately followed +//! by an argument of a type that satisfies Allocator requirements +typedef unspecified allocator_arg_t; + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! The `erased_type` struct is an empty struct that serves as a placeholder for a type +//! T in situations where the actual type T is determined at runtime. For example, +//! the nested type, `allocator_type`, is an alias for `erased_type` in classes that +//! use type-erased allocators. +struct erased_type {}; + +//! A instance of type +//! allocator_arg_t +static allocator_arg_t allocator_arg = BOOST_CONTAINER_DOC1ST(unspecified, *std_allocator_arg_holder<>::dummy); + +// @cond + +template +struct constructible_with_allocator_suffix; + +template +struct constructible_with_allocator_prefix; + +template +struct uses_allocator; + +// @endcond + +}} // namespace boost { namespace container { + +#endif //BOOST_CONTAINER_USES_ALLOCATOR_HPP diff --git a/proj/vc7ide/alloc_lib.vcproj b/proj/vc7ide/alloc_lib.vcproj index eec4f59..f192f21 100644 --- a/proj/vc7ide/alloc_lib.vcproj +++ b/proj/vc7ide/alloc_lib.vcproj @@ -102,6 +102,27 @@ + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + @@ -181,6 +205,9 @@ + + diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index c726408..178ee63 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -119,10 +119,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pair_test", "pair_test.vcpr ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scoped_allocator_adaptor_test", "scoped_allocator_adaptor.vcproj", "{B4E9FB12-7D7C-4461-83A9-5EB2C78E608F}" - 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 @@ -223,6 +219,90 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_alloc_stable_vector_b 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 Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -355,10 +435,6 @@ Global {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 - {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 @@ -453,6 +529,90 @@ Global {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 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 035bcc0..01a87f7 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -162,7 +162,10 @@ RelativePath="..\..\..\..\boost\container\throw_exception.hpp"> + RelativePath="..\..\..\..\boost\container\uses_allocator.hpp"> + + @@ -192,7 +195,7 @@ RelativePath="..\..\..\..\boost\container\detail\alloc_lib.h"> + RelativePath="..\..\..\..\boost\container\detail\alloc_lib.hpp"> @@ -203,6 +206,12 @@ + + + + @@ -221,6 +230,12 @@ + + + + @@ -281,12 +296,18 @@ + + + + @@ -312,6 +333,67 @@ RelativePath="..\..\..\..\boost\container\detail\workaround.hpp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -348,6 +457,9 @@ + + @@ -396,6 +508,9 @@ + + @@ -412,6 +527,9 @@ + + diff --git a/proj/vc7ide/doc_pmr.vcproj b/proj/vc7ide/doc_pmr.vcproj new file mode 100644 index 0000000..9806522 --- /dev/null +++ b/proj/vc7ide/doc_pmr.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/global_resource.vcproj b/proj/vc7ide/global_resource.vcproj new file mode 100644 index 0000000..bc996f5 --- /dev/null +++ b/proj/vc7ide/global_resource.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/memory_resource_test.vcproj b/proj/vc7ide/memory_resource_test.vcproj new file mode 100644 index 0000000..45b62ac --- /dev/null +++ b/proj/vc7ide/memory_resource_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/monotonic_buffer_resource_test.vcproj b/proj/vc7ide/monotonic_buffer_resource_test.vcproj new file mode 100644 index 0000000..8dea90c --- /dev/null +++ b/proj/vc7ide/monotonic_buffer_resource_test.vcproj @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_deque_test.vcproj b/proj/vc7ide/pmr_deque_test.vcproj new file mode 100644 index 0000000..d34a65c --- /dev/null +++ b/proj/vc7ide/pmr_deque_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_flat_map_test.vcproj b/proj/vc7ide/pmr_flat_map_test.vcproj new file mode 100644 index 0000000..141eebc --- /dev/null +++ b/proj/vc7ide/pmr_flat_map_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_flat_set_test.vcproj b/proj/vc7ide/pmr_flat_set_test.vcproj new file mode 100644 index 0000000..a11d96c --- /dev/null +++ b/proj/vc7ide/pmr_flat_set_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_list_test.vcproj b/proj/vc7ide/pmr_list_test.vcproj new file mode 100644 index 0000000..a3c9343 --- /dev/null +++ b/proj/vc7ide/pmr_list_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_map_test.vcproj b/proj/vc7ide/pmr_map_test.vcproj new file mode 100644 index 0000000..93120a4 --- /dev/null +++ b/proj/vc7ide/pmr_map_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_set_test.vcproj b/proj/vc7ide/pmr_set_test.vcproj new file mode 100644 index 0000000..2935011 --- /dev/null +++ b/proj/vc7ide/pmr_set_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_slist_test.vcproj b/proj/vc7ide/pmr_slist_test.vcproj new file mode 100644 index 0000000..c8a2d98 --- /dev/null +++ b/proj/vc7ide/pmr_slist_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_small_vector_test.vcproj b/proj/vc7ide/pmr_small_vector_test.vcproj new file mode 100644 index 0000000..6291009 --- /dev/null +++ b/proj/vc7ide/pmr_small_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_stable_vector_test.vcproj b/proj/vc7ide/pmr_stable_vector_test.vcproj new file mode 100644 index 0000000..5647142 --- /dev/null +++ b/proj/vc7ide/pmr_stable_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_string_test.vcproj b/proj/vc7ide/pmr_string_test.vcproj new file mode 100644 index 0000000..7160fd4 --- /dev/null +++ b/proj/vc7ide/pmr_string_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/pmr_vector_test.vcproj b/proj/vc7ide/pmr_vector_test.vcproj new file mode 100644 index 0000000..5c5249f --- /dev/null +++ b/proj/vc7ide/pmr_vector_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/polymorphic_allocator_test.vcproj b/proj/vc7ide/polymorphic_allocator_test.vcproj new file mode 100644 index 0000000..607cc9e --- /dev/null +++ b/proj/vc7ide/polymorphic_allocator_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/resource_adaptor.vcproj b/proj/vc7ide/resource_adaptor.vcproj new file mode 100644 index 0000000..82679cd --- /dev/null +++ b/proj/vc7ide/resource_adaptor.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/scoped_allocator_adaptor.vcproj b/proj/vc7ide/scoped_allocator_adaptor_test.vcproj similarity index 100% rename from proj/vc7ide/scoped_allocator_adaptor.vcproj rename to proj/vc7ide/scoped_allocator_adaptor_test.vcproj diff --git a/proj/vc7ide/synchronized_pool_resource_test.vcproj b/proj/vc7ide/synchronized_pool_resource_test.vcproj new file mode 100644 index 0000000..997e2c1 --- /dev/null +++ b/proj/vc7ide/synchronized_pool_resource_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unsynchronized_pool_resource_test.vcproj b/proj/vc7ide/unsynchronized_pool_resource_test.vcproj new file mode 100644 index 0000000..a11d708 --- /dev/null +++ b/proj/vc7ide/unsynchronized_pool_resource_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/uses_allocator_test.vcproj b/proj/vc7ide/uses_allocator_test.vcproj new file mode 100644 index 0000000..92f7094 --- /dev/null +++ b/proj/vc7ide/uses_allocator_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dlmalloc.cpp b/src/dlmalloc.cpp new file mode 100644 index 0000000..6ab6de3 --- /dev/null +++ b/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/dlmalloc_ext_2_8_6.c b/src/dlmalloc_ext_2_8_6.c index 4896dfb..0b2df5c 100644 --- a/src/dlmalloc_ext_2_8_6.c +++ b/src/dlmalloc_ext_2_8_6.c @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// (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) // @@ -8,8 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// - -#define BOOST_CONTAINER_SOURCE #include #include "errno.h" //dlmalloc bug EINVAL is used in posix_memalign without checking LACKS_ERRNO_H @@ -1074,7 +1072,7 @@ static int internal_multialloc_arrays return 1; } -BOOST_CONTAINER_DECL int boost_cont_multialloc_arrays +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; @@ -1127,10 +1125,10 @@ static boost_cont_malloc_stats_t get_malloc_stats(mstate m) return ret; } -BOOST_CONTAINER_DECL size_t boost_cont_size(const void *p) +size_t boost_cont_size(const void *p) { return DL_SIZE_IMPL(p); } -BOOST_CONTAINER_DECL void* boost_cont_malloc(size_t bytes) +void* boost_cont_malloc(size_t bytes) { size_t received_bytes; ensure_initialization(); @@ -1138,7 +1136,7 @@ BOOST_CONTAINER_DECL void* boost_cont_malloc(size_t bytes) (BOOST_CONTAINER_ALLOCATE_NEW, 1, bytes, bytes, &received_bytes, 0).first; } -BOOST_CONTAINER_DECL void boost_cont_free(void* mem) +void boost_cont_free(void* mem) { mstate ms = (mstate)gm; if (!ok_magic(ms)) { @@ -1150,7 +1148,7 @@ BOOST_CONTAINER_DECL void boost_cont_free(void* mem) } } -BOOST_CONTAINER_DECL void* boost_cont_memalign(size_t bytes, size_t alignment) +void* boost_cont_memalign(size_t bytes, size_t alignment) { void *addr; ensure_initialization(); @@ -1161,7 +1159,7 @@ BOOST_CONTAINER_DECL void* boost_cont_memalign(size_t bytes, size_t alignment) return addr; } -BOOST_CONTAINER_DECL int boost_cont_multialloc_nodes +int boost_cont_multialloc_nodes (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain) { int ret = 0; @@ -1177,12 +1175,12 @@ BOOST_CONTAINER_DECL int boost_cont_multialloc_nodes return ret; } -BOOST_CONTAINER_DECL size_t boost_cont_footprint() +size_t boost_cont_footprint() { return ((mstate)gm)->footprint; } -BOOST_CONTAINER_DECL size_t boost_cont_allocated_memory() +size_t boost_cont_allocated_memory() { size_t alloc_mem = 0; mstate m = (mstate)gm; @@ -1227,13 +1225,13 @@ BOOST_CONTAINER_DECL size_t boost_cont_allocated_memory() return alloc_mem; } -BOOST_CONTAINER_DECL size_t boost_cont_chunksize(const void *p) +size_t boost_cont_chunksize(const void *p) { return chunksize(mem2chunk(p)); } -BOOST_CONTAINER_DECL int boost_cont_all_deallocated() +int boost_cont_all_deallocated() { return !s_allocated_memory; } -BOOST_CONTAINER_DECL boost_cont_malloc_stats_t boost_cont_malloc_stats() +boost_cont_malloc_stats_t boost_cont_malloc_stats() { mstate ms = (mstate)gm; if (ok_magic(ms)) { @@ -1246,16 +1244,16 @@ BOOST_CONTAINER_DECL boost_cont_malloc_stats_t boost_cont_malloc_stats() } } -BOOST_CONTAINER_DECL size_t boost_cont_in_use_memory() +size_t boost_cont_in_use_memory() { return s_allocated_memory; } -BOOST_CONTAINER_DECL int boost_cont_trim(size_t pad) +int boost_cont_trim(size_t pad) { ensure_initialization(); return dlmalloc_trim(pad); } -BOOST_CONTAINER_DECL int boost_cont_grow +int boost_cont_grow (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received) { mstate ms = (mstate)gm; @@ -1279,7 +1277,7 @@ BOOST_CONTAINER_DECL int boost_cont_grow return 0; } -BOOST_CONTAINER_DECL int boost_cont_shrink +int boost_cont_shrink (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit) { mstate ms = (mstate)gm; @@ -1297,7 +1295,7 @@ BOOST_CONTAINER_DECL int boost_cont_shrink } -BOOST_CONTAINER_DECL void* boost_cont_alloc +void* boost_cont_alloc (size_t minbytes, size_t preferred_bytes, size_t *received_bytes) { //ensure_initialization provided by boost_cont_allocation_command @@ -1305,7 +1303,7 @@ BOOST_CONTAINER_DECL void* boost_cont_alloc (BOOST_CONTAINER_ALLOCATE_NEW, 1, minbytes, preferred_bytes, received_bytes, 0).first; } -BOOST_CONTAINER_DECL void boost_cont_multidealloc(boost_cont_memchain *pchain) +void boost_cont_multidealloc(boost_cont_memchain *pchain) { mstate ms = (mstate)gm; if (!ok_magic(ms)) { @@ -1315,7 +1313,7 @@ BOOST_CONTAINER_DECL void boost_cont_multidealloc(boost_cont_memchain *pchain) internal_multialloc_free(ms, pchain); } -BOOST_CONTAINER_DECL int boost_cont_malloc_check() +int boost_cont_malloc_check() { #ifdef DEBUG mstate ms = (mstate)gm; @@ -1333,7 +1331,7 @@ BOOST_CONTAINER_DECL int boost_cont_malloc_check() } -BOOST_CONTAINER_DECL boost_cont_command_ret_t boost_cont_allocation_command +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) { @@ -1408,11 +1406,50 @@ BOOST_CONTAINER_DECL boost_cont_command_ret_t boost_cont_allocation_command return ret; } -BOOST_CONTAINER_DECL int boost_cont_mallopt(int param_number, int value) +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 diff --git a/src/global_resource.cpp b/src/global_resource.cpp new file mode 100644 index 0000000..23ca978 --- /dev/null +++ b/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 //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) + { return new char[bytes]; (void)bytes; (void)alignment; } + + virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) + { delete[]((char*)p); (void)bytes; (void)alignment; } + + 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/monotonic_buffer_resource.cpp b/src/monotonic_buffer_resource.cpp new file mode 100644 index 0000000..8e5cc89 --- /dev/null +++ b/src/monotonic_buffer_resource.cpp @@ -0,0 +1,154 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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(0u) + , m_current_buffer_size(0u) + , m_next_buffer_size(initial_next_buffer_size) +{} + +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(0u) + , m_current_buffer_size(0u) + , m_next_buffer_size(minimum_buffer_size) +{ //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::container_detail::max_value(buffer_size, std::size_t(initial_next_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(); } + +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/pool_resource.cpp b/src/pool_resource.cpp new file mode 100644 index 0000000..4df7ee2 --- /dev/null +++ b/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; + + public: + explicit pool_data_t(std::size_t initial_blocks_per_chunk) + : block_slist_base(), 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::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::container_detail::min_value(max_blocks_per_chunk, next_blocks_per_chunk); + //Avoid overflow + blocks_per_chunk = boost::container::container_detail::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::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::container_detail::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::container_detail::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/synchronized_pool_resource.cpp b/src/synchronized_pool_resource.cpp new file mode 100644 index 0000000..b98bed4 --- /dev/null +++ b/src/synchronized_pool_resource.cpp @@ -0,0 +1,123 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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; + +class dlmalloc_sync_scoped_lock +{ + void *m_sync; + + public: + explicit dlmalloc_sync_scoped_lock(void *sync) + : m_sync(sync) + { + if(!dlmalloc_sync_lock(m_sync)){ + throw_bad_alloc(); + } + } + + ~dlmalloc_sync_scoped_lock() + { + dlmalloc_sync_unlock(m_sync); + } +}; + +} //namespace { + +namespace boost { +namespace container { +namespace pmr { + +synchronized_pool_resource::synchronized_pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT + : m_pool_resource(opts, upstream), m_opaque_sync() +{} + +synchronized_pool_resource::synchronized_pool_resource() BOOST_NOEXCEPT + : m_pool_resource(), m_opaque_sync() +{} + +synchronized_pool_resource::synchronized_pool_resource(memory_resource* upstream) BOOST_NOEXCEPT + : m_pool_resource(upstream), m_opaque_sync() +{} + +synchronized_pool_resource::synchronized_pool_resource(const pool_options& opts) BOOST_NOEXCEPT + : m_pool_resource(opts), m_opaque_sync() +{} + +synchronized_pool_resource::~synchronized_pool_resource() //virtual +{ + if(m_opaque_sync) + dlmalloc_sync_destroy(m_opaque_sync); +} + +void synchronized_pool_resource::release() +{ + if(m_opaque_sync){ //If there is no mutex, no allocation could be done + 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 +{ + if(!m_opaque_sync){ //If there is no mutex, no allocation could be done + m_opaque_sync = dlmalloc_sync_create(); + if(!m_opaque_sync){ + throw_bad_alloc(); + } + } + dlmalloc_sync_scoped_lock lock(m_opaque_sync); (void)lock; + 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 +{ + dlmalloc_sync_scoped_lock lock(m_opaque_sync); (void)lock; + 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/unsynchronized_pool_resource.cpp b/src/unsynchronized_pool_resource.cpp new file mode 100644 index 0000000..0c84f69 --- /dev/null +++ b/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/test/Jamfile.v2 b/test/Jamfile.v2 index 074630b..55e2245 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,6 +11,12 @@ # 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: diff --git a/test/alloc_basic_test.cpp b/test/alloc_basic_test.cpp index 8413d79..4bfdcf4 100644 --- a/test/alloc_basic_test.cpp +++ b/test/alloc_basic_test.cpp @@ -8,7 +8,7 @@ // ////////////////////////////////////////////////////////////////////////////// -#include +#include #include #include #include @@ -18,50 +18,50 @@ using namespace boost::container; bool basic_test() { size_t received = 0; - if(!boost_cont_all_deallocated()) + if(!dlmalloc_all_deallocated()) return false; - void *ptr = boost_cont_alloc(50, 98, &received); - if(boost_cont_size(ptr) != received) + void *ptr = dlmalloc_alloc(50, 98, &received); + if(dlmalloc_size(ptr) != received) return false; - if(boost_cont_allocated_memory() != boost_cont_chunksize(ptr)) + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) return false; - if(boost_cont_all_deallocated()) + if(dlmalloc_all_deallocated()) return false; - boost_cont_grow(ptr, received + 20, received + 30, &received); + dlmalloc_grow(ptr, received + 20, received + 30, &received); - if(boost_cont_allocated_memory() != boost_cont_chunksize(ptr)) + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) return false; - if(boost_cont_size(ptr) != received) + if(dlmalloc_size(ptr) != received) return false; - if(!boost_cont_shrink(ptr, 100, 140, &received, 1)) + if(!dlmalloc_shrink(ptr, 100, 140, &received, 1)) return false; - if(boost_cont_allocated_memory() != boost_cont_chunksize(ptr)) + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) return false; - if(!boost_cont_shrink(ptr, 0, 140, &received, 1)) + if(!dlmalloc_shrink(ptr, 0, 140, &received, 1)) return false; - if(boost_cont_allocated_memory() != boost_cont_chunksize(ptr)) + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) return false; - if(boost_cont_shrink(ptr, 0, received/2, &received, 1)) + if(dlmalloc_shrink(ptr, 0, received/2, &received, 1)) return false; - if(boost_cont_allocated_memory() != boost_cont_chunksize(ptr)) + if(dlmalloc_allocated_memory() != dlmalloc_chunksize(ptr)) return false; - if(boost_cont_size(ptr) != received) + if(dlmalloc_size(ptr) != received) return false; - boost_cont_free(ptr); + dlmalloc_free(ptr); - boost_cont_malloc_check(); - if(!boost_cont_all_deallocated()) + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) return false; return true; } @@ -69,7 +69,7 @@ bool basic_test() bool vector_test() { typedef boost::container::vector > Vector; - if(!boost_cont_all_deallocated()) + if(!dlmalloc_all_deallocated()) return false; { const int NumElem = 1000; @@ -86,7 +86,7 @@ bool vector_test() new_buf = &v[0]; } } - if(!boost_cont_all_deallocated()) + if(!dlmalloc_all_deallocated()) return false; return true; } @@ -94,7 +94,7 @@ bool vector_test() bool list_test() { typedef boost::container::list > List; - if(!boost_cont_all_deallocated()) + if(!dlmalloc_all_deallocated()) return false; { const int NumElem = 1000; @@ -102,7 +102,7 @@ bool list_test() int values[NumElem]; l.insert(l.end(), &values[0], &values[NumElem]); } - if(!boost_cont_all_deallocated()) + if(!dlmalloc_all_deallocated()) return false; return true; } diff --git a/test/alloc_full_test.cpp b/test/alloc_full_test.cpp index 9147047..a88c560 100644 --- a/test/alloc_full_test.cpp +++ b/test/alloc_full_test.cpp @@ -17,7 +17,7 @@ #include #include #include //std::remove -#include +#include namespace boost { namespace container { namespace test { @@ -30,9 +30,9 @@ enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocat bool test_allocation() { - if(!boost_cont_all_deallocated()) + if(!dlmalloc_all_deallocated()) return false; - boost_cont_malloc_check(); + dlmalloc_malloc_check(); for( deallocation_type t = DirectDeallocation ; t != EndDeallocationType ; t = (deallocation_type)((int)t + 1)){ @@ -40,7 +40,7 @@ bool test_allocation() //std::size_t free_memory = a.get_free_memory(); for(int i = 0; i != NumIt; ++i){ - void *ptr = boost_cont_malloc(i); + void *ptr = dlmalloc_malloc(i); if(!ptr) break; buffers.push_back(ptr); @@ -52,7 +52,7 @@ bool test_allocation() for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ - boost_cont_free(buffers[j]); + dlmalloc_free(buffers[j]); } } break; @@ -61,7 +61,7 @@ bool test_allocation() for(int j = (int)buffers.size() ;j-- ;){ - boost_cont_free(buffers[j]); + dlmalloc_free(buffers[j]); } } break; @@ -71,7 +71,7 @@ bool test_allocation() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } } @@ -79,14 +79,14 @@ bool test_allocation() default: break; } - if(!boost_cont_all_deallocated()) + 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; } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated(); } //This test allocates until there is no more memory @@ -95,12 +95,12 @@ bool test_allocation() bool test_allocation_shrink() { - boost_cont_malloc_check(); + dlmalloc_malloc_check(); std::vector buffers; //Allocate buffers with extra memory for(int i = 0; i != NumIt; ++i){ - void *ptr = boost_cont_malloc(i*2); + void *ptr = dlmalloc_malloc(i*2); if(!ptr) break; buffers.push_back(ptr); @@ -111,12 +111,12 @@ bool test_allocation_shrink() ;i < max ; ++i){ std::size_t try_received_size = 0; - void* try_result = boost_cont_allocation_command + 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 = boost_cont_allocation_command + void* result = dlmalloc_allocation_command ( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, i*2 , i, &received_size, (char*)buffers[i]).first; @@ -141,11 +141,11 @@ bool test_allocation_shrink() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); } //This test allocates until there is no more memory @@ -154,12 +154,12 @@ bool test_allocation_shrink() bool test_allocation_expand() { - boost_cont_malloc_check(); + dlmalloc_malloc_check(); std::vector buffers; //Allocate buffers with extra memory for(int i = 0; i != NumIt; ++i){ - void *ptr = boost_cont_malloc(i); + void *ptr = dlmalloc_malloc(i); if(!ptr) break; buffers.push_back(ptr); @@ -173,7 +173,7 @@ bool test_allocation_expand() 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(boost_cont_allocation_command + 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 @@ -191,11 +191,11 @@ bool test_allocation_expand() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); } //This test allocates until there is no more memory @@ -210,10 +210,10 @@ bool test_allocation_shrink_and_expand() //Allocate buffers wand store received sizes for(int i = 0; i != NumIt; ++i){ std::size_t received_size = 0; - void *ptr = boost_cont_allocation_command + void *ptr = dlmalloc_allocation_command (BOOST_CONTAINER_ALLOCATE_NEW, 1, i, i*2, &received_size, 0).first; if(!ptr){ - ptr = boost_cont_allocation_command + ptr = dlmalloc_allocation_command ( BOOST_CONTAINER_ALLOCATE_NEW, 1, 1, i*2, &received_size, 0).first; if(!ptr) break; @@ -229,7 +229,7 @@ bool test_allocation_shrink_and_expand() std::size_t received_size = 0; bool size_reduced_flag; if(true == (size_reduced_flag = !! - boost_cont_allocation_command + 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])){ @@ -249,7 +249,7 @@ bool test_allocation_shrink_and_expand() if(!size_reduced[i]) continue; std::size_t received_size = 0; std::size_t request_size = received_sizes[i]; - if(boost_cont_allocation_command + if(dlmalloc_allocation_command ( BOOST_CONTAINER_EXPAND_FWD, 1, request_size , request_size, &received_size, (char*)buffers[i]).first){ if(received_size != request_size){ @@ -266,11 +266,11 @@ bool test_allocation_shrink_and_expand() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } - return 0 != boost_cont_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); } //This test allocates until there is no more memory @@ -280,12 +280,12 @@ bool test_allocation_shrink_and_expand() bool test_allocation_deallocation_expand() { - boost_cont_malloc_check(); + dlmalloc_malloc_check(); std::vector buffers; //Allocate buffers with extra memory for(int i = 0; i != NumIt; ++i){ - void *ptr = boost_cont_malloc(i); + void *ptr = dlmalloc_malloc(i); if(!ptr) break; buffers.push_back(ptr); @@ -297,7 +297,7 @@ bool test_allocation_deallocation_expand() ;i < max ;++i){ if(i%2){ - boost_cont_free(buffers[i]); + dlmalloc_free(buffers[i]); buffers[i] = 0; } } @@ -313,7 +313,7 @@ bool test_allocation_deallocation_expand() std::size_t preferred_size = i*2; preferred_size = min_size > preferred_size ? min_size : preferred_size; - while(boost_cont_allocation_command + 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 @@ -336,11 +336,11 @@ bool test_allocation_deallocation_expand() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); } //This test allocates until there is no more memory @@ -352,14 +352,14 @@ bool test_allocation_deallocation_expand() bool test_allocation_with_reuse() { - boost_cont_malloc_check(); + 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 = boost_cont_malloc(i*sizeof_object); + void *ptr = dlmalloc_malloc(i*sizeof_object); if(!ptr) break; buffers.push_back(ptr); @@ -370,7 +370,7 @@ bool test_allocation_with_reuse() for(int i = 0, max = (int)buffers.size() - 1 ;i < max ;++i){ - boost_cont_free(buffers[i]); + dlmalloc_free(buffers[i]); } //Save the unique buffer and clear vector @@ -382,7 +382,7 @@ bool test_allocation_with_reuse() 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; - boost_cont_command_ret_t ret = boost_cont_allocation_command + 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 @@ -396,9 +396,9 @@ bool test_allocation_with_reuse() ptr = ret.first; } //There should be only a single block so deallocate it - boost_cont_free(ptr); - boost_cont_malloc_check(); - if(!boost_cont_all_deallocated()) + dlmalloc_free(ptr); + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) return false; } return true; @@ -410,26 +410,26 @@ bool test_allocation_with_reuse() bool test_aligned_allocation() { - boost_cont_malloc_check(); + 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 = boost_cont_memalign(i-1, j); + void *ptr = dlmalloc_memalign(i-1, j); if(!ptr){ return false; } if(((std::size_t)ptr & (j - 1)) != 0) return false; - boost_cont_free(ptr); + dlmalloc_free(ptr); //if(!a.all_memory_deallocated() || !a.check_sanity()){ // return false; //} } } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); } //This test allocates memory with different alignments @@ -437,7 +437,7 @@ bool test_aligned_allocation() bool test_continuous_aligned_allocation() { - boost_cont_malloc_check(); + dlmalloc_malloc_check(); std::vector buffers; //Allocate aligned buffers in a loop //and then deallocate it @@ -447,7 +447,7 @@ bool test_continuous_aligned_allocation() 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 = boost_cont_memalign(i-1, j); + void *ptr = dlmalloc_memalign(i-1, j); buffers.push_back(ptr); if(!ptr){ continue_loop = false; @@ -459,7 +459,7 @@ bool test_continuous_aligned_allocation() } //Deallocate all for(int k = (int)buffers.size(); k--;){ - boost_cont_free(buffers[k]); + dlmalloc_free(buffers[k]); } buffers.clear(); //if(!a.all_memory_deallocated() && a.check_sanity()) @@ -468,15 +468,15 @@ bool test_continuous_aligned_allocation() break; } } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated();//a.all_memory_deallocated() && a.check_sanity(); + 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() { - boost_cont_malloc_check(); + dlmalloc_malloc_check(); for( deallocation_type t = DirectDeallocation ; t != EndDeallocationType ; t = (deallocation_type)((int)t + 1)){ @@ -486,7 +486,7 @@ bool test_many_equal_allocation() //Allocate buffers with extra memory for(int i = 0; i != NumIt; ++i){ - void *ptr = boost_cont_malloc(i); + void *ptr = dlmalloc_malloc(i); if(!ptr) break; //if(!a.check_sanity()) @@ -500,7 +500,7 @@ bool test_many_equal_allocation() ;i < max ;++i){ if(i%2){ - boost_cont_free(buffers2[i]); + dlmalloc_free(buffers2[i]); buffers2[i] = 0; } } @@ -510,10 +510,10 @@ bool test_many_equal_allocation() std::vector buffers; for(int i = 0; i != NumIt/10; ++i){ - boost_cont_memchain chain; + dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - boost_cont_multialloc_nodes((i+1)*2, i+1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); - boost_cont_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&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; @@ -535,7 +535,7 @@ bool test_many_equal_allocation() for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ - boost_cont_free(buffers[j]); + dlmalloc_free(buffers[j]); } } break; @@ -544,7 +544,7 @@ bool test_many_equal_allocation() for(int j = (int)buffers.size() ;j-- ;){ - boost_cont_free(buffers[j]); + dlmalloc_free(buffers[j]); } } break; @@ -554,7 +554,7 @@ bool test_many_equal_allocation() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } } @@ -570,7 +570,7 @@ bool test_many_equal_allocation() ;j < max ;++j){ int pos = (j%4)*((int)buffers2.size())/4; - boost_cont_free(buffers2[pos]); + dlmalloc_free(buffers2[pos]); buffers2.erase(buffers2.begin()+pos); } @@ -578,8 +578,8 @@ bool test_many_equal_allocation() //a.all_memory_deallocated() && a.check_sanity(); //if(!ok) return ok; } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated(); } //This test allocates multiple values until there is no more memory @@ -587,7 +587,7 @@ bool test_many_equal_allocation() bool test_many_different_allocation() { - boost_cont_malloc_check(); + dlmalloc_malloc_check(); const std::size_t ArraySize = 11; std::size_t requested_sizes[ArraySize]; for(std::size_t i = 0; i < ArraySize; ++i){ @@ -603,7 +603,7 @@ bool test_many_different_allocation() //Allocate buffers with extra memory for(int i = 0; i != NumIt; ++i){ - void *ptr = boost_cont_malloc(i); + void *ptr = dlmalloc_malloc(i); if(!ptr) break; buffers2.push_back(ptr); @@ -615,17 +615,17 @@ bool test_many_different_allocation() ;i < max ;++i){ if(i%2){ - boost_cont_free(buffers2[i]); + dlmalloc_free(buffers2[i]); buffers2[i] = 0; } } std::vector buffers; for(int i = 0; i != NumIt; ++i){ - boost_cont_memchain chain; + dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - boost_cont_multialloc_arrays(ArraySize, requested_sizes, 1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); - boost_cont_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&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; @@ -643,7 +643,7 @@ bool test_many_different_allocation() for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ - boost_cont_free(buffers[j]); + dlmalloc_free(buffers[j]); } } break; @@ -652,7 +652,7 @@ bool test_many_different_allocation() for(int j = (int)buffers.size() ;j-- ;){ - boost_cont_free(buffers[j]); + dlmalloc_free(buffers[j]); } } break; @@ -662,7 +662,7 @@ bool test_many_different_allocation() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; - boost_cont_free(buffers[pos]); + dlmalloc_free(buffers[pos]); buffers.erase(buffers.begin()+pos); } } @@ -678,7 +678,7 @@ bool test_many_different_allocation() ;j < max ;++j){ int pos = (j%4)*((int)buffers2.size())/4; - boost_cont_free(buffers2[pos]); + dlmalloc_free(buffers2[pos]); buffers2.erase(buffers2.begin()+pos); } @@ -686,53 +686,53 @@ bool test_many_different_allocation() //a.all_memory_deallocated() && a.check_sanity(); //if(!ok) return ok; } - boost_cont_malloc_check(); - return 0 != boost_cont_all_deallocated(); + dlmalloc_malloc_check(); + return 0 != dlmalloc_all_deallocated(); } bool test_many_deallocation() { const std::size_t ArraySize = 11; - std::vector buffers; + 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){ - boost_cont_memchain chain; + dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - boost_cont_multialloc_arrays(ArraySize, requested_sizes, 1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); - boost_cont_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&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){ - boost_cont_multidealloc(&buffers[i]); + dlmalloc_multidealloc(&buffers[i]); } buffers.clear(); - boost_cont_malloc_check(); - if(!boost_cont_all_deallocated()) + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) return false; for(int i = 0; i != NumIt; ++i){ - boost_cont_memchain chain; + dlmalloc_memchain chain; BOOST_CONTAINER_MEMCHAIN_INIT(&chain); - boost_cont_multialloc_nodes(ArraySize, i*4+1, DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &chain); - boost_cont_memchain_it it = BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(&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){ - boost_cont_multidealloc(&buffers[i]); + dlmalloc_multidealloc(&buffers[i]); } buffers.clear(); - boost_cont_malloc_check(); - if(!boost_cont_all_deallocated()) + dlmalloc_malloc_check(); + if(!dlmalloc_all_deallocated()) return false; return true; @@ -835,7 +835,7 @@ bool test_all_allocation() return false; } - return 0 != boost_cont_all_deallocated(); + return 0 != dlmalloc_all_deallocated(); } }}} //namespace boost { namespace container { namespace test { diff --git a/test/allocator_argument_tester.hpp b/test/allocator_argument_tester.hpp new file mode 100644 index 0000000..5050ff4 --- /dev/null +++ b/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::container_detail::bool_ propagate_on_container_copy_assignment; + typedef boost::container::container_detail::bool_ propagate_on_container_move_assignment; + typedef boost::container::container_detail::bool_ propagate_on_container_swap; + typedef boost::container::container_detail::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/test/derived_from_memory_resource.hpp b/test/derived_from_memory_resource.hpp new file mode 100644 index 0000000..a8097a7 --- /dev/null +++ b/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/test/global_resource_test.cpp b/test/global_resource_test.cpp new file mode 100644 index 0000000..860b463 --- /dev/null +++ b/test/global_resource_test.cpp @@ -0,0 +1,116 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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; + +std::size_t allocation_count = 0; + +#ifdef BOOST_MSVC +#pragma warning (push) +#pragma warning (disable : 4290) +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40700) && (__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 + +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); +} + +#ifdef BOOST_MSVC +#pragma warning (pop) +#endif + +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); +} + +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() +{ + test_new_delete_resource(); + test_null_memory_resource(); + test_default_resource(); + return ::boost::report_errors(); +} diff --git a/test/memory_resource_logger.hpp b/test/memory_resource_logger.hpp new file mode 100644 index 0000000..e8bc405 --- /dev/null +++ b/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/test/memory_resource_test.cpp b/test/memory_resource_test.cpp new file mode 100644 index 0000000..4c4cb51 --- /dev/null +++ b/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/test/monotonic_buffer_resource_test.cpp b/test/monotonic_buffer_resource_test.cpp new file mode 100644 index 0000000..568eb7b --- /dev/null +++ b/test/monotonic_buffer_resource_test.cpp @@ -0,0 +1,462 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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() +{ + //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); + const std::size_t BufSz = monotonic_buffer_resource::initial_next_buffer_size; + //Now allocate storage, and stub it as the return buffer + //for "derived_from_memory_resource": + boost::move_detail::aligned_storage::type buf; + 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 ocurred + 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); +} + +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/test/pmr_deque_test.cpp b/test/pmr_deque_test.cpp new file mode 100644 index 0000000..1b1a4bd --- /dev/null +++ b/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::container_detail::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/test/pmr_flat_map_test.cpp b/test/pmr_flat_map_test.cpp new file mode 100644 index 0000000..2969db2 --- /dev/null +++ b/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::container_detail::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/test/pmr_flat_set_test.cpp b/test/pmr_flat_set_test.cpp new file mode 100644 index 0000000..55cd5b3 --- /dev/null +++ b/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::container_detail::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/test/pmr_list_test.cpp b/test/pmr_list_test.cpp new file mode 100644 index 0000000..8b3bd22 --- /dev/null +++ b/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::container_detail::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/test/pmr_map_test.cpp b/test/pmr_map_test.cpp new file mode 100644 index 0000000..d50c10f --- /dev/null +++ b/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::container_detail::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/test/pmr_set_test.cpp b/test/pmr_set_test.cpp new file mode 100644 index 0000000..6788eb5 --- /dev/null +++ b/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::container_detail::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/test/pmr_slist_test.cpp b/test/pmr_slist_test.cpp new file mode 100644 index 0000000..ed4b5ae --- /dev/null +++ b/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/test/pmr_small_vector_test.cpp b/test/pmr_small_vector_test.cpp new file mode 100644 index 0000000..cc6a0bd --- /dev/null +++ b/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::container_detail::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/test/pmr_stable_vector_test.cpp b/test/pmr_stable_vector_test.cpp new file mode 100644 index 0000000..d0a280f --- /dev/null +++ b/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::container_detail::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/test/pmr_static_vector_test.cpp b/test/pmr_static_vector_test.cpp new file mode 100644 index 0000000..6681f7c --- /dev/null +++ b/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/test/pmr_string_test.cpp b/test/pmr_string_test.cpp new file mode 100644 index 0000000..628865f --- /dev/null +++ b/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::container_detail::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/test/pmr_vector_test.cpp b/test/pmr_vector_test.cpp new file mode 100644 index 0000000..df0cac1 --- /dev/null +++ b/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::container_detail::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/test/polymorphic_allocator_test.cpp b/test/polymorphic_allocator_test.cpp new file mode 100644 index 0000000..449b706 --- /dev/null +++ b/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 == container_detail::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 == container_detail::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/test/pool_resource_test.hpp b/test/pool_resource_test.hpp new file mode 100644 index 0000000..267ad2b --- /dev/null +++ b/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 + //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/test/propagation_test_allocator.hpp b/test/propagation_test_allocator.hpp new file mode 100644 index 0000000..ca6d8e5 --- /dev/null +++ b/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::container_detail::bool_ propagate_on_container_copy_assignment; + typedef boost::container::container_detail::bool_ propagate_on_container_move_assignment; + typedef boost::container::container_detail::bool_ propagate_on_container_swap; + typedef boost::container::container_detail::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/test/resource_adaptor_test.cpp b/test/resource_adaptor_test.cpp new file mode 100644 index 0000000..df72f85 --- /dev/null +++ b/test/resource_adaptor_test.cpp @@ -0,0 +1,186 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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" + +using namespace boost::container::pmr; + +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; }; + + 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() +{ + derived_from_resource_adaptor_stateful dra; + char dummy = 0; + dra.get_allocator().allocate_return = &dummy; + void *allocate_ret = dra.do_allocate(998, 1234); + BOOST_TEST(allocate_ret == &dummy); + BOOST_TEST(dra.get_allocator().allocate_size == 998); +} + +void test_do_deallocate() +{ + derived_from_resource_adaptor_stateful dra; + char dummy = 0; + dra.do_deallocate(&dummy, 1234, 753); + BOOST_TEST(dra.get_allocator().deallocate_p == &dummy); + BOOST_TEST(dra.get_allocator().deallocate_size == 1234); +} + +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(); + test_do_deallocate(); + test_do_is_equal(); + return ::boost::report_errors(); +} diff --git a/test/scoped_allocator_adaptor_test.cpp b/test/scoped_allocator_adaptor_test.cpp index 04b7f81..699d56a 100644 --- a/test/scoped_allocator_adaptor_test.cpp +++ b/test/scoped_allocator_adaptor_test.cpp @@ -19,81 +19,7 @@ #include #include -using namespace boost::container; - -template -class test_allocator -{ - BOOST_COPYABLE_AND_MOVABLE(test_allocator) - public: - - template - struct rebind - { - typedef test_allocator other; - }; - - typedef container_detail::bool_ propagate_on_container_copy_assignment; - typedef container_detail::bool_ propagate_on_container_move_assignment; - typedef container_detail::bool_ propagate_on_container_swap; - typedef container_detail::bool_ is_always_equal; - typedef T value_type; - - test_allocator() - : m_move_contructed(false), m_move_assigned(false) - {} - - test_allocator(const test_allocator&) - : m_move_contructed(false), m_move_assigned(false) - {} - - test_allocator(BOOST_RV_REF(test_allocator) ) - : m_move_contructed(true), m_move_assigned(false) - {} - - template - test_allocator(BOOST_RV_REF_BEG test_allocator BOOST_RV_REF_END) - : m_move_contructed(true), m_move_assigned(false) - {} - - template - test_allocator(const test_allocator &) - {} - - test_allocator & operator=(BOOST_COPY_ASSIGN_REF(test_allocator)) - { - return *this; - } - - test_allocator & operator=(BOOST_RV_REF(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 test_allocator& - , const test_allocator&) -{ return true; } - -template -bool operator!=( const test_allocator& - , const test_allocator&) -{ return false; } - +#include "allocator_argument_tester.hpp" template struct tagged_integer @@ -113,148 +39,6 @@ struct mark_on_destructor bool destroyed; }; -//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 test_allocator allocator_type; - typedef allocator_type allocator_constructor_type; - struct nat{}; - typedef nat allocator_arg_type; -}; - -template -struct uses_allocator_base -{ - typedef test_allocator allocator_type; - typedef allocator_type allocator_constructor_type; - typedef 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 mark_on_scoped_allocation - : uses_allocator_base -{ - private: - BOOST_COPYABLE_AND_MOVABLE(mark_on_scoped_allocation) - - public: - - typedef uses_allocator_base base_type; - - //0 user argument constructors - mark_on_scoped_allocation() - : construction_type(NotUsesAllocator), value(0) - {} - - explicit mark_on_scoped_allocation - (typename base_type::allocator_constructor_type) - : construction_type(ConstructibleSuffix), value(0) - {} - - explicit mark_on_scoped_allocation - (typename base_type::allocator_arg_type, typename base_type::allocator_constructor_type) - : construction_type(ConstructiblePrefix), value(0) - {} - - //1 user argument constructors - explicit mark_on_scoped_allocation(int i) - : construction_type(NotUsesAllocator), value(i) - {} - - mark_on_scoped_allocation - (int i, typename base_type::allocator_constructor_type) - : construction_type(ConstructibleSuffix), value(i) - {} - - mark_on_scoped_allocation - ( typename base_type::allocator_arg_type - , typename base_type::allocator_constructor_type - , int i) - : construction_type(ConstructiblePrefix), value(i) - {} - - //Copy constructors - mark_on_scoped_allocation(const mark_on_scoped_allocation &other) - : construction_type(NotUsesAllocator), value(other.value) - {} - - mark_on_scoped_allocation( const mark_on_scoped_allocation &other - , typename base_type::allocator_constructor_type) - : construction_type(ConstructibleSuffix), value(other.value) - {} - - mark_on_scoped_allocation( typename base_type::allocator_arg_type - , typename base_type::allocator_constructor_type - , const mark_on_scoped_allocation &other) - : construction_type(ConstructiblePrefix), value(other.value) - {} - - //Move constructors - mark_on_scoped_allocation(BOOST_RV_REF(mark_on_scoped_allocation) other) - : construction_type(NotUsesAllocator), value(other.value) - { other.value = 0; other.construction_type = NotUsesAllocator; } - - mark_on_scoped_allocation( BOOST_RV_REF(mark_on_scoped_allocation) other - , typename base_type::allocator_constructor_type) - : construction_type(ConstructibleSuffix), value(other.value) - { other.value = 0; other.construction_type = ConstructibleSuffix; } - - mark_on_scoped_allocation( typename base_type::allocator_arg_type - , typename base_type::allocator_constructor_type - , BOOST_RV_REF(mark_on_scoped_allocation) 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 - < ::mark_on_scoped_allocation > -{ - static const bool value = true; -}; - -template -struct constructible_with_allocator_suffix - < ::mark_on_scoped_allocation > -{ - static const bool value = true; -}; - -} //namespace container { -} //namespace boost { - #include #include @@ -263,19 +47,21 @@ struct constructible_with_allocator_suffix int main() { - typedef test_allocator, 0> OuterAlloc; - typedef test_allocator, 10> Outer10IdAlloc; - typedef test_allocator, 0> Rebound9OuterAlloc; - typedef test_allocator, 1> InnerAlloc1; - typedef test_allocator, 2> InnerAlloc2; - typedef test_allocator, 11> Inner11IdAlloc1; + using namespace boost::container; - typedef test_allocator, 0, false> OuterAllocFalseHasTrueTypes; - typedef test_allocator, 0, true> OuterAllocTrueHasTrueTypes; - typedef test_allocator, 1, false> InnerAlloc1FalseHasTrueTypes; - typedef test_allocator, 1, true> InnerAlloc1TrueHasTrueTypes; - typedef test_allocator, 2, false> InnerAlloc2FalseHasTrueTypes; - typedef test_allocator, 2, true> InnerAlloc2TrueHasTrueTypes; + 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; @@ -301,81 +87,81 @@ int main() , InnerAlloc2 > Rebound9Scoped2Inner; //outer_allocator_type - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< OuterAlloc + BOOST_STATIC_ASSERT(( container_detail::is_same< OuterAlloc , Scoped0Inner::outer_allocator_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< OuterAlloc + BOOST_STATIC_ASSERT(( container_detail::is_same< OuterAlloc , Scoped1Inner::outer_allocator_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< OuterAlloc + BOOST_STATIC_ASSERT(( container_detail::is_same< OuterAlloc , Scoped2Inner::outer_allocator_type>::value )); //value_type - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::value_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::value_type , Scoped0Inner::value_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::value_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::value_type , Scoped1Inner::value_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::value_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::value_type , Scoped2Inner::value_type>::value )); //size_type - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::size_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::size_type , Scoped0Inner::size_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::size_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::size_type , Scoped1Inner::size_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::size_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::size_type , Scoped2Inner::size_type>::value )); //difference_type - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::difference_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::difference_type , Scoped0Inner::difference_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::difference_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::difference_type , Scoped1Inner::difference_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::difference_type + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::difference_type , Scoped2Inner::difference_type>::value )); //pointer - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::pointer , Scoped0Inner::pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::pointer , Scoped1Inner::pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::pointer , Scoped2Inner::pointer>::value )); //const_pointer - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::const_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::const_pointer , Scoped0Inner::const_pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::const_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::const_pointer , Scoped1Inner::const_pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::const_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::const_pointer , Scoped2Inner::const_pointer>::value )); //void_pointer - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::void_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::void_pointer , Scoped0Inner::void_pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::void_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::void_pointer , Scoped1Inner::void_pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::void_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::void_pointer , Scoped2Inner::void_pointer>::value )); //const_void_pointer - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::const_void_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::const_void_pointer , Scoped0Inner::const_void_pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::const_void_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::const_void_pointer , Scoped1Inner::const_void_pointer>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< allocator_traits::const_void_pointer + BOOST_STATIC_ASSERT(( container_detail::is_same< allocator_traits::const_void_pointer , Scoped2Inner::const_void_pointer>::value )); //rebind - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same >::other + BOOST_STATIC_ASSERT(( container_detail::is_same >::other , Rebound9Scoped0Inner >::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same >::other + BOOST_STATIC_ASSERT(( container_detail::is_same >::other , Rebound9Scoped1Inner >::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same >::other + BOOST_STATIC_ASSERT(( container_detail::is_same >::other , Rebound9Scoped2Inner >::value )); //inner_allocator_type - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< Scoped0Inner + BOOST_STATIC_ASSERT(( container_detail::is_same< Scoped0Inner , Scoped0Inner::inner_allocator_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< scoped_allocator_adaptor + BOOST_STATIC_ASSERT(( container_detail::is_same< scoped_allocator_adaptor , Scoped1Inner::inner_allocator_type>::value )); - BOOST_STATIC_ASSERT(( boost::container::container_detail::is_same< scoped_allocator_adaptor + BOOST_STATIC_ASSERT(( container_detail::is_same< scoped_allocator_adaptor , Scoped2Inner::inner_allocator_type>::value )); { @@ -746,7 +532,7 @@ int main() } { - vector > > dummy; + vector > > dummy; dummy.push_back(0); } @@ -781,34 +567,16 @@ int main() //construct { - - BOOST_STATIC_ASSERT(( !boost::container::uses_allocator - < ::mark_on_scoped_allocation - , test_allocator - >::value )); - BOOST_STATIC_ASSERT(( boost::container::uses_allocator - < ::mark_on_scoped_allocation - , test_allocator - >::value )); - BOOST_STATIC_ASSERT(( boost::container::uses_allocator - < ::mark_on_scoped_allocation - , test_allocator - >::value )); - BOOST_STATIC_ASSERT(( boost::container::constructible_with_allocator_prefix - < ::mark_on_scoped_allocation >::value )); - BOOST_STATIC_ASSERT(( boost::container::constructible_with_allocator_suffix - < ::mark_on_scoped_allocation >::value )); - //////////////////////////////////////////////////////////// //First check scoped allocator with just OuterAlloc. - //In this case OuterAlloc (test_allocator with tag 0) should be + //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 ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s0i.construct(&dummy); @@ -820,7 +588,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s0i.construct(&dummy); @@ -832,7 +600,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s0i.construct(&dummy); @@ -846,7 +614,7 @@ int main() //Check construction with 1 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s0i.construct(&dummy, 1); @@ -858,7 +626,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s0i.construct(&dummy, 2); @@ -870,7 +638,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s0i.construct(&dummy, 3); @@ -884,14 +652,14 @@ int main() } //////////////////////////////////////////////////////////// //Then check scoped allocator with OuterAlloc and InnerAlloc. - //In this case InnerAlloc (test_allocator with tag 1) should be + //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 ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s1i.construct(&dummy); @@ -903,7 +671,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s1i.construct(&dummy); @@ -915,7 +683,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s1i.construct(&dummy); @@ -929,7 +697,7 @@ int main() //Check construction with 1 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s1i.construct(&dummy, 1); @@ -941,7 +709,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s1i.construct(&dummy, 2); @@ -953,7 +721,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); s1i.construct(&dummy, 3); @@ -972,31 +740,31 @@ int main() //////////////////////////////////////////////////////////// //First check scoped allocator with just OuterAlloc. - //In this case OuterAlloc (test_allocator with tag 0) should be + //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(( boost::container::is_scoped_allocator + BOOST_STATIC_ASSERT(( is_scoped_allocator ::value )); - BOOST_STATIC_ASSERT(( ::boost::container::container_detail::is_same - < boost::container::outermost_allocator::type + BOOST_STATIC_ASSERT(( container_detail::is_same + < outermost_allocator::type , Outer10IdAlloc >::value )); - BOOST_STATIC_ASSERT(( ::boost::container::container_detail::is_same + BOOST_STATIC_ASSERT(( container_detail::is_same < ScopedScoped0Inner::outer_allocator_type , scoped_allocator_adaptor >::value )); - BOOST_STATIC_ASSERT(( ::boost::container::container_detail::is_same + BOOST_STATIC_ASSERT(( container_detail::is_same < scoped_allocator_adaptor::outer_allocator_type , Outer10IdAlloc >::value )); ScopedScoped0Inner ssro0i; - Outer10IdAlloc & val = boost::container::outermost_allocator::get(ssro0i); + Outer10IdAlloc & val = outermost_allocator::get(ssro0i); (void)val; //Check construction with 0 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro0i.construct(&dummy); @@ -1008,7 +776,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro0i.construct(&dummy); @@ -1020,7 +788,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro0i.construct(&dummy); @@ -1034,7 +802,7 @@ int main() //Check construction with 1 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro0i.construct(&dummy, 1); @@ -1046,7 +814,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro0i.construct(&dummy, 2); @@ -1058,7 +826,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro0i.construct(&dummy, 3); @@ -1073,37 +841,37 @@ int main() //////////////////////////////////////////////////////////// //Then check scoped allocator with OuterAlloc and InnerAlloc. //In this case inner_allocator_type is not convertible to - //::mark_on_scoped_allocation so uses_allocator + //::allocator_argument_tester so uses_allocator //should be false on all tests. //////////////////////////////////////////////////////////// { //Check outer_allocator_type is scoped - BOOST_STATIC_ASSERT(( boost::container::is_scoped_allocator + BOOST_STATIC_ASSERT(( is_scoped_allocator ::value )); - BOOST_STATIC_ASSERT(( ::boost::container::container_detail::is_same - < boost::container::outermost_allocator::type + BOOST_STATIC_ASSERT(( container_detail::is_same + < outermost_allocator::type , Outer10IdAlloc >::value )); - BOOST_STATIC_ASSERT(( ::boost::container::container_detail::is_same + BOOST_STATIC_ASSERT(( container_detail::is_same < ScopedScoped1Inner::outer_allocator_type , scoped_allocator_adaptor >::value )); - BOOST_STATIC_ASSERT(( ::boost::container::container_detail::is_same + BOOST_STATIC_ASSERT(( container_detail::is_same < scoped_allocator_adaptor::outer_allocator_type , Outer10IdAlloc >::value )); BOOST_STATIC_ASSERT(( ! - ::boost::container::uses_allocator - < ::mark_on_scoped_allocation + uses_allocator + < ::allocator_argument_tester , ScopedScoped1Inner::inner_allocator_type::outer_allocator_type >::value )); ScopedScoped1Inner ssro1i; - Outer10IdAlloc & val = boost::container::outermost_allocator::get(ssro1i); + Outer10IdAlloc & val = outermost_allocator::get(ssro1i); (void)val; //Check construction with 0 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro1i.construct(&dummy); @@ -1115,7 +883,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro1i.construct(&dummy); @@ -1127,7 +895,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro1i.construct(&dummy); @@ -1141,7 +909,7 @@ int main() //Check construction with 1 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro1i.construct(&dummy, 1); @@ -1153,7 +921,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro1i.construct(&dummy, 2); @@ -1165,7 +933,7 @@ int main() dummy.~MarkType(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; MarkType dummy; dummy.~MarkType(); ssro1i.construct(&dummy, 3); @@ -1182,12 +950,12 @@ int main() //Now check propagation to pair //////////////////////////////////////////////////////////// //First check scoped allocator with just OuterAlloc. - //In this case OuterAlloc (test_allocator with tag 0) should be + //In this case OuterAlloc (propagation_test_allocator with tag 0) should be //used to construct types. //////////////////////////////////////////////////////////// { - using boost::container::container_detail::pair; - typedef test_allocator< pair< tagged_integer<0> + using container_detail::pair; + typedef propagation_test_allocator< pair< tagged_integer<0> , tagged_integer<0> >, 0> OuterPairAlloc; // typedef scoped_allocator_adaptor < OuterPairAlloc > ScopedPair0Inner; @@ -1195,7 +963,7 @@ int main() ScopedPair0Inner s0i; //Check construction with 0 user arguments { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; dummy.~MarkTypePair(); @@ -1210,7 +978,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; dummy.~MarkTypePair(); @@ -1225,7 +993,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; dummy.~MarkTypePair(); @@ -1242,7 +1010,7 @@ int main() //Check construction with 1 user arguments for each pair { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; dummy.~MarkTypePair(); @@ -1257,7 +1025,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; dummy.~MarkTypePair(); @@ -1272,7 +1040,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; dummy.~MarkTypePair(); @@ -1288,7 +1056,7 @@ int main() } //Check construction with pair copy construction { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy, dummy2; dummy.~MarkTypePair(); @@ -1303,7 +1071,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy, dummy2(1, 1); dummy.~MarkTypePair(); @@ -1318,7 +1086,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy, dummy2(2, 2); dummy.~MarkTypePair(); @@ -1334,7 +1102,7 @@ int main() } //Check construction with pair move construction { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy, dummy2(3, 3); dummy2.first.construction_type = dummy2.second.construction_type = ConstructibleSuffix; @@ -1354,7 +1122,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy, dummy2(1, 1); dummy.~MarkTypePair(); @@ -1373,7 +1141,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy, dummy2(2, 2); dummy.~MarkTypePair(); @@ -1393,7 +1161,7 @@ int main() } //Check construction with related pair copy construction { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; pair dummy2; @@ -1409,7 +1177,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; pair dummy2(1, 1); @@ -1425,7 +1193,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; pair dummy2(2, 2); @@ -1442,7 +1210,7 @@ int main() } //Check construction with related pair move construction { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; pair dummy2(3, 3); @@ -1458,7 +1226,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; pair dummy2(1, 1); @@ -1474,7 +1242,7 @@ int main() dummy.~MarkTypePair(); } { - typedef ::mark_on_scoped_allocation MarkType; + typedef ::allocator_argument_tester MarkType; typedef pair MarkTypePair; MarkTypePair dummy; pair dummy2(2, 2); diff --git a/test/synchronized_pool_resource_test.cpp b/test/synchronized_pool_resource_test.cpp new file mode 100644 index 0000000..da1589a --- /dev/null +++ b/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/test/unsynchronized_pool_resource_test.cpp b/test/unsynchronized_pool_resource_test.cpp new file mode 100644 index 0000000..298607a --- /dev/null +++ b/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/test/uses_allocator_test.cpp b/test/uses_allocator_test.cpp new file mode 100644 index 0000000..39807f0 --- /dev/null +++ b/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; +}