diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9cb17de..9474715 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost.Interprocess library documentation Jamfile --------------------------------- # -# Copyright Ion Gaztañaga 2005-2007. Use, modification and +# Copyright Ion Gaztanaga 2005-2007. Use, modification and # distribution is subject to the Boost Software License, Version # 1.0. (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index eed8e52..21be343 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -58,6 +58,15 @@ separate compilation. However, the subset used by [*Boost.Interprocess] does not need any separate compilation so the user can define `BOOST_DATE_TIME_NO_LIB` to avoid Boost from trying to automatically link the [*Boost.DateTime]. +In POSIX systems, [*Boost.Interprocess] uses pthread system calls to implement +classes like mutexes, condition variables, etc... In some operating systems, +these POSIX calls are implemented in separate libraries that are not automatically +linked by the compiler. For example, in some Linux systems POSIX pthread functions +are implemented in `librt.a` library, so you might need to add that library +when linking an executable or shared library that uses [*Boost.Interprocess]. +If you obtain linking errors related to those pthread functions, please revise +your system's documentation to know which library implements them. + [endsect] [section:tested_compilers Tested compilers] @@ -162,6 +171,9 @@ also the comparison functor when an allocator is passed in the constructor: [import ../example/doc_map.cpp] [doc_map] +For a more advanced example including containers of containers, see the section +[link interprocess.allocators_containers.containers_explained.containers_of_containers Containers of containers]. + [endsect] [endsect] @@ -551,6 +563,30 @@ behavior as the standard C (stdio.h) `int remove(const char *path)` function. [endsect] +[section:anonymous_shared_memory Anonymous shared memory for UNIX systems] + +Creating a shared memory segment and mapping it can be a bit tedious when several +processes are involved. When processes are related via `fork()` operating system +call in UNIX sytems a simpler method is available using anonymous shared memory. + +This feature has been implemented in UNIX systems mapping the device `\dev\zero` or +just using the `MAP_ANONYMOUS` in a POSIX conformant `mmap` system call. + +This feature is wrapped in [*Boost.Interprocess] using the `anonymous_shared_memory()` +function, which returns a `mapped_region` object holding an anonymous shared memory +segment that can be shared by related processes. + +Here's is an example: + +[import ../example/doc_anonymous_shared_memory.cpp] +[doc_anonymous_shared_memory] + +Once the segment is created, a `fork()` call can +be used so that `region` is used to communicate two related processes. + +[endsect] + + [section:windows_shared_memory Native windows shared memory] Windows operating system also offers shared memory, but the lifetime of this @@ -1298,7 +1334,7 @@ All the mutex types from [*Boost.Interprocess] implement the following operation [blurb ['[*void lock()]]] [*Effects:] - The calling thread tries to obtain ownership of the mutex, and if another thread has ownership of the mutex, it waits until it can obtain the ownership. If a thread takes ownership of the mutex the mutex must be unlocked by the same mutex. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. + The calling thread tries to obtain ownership of the mutex, and if another thread has ownership of the mutex, it waits until it can obtain the ownership. If a thread takes ownership of the mutex the mutex must be unlocked by the same thread. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. [*Throws:] *interprocess_exception* on error. @@ -2129,7 +2165,8 @@ more features and operations, see their reference for more informations [section:lock_conversions Lock Transfers Through Move Semantics] -[blurb [*Interprocess uses its own move semantics emulation code. +[blurb [*Interprocess uses its own move semantics emulation code for compilers +that don't support rvalues references. This is a temporary solution until a Boost move semantics library is accepted.]] Scoped locks and similar utilities offer simple resource management possibilities, @@ -3063,6 +3100,8 @@ To use a managed shared memory, you must include the following header: // managed_shared_memory segment (open_only, "MySharedMemory");//Shared memory object name[c++] +[c++] + //1. If the segment was previously created // equivalent to "open_only". //2. Otherwise, equivalent to "open_only" (size is ignored) @@ -3519,6 +3558,36 @@ Here is an example showing this functionality: [endsect] +[section:managed_memory_segment_atomic_func Executing an object function atomically] + +Sometimes the programmer must execute some code, and needs to execute it with the +guarantee that no other process or thread will create or destroy any named, unique +or anonymous object while executing the functor. A user might want to create several +named objects and initialize them, but those objects should be available for the rest of processes +at once. + +To achieve this, the programmer can use the `atomic_func()` function offered by +managed classes: + +[c++] + + //This object function will create several named objects + create_several_objects_func func(/**/); + + //While executing the function, no other process will be + //able to create or destroy objects + managed_memory.atomic_func(func); + + +Note that `atomic_func` does not prevent other processes from allocating raw memory +or executing member functions for already constructed objects (e.g.: another process +might be pushing elements into a vector placed in the segment). The atomic function +only blocks named, unique and anonymous creation, search and destruction +(concurrent calls to `construct<>`, `find<>`, `find_or_construct<>`, `destroy<>`...) +from other processes. + +[endsect] + [endsect] [section:managed_memory_segment_advanced_features Managed Memory Segment Advanced Features] @@ -3855,7 +3924,7 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * If the parameter `command` only contains the value `expand_bwd` (with optional additional `nothrow_allocation`), the allocator will try to increase the size of the memory block referenced by pointer `reuse_ptr` only moving the start of the - block to a returned new position new_ptr. If it's not possible, it will try to + block to a returned new position `new_ptr`. If it's not possible, it will try to move the start of the block as much as possible as long as this results in `size(new_ptr) >= limit_size`. Success is reported only if this results in `limit_size <= size(new_ptr)`. @@ -3863,7 +3932,7 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * If the parameter `command` only contains the value `allocate_new` (with optional additional `nothrow_allocation`), the allocator will try to allocate memory for `preferred_size` objects. If it's not possible it will try to allocate memory for - at least limit_size` objects. + at least `limit_size` objects. * If the parameter `command` only contains a combination of `expand_fwd` and `allocate_new`, (with optional additional `nothrow_allocation`) the allocator will @@ -3918,8 +3987,8 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * If the user chooses `char` as template argument and a backwards expansion is performed, although properly aligned, the returned buffer might not be suitable because the distance between the new beginning and the old beginning - might not multiple of the type the user wants to construct, because due to internal - restriction the expansion can be slightly bigger than the requested. [*When + might not multiple of the type the user wants to construct, since due to internal + restrictions the expansion can be slightly bigger than the requested bytes. [*When performing backwards expansion, if you have already constructed objects in the old buffer, make sure to specify correctly the type.] @@ -3935,6 +4004,43 @@ requests and the memory waste. [endsect] +[section:copy_on_write_read_only Opening managed shared memory and mapped files with Copy On Write or Read Only modes] + +When mapping a memory segment based on shared memory or files, there is an option to +open them using [*open_copy_on_write] option. This option is similar to `open_only` but +every change the programmer does with this managed segment is kept private to this process +and is not translated to the underlying device (shared memory or file). + +The underlying shared memory or file is opened as read-only so several processes can +share an initial managed segment and make private changes to it. If many processes +open a managed segment in copy on write mode and not modified pages from the managed +segment will be shared between all those processes, with considerable memory savings. + +Opening managed shared memory and mapped files with [*open_read_only] maps the the +underlying device in memory with [*read-only] attributes. This means that any attempt +to write that memory, either creating objects or locking any mutex might result in an +page-fault error (and thus, program termination) from the OS. Read-only mode opens +the underlying device (shared memory, file...) in read-only mode and +can result in considerable memory savings if several processes just want to process +a managed memory segment without modifying it. Read-only mode operations are limited: + +* Read-only mode must be used only from managed classes. If the programmer obtains + the segment manager and tries to use it directly it might result in an access violation. + The reason for this is that the segment manager is placed in the underlying device + and does not nothing about the mode it's been mapped in memory. + +* Only const member functions from managed segments should be used. + +* Additionally, the `find<>` member function avoids using internal locks and can be + used to look for named and unique objects. + +Here's an example that shows the use of these two open modes: + +[import ../example/doc_managed_copy_on_write.cpp] +[doc_managed_copy_on_write] + +[endsect] + [endsect] [section:managed_heap_memory_external_buffer Managed Heap Memory And Managed External Buffer] @@ -4933,6 +5039,56 @@ Boost.Interprocess containers: [endsect] +[section:containers_of_containers Containers of containers] + +When creating containers of containers, each container needs an allocator. +To avoid using several allocators with complex type definitions, we can take +advantage of the type erasure provided by void allocators and the ability +to implicitly convert void allocators in allocators that allocate other types. + +Here we have an example that builds a map in shared memory. Key is a string +and the mapped type is a class that stores several containers: + +[import ../example/doc_complex_map.cpp] +[doc_complex_map] + +[endsect] + +[endsect] + +[section:additional_containers Boost containers compatible with Boost.Interprocess] + +As mentioned, container developers might need to change their implementation to make them +compatible with Boost.Interprocess, because implementation usually ignore allocators with +smart pointers. Hopefully several Boost containers are compatible with [*Interprocess]. + +[section:unordered Boost unordered containers] + +[*Boost.Unordered] containers are compatible with Interprocess, so programmers can store +hash containers in shared memory and memory mapped files. Here's an small example storing +`unordered_map` in shared memory: + +[import ../example/doc_unordered_map.cpp] +[doc_unordered_map] + +[endsect] + +[section:multi_index Boost.MultiIndex containers] + +The widely used [*Boost.MultiIndex] library is compatible with [*Boost.Interprocess] so +we can construct pretty good databases in shared memory. Constructing databases in shared +memory is a bit tougher than in normal memory, usually because those databases contain strings +and those strings need to be placed in shared memory. Shared memory strings require +an allocator in their constructors so this usually makes object insertion a bit more +complicated. + +Here's is an example that shows how to put a multi index container in shared memory: + +[import ../example/doc_multi_index.cpp] +[doc_multi_index] + +[endsect] + [endsect] [section:memory_algorithms Memory allocation algorithms] @@ -6262,7 +6418,7 @@ will manage the index. `segment_manager` will define interesting internal types For example, the index type `flat_map_index` based in `boost::interprocess::flat_map` is just defined as: -[import ../../../boost/interprocess/indexes/flat_map_index.hpp] +[import ../../boost/interprocess/indexes/flat_map_index.hpp] [flat_map_index] @@ -6385,6 +6541,18 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_36_00 Boost 1.36 Release] + +* Added anonymous shared memory for UNIX systems. +* Fixed erroneous `void` return types from `flat_map::erase()` functions. +* Fixed missing move semantics on managed memory classes. +* Added copy_on_write and open_read_only options for shared memory and mapped file managed classes. +* [*ABI breaking]: Added to `mapped_region` the mode used to create it. +* Corrected instantiation errors in void allocators. +* `shared_ptr` is movable and supports aliasing. + +[endsect] + [section:release_notes_boost_1_35_00 Boost 1.35 Release] * Added auxiliary utilities to ease the definition and construction of @@ -6654,20 +6822,6 @@ But the work to implement PF_UNIX-like sockets and doors would be huge [endsect] -[section:future_containers Unordered associative containers and other containers] - -We should be able to construct boost::unordered_xxx family in managed memory segments, -so that there is no code duplication in boost. So [*Boost.Interprocess] should cooperate -with boost container developers instead of duplicating effort writing it's own containers. - -A very interesting project is making [*boost::multi_index] compatible with -[*Boost.Interprocess] ready for shared memory. This could be a good basis for memory -mapped data-bases. The work to achieve this, however, can be huge. It would be -interesting a collaboration with [*Intrusive] library to achieve shared memory -intrusive containers. - -[endsect] - [endsect] [endsect] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 09309d4..eb26876 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost Interprocess Library Example Jamfile -# (C) Copyright Ion Gaztañaga 2006. +# (C) Copyright Ion Gaztanaga 2006. # Use, modification and distribution are subject to the # Boost Software License, Version 1.0. (See accompanying file # LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/example/doc_anonymous_shared_memory.cpp b/example/doc_anonymous_shared_memory.cpp new file mode 100644 index 0000000..b0dbcf2 --- /dev/null +++ b/example/doc_anonymous_shared_memory.cpp @@ -0,0 +1,36 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_anonymous_shared_memory +#include +#include +#include +#include + +int main () +{ + using namespace boost::interprocess; + try{ + //Create an anonymous shared memory segment with size 1000 + mapped_region region(anonymous_shared_memory(1000)); + + //Write all the memory to 1 + std::memset(region.get_address(), 1, region.get_size()); + + //The segment is unmapped when "region" goes out of scope + } + catch(interprocess_exception &ex){ + std::cout << ex.what() << std::endl; + return 1; + } + return 0; +} +//] +#include diff --git a/example/doc_complex_map.cpp b/example/doc_complex_map.cpp new file mode 100644 index 0000000..1d64dac --- /dev/null +++ b/example/doc_complex_map.cpp @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_complex_map +#include +#include +#include +#include +#include + +using namespace boost::interprocess; + +//Typedefs of allocators and containers +typedef managed_shared_memory::segment_manager segment_manager_t; +typedef allocator void_allocator; +typedef allocator int_allocator; +typedef vector int_vector; +typedef allocator int_vector_allocator; +typedef vector int_vector_vector; +typedef allocator char_allocator; +typedef basic_string, char_allocator> char_string; + +class complex_data +{ + int id_; + char_string char_string_; + int_vector_vector int_vector_vector_; + + public: + //Since void_allocator is convertible to any other allocator, we can simplify + //the initialization taking just one allocator for all inner containers. + complex_data(int id, const char *name, const void_allocator &void_alloc) + : id_(id), char_string_(name, void_alloc), int_vector_vector_(void_alloc) + {} + //Other members... +}; + +//Definition of the map holding a string as key and complex_data as mapped type +typedef std::pair map_value_type; +typedef std::pair movable_to_map_value_type; +typedef allocator map_value_type_allocator; +typedef map< char_string, complex_data + , std::less, map_value_type_allocator> complex_map_type; + +int main () +{ + shared_memory_object::remove("MySharedMemory"); + remove_shared_memory_on_destroy remove_on_destroy("MySharedMemory"); + { + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); + + //An allocator convertible to any allocator type + void_allocator alloc_inst (segment.get_segment_manager()); + + //Construct the shared memory map and fill it + complex_map_type *mymap = segment.construct + //(object name), (first ctor parameter, second ctor parameter) + ("MyMap")(std::less(), alloc_inst); + + for(int i = 0; i < 100; ++i){ + //Both key(string) and value(complex_data) need an allocator in their constructors + char_string key_object(alloc_inst); + complex_data mapped_object(i, "default_name", alloc_inst); + map_value_type value(key_object, mapped_object); + //Modify values and insert them in the map + mymap->insert(value); + } + } + return 0; +} +//] +#include diff --git a/example/doc_file_mapping.cpp b/example/doc_file_mapping.cpp index 24d20ac..568f577 100644 --- a/example/doc_file_mapping.cpp +++ b/example/doc_file_mapping.cpp @@ -56,7 +56,6 @@ int main () std::cout << ex.what() << std::endl; return 1; } - std::remove("file.bin"); return 0; } //] diff --git a/example/doc_managed_copy_on_write.cpp b/example/doc_managed_copy_on_write.cpp new file mode 100644 index 0000000..0b8fecc --- /dev/null +++ b/example/doc_managed_copy_on_write.cpp @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_managed_copy_on_write +#include +#include //std::fstream +#include //std::remove +#include //std::distance + +int main() +{ + using namespace boost::interprocess; + + //Try to erase any previous managed segment with the same name + std::remove("MyManagedFile"); + std::remove("MyManagedFile2"); + remove_file_on_destroy destroyer1("MyManagedFile"); + remove_file_on_destroy destroyer2("MyManagedFile2"); + + { + //Create an named integer in a managed mapped file + managed_mapped_file managed_file(create_only, "MyManagedFile", 65536); + managed_file.construct("MyInt")(0u); + + //Now create a copy on write version + managed_mapped_file managed_file_cow(open_copy_on_write, "MyManagedFile"); + + //Erase the int and create a new one + if(!managed_file_cow.destroy("MyInt")) + throw int(0); + managed_file_cow.construct("MyInt2"); + + //Check changes + if(managed_file_cow.find("MyInt").first && !managed_file_cow.find("MyInt2").first) + throw int(0); + + //Check the original is intact + if(!managed_file.find("MyInt").first && managed_file.find("MyInt2").first) + throw int(0); + + { //Dump the modified copy on write segment to a file + std::fstream file("MyManagedFile2", std::ios_base::out | std::ios_base::binary); + if(!file) + throw int(0); + file.write((const char *)managed_file_cow.get_address(), managed_file_cow.get_size()); + } + + //Now open the modified file and test changes + managed_mapped_file managed_file_cow2(open_only, "MyManagedFile2"); + if(managed_file_cow2.find("MyInt").first && !managed_file_cow2.find("MyInt2").first) + throw int(0); + } + { + //Now create a read-only version + managed_mapped_file managed_file_ro(open_read_only, "MyManagedFile"); + + //Check the original is intact + if(!managed_file_ro.find("MyInt").first && managed_file_ro.find("MyInt2").first) + throw int(0); + + //Check the number of named objects using the iterators + if(std::distance(managed_file_ro.named_begin(), managed_file_ro.named_end()) != 1 && + std::distance(managed_file_ro.unique_begin(), managed_file_ro.unique_end()) != 0 ) + throw int(0); + } + return 0; +} +//] +#include diff --git a/example/doc_message_queueA.cpp b/example/doc_message_queueA.cpp index 784ff24..04c1838 100644 --- a/example/doc_message_queueA.cpp +++ b/example/doc_message_queueA.cpp @@ -35,11 +35,9 @@ int main () } } catch(interprocess_exception &ex){ - message_queue::remove("message_queue"); std::cout << ex.what() << std::endl; return 1; } - message_queue::remove("message_queue"); return 0; } diff --git a/example/doc_move_containers.cpp b/example/doc_move_containers.cpp index 65f75f2..aeadf61 100644 --- a/example/doc_move_containers.cpp +++ b/example/doc_move_containers.cpp @@ -53,7 +53,7 @@ int main () //In the following line, no string copy-constructor will be called. //"move_me"'s contents will be transferred to the string created in //the vector - myshmvector->push_back(move(move_me)); + myshmvector->push_back(boost::interprocess::move(move_me)); //The source string is in default constructed state assert(move_me.empty()); @@ -69,7 +69,7 @@ int main () //No string copy-constructor or assignments will be called, but //move constructors and move-assignments. No memory allocation //function will be called in this operations!! - myshmvector->insert(myshmvector->begin(), move(string_to_compare)); + myshmvector->insert(myshmvector->begin(), boost::interprocess::move(string_to_compare)); //Destroy vector. This will free all strings that the vector contains shm.destroy_ptr(myshmvector); diff --git a/example/doc_multi_index.cpp b/example/doc_multi_index.cpp new file mode 100644 index 0000000..24cbd63 --- /dev/null +++ b/example/doc_multi_index.cpp @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_multi_index +#include +#include +#include + +#include +#include +#include + +using namespace boost::interprocess; +namespace bmi = boost::multi_index; + +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator>shm_string; + +//Data to insert in shared memory +struct employee +{ + int id; + int age; + shm_string name; + employee( int id_ + , int age_ + , const char *name_ + , const char_allocator &a) + : id(id_), age(age_), name(name_, a) + {} +}; + +//Tags +struct id{}; +struct age{}; +struct name{}; + +// Define a multi_index_container of employees with following indices: +// - a unique index sorted by employee::int, +// - a non-unique index sorted by employee::name, +// - a non-unique index sorted by employee::age. +typedef bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + managed_shared_memory::allocator::type +> employee_set; + +int main () +{ + //Erase previous shared memory with the name + shared_memory_object::remove("MySharedMemory"); + + try{ + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); + + //Construct the multi_index in shared memory + employee_set *es = segment.construct + ("My MultiIndex Container") //Container's name in shared memory + ( employee_set::ctor_args_list() + , segment.get_allocator()); //Ctor parameters + + //Now insert elements + char_allocator ca(segment.get_allocator()); + es->insert(employee(0,31, "Joe", ca)); + es->insert(employee(1,27, "Robert", ca)); + es->insert(employee(2,40, "John", ca)); + } + catch(...){ + shared_memory_object::remove("MySharedMemory"); + throw; + } + shared_memory_object::remove("MySharedMemory"); + return 0; +} +//] +#include diff --git a/example/doc_shared_memory.cpp b/example/doc_shared_memory.cpp index 4764c9f..3b5b7bc 100644 --- a/example/doc_shared_memory.cpp +++ b/example/doc_shared_memory.cpp @@ -38,7 +38,6 @@ int main () std::cout << ex.what() << std::endl; return 1; } - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_shared_memory2.cpp b/example/doc_shared_memory2.cpp index a8999bb..3fd2da2 100644 --- a/example/doc_shared_memory2.cpp +++ b/example/doc_shared_memory2.cpp @@ -36,9 +36,10 @@ int main () } catch(interprocess_exception &ex){ std::cout << "Unexpected exception: " << ex.what() << std::endl; + shared_memory_object::remove("shared_memory"); return 1; } - + shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_unordered_map.cpp b/example/doc_unordered_map.cpp new file mode 100644 index 0000000..3839c6f --- /dev/null +++ b/example/doc_unordered_map.cpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_unordered_map +#include +#include + +#include //boost::unordered_map +#include //std::equal_to +#include //boost::hash + +int main () +{ + using namespace boost::interprocess; + //Erase previous shared memory with the name + shared_memory_object::remove("MySharedMemory"); + + try{ + //Create shared memory + managed_shared_memory segment(create_only ,"MySharedMemory" ,65536); + + //Note that unordered_map's value_type is std::pair, + //so the allocator must allocate that pair. + typedef int KeyType; + typedef float MappedType; + typedef std::pair ValueType; + + //Typedef the allocator + typedef allocator ShmemAllocator; + + //Alias an unordered_map of ints that uses the previous STL-like allocator. + typedef boost::unordered_map + < KeyType , MappedType + , boost::hash ,std::equal_to + , ShmemAllocator> + MyHashMap; + + //Construct a shared memory hash map. + //Note that the first parameter is the initial bucket count and + //after that, the hash function, the equality function and the allocator + MyHashMap *myhashmap = segment.construct("MyHashMap") //object name + ( 3, boost::hash(), std::equal_to() // + , segment.get_allocator()); //allocator instance + + //Insert data in the hash map + for(int i = 0; i < 100; ++i){ + myhashmap->insert(ValueType(i, (float)i)); + } + } + catch(...){ + shared_memory_object::remove("MySharedMemory"); + throw; + } + shared_memory_object::remove("MySharedMemory"); + return 0; +} +//] +#include diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index 0c00006..fab13ca 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -43,14 +44,14 @@ namespace detail{ template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class adaptive_pool_base : public node_pool_allocation_impl < adaptive_pool_base - < Version, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> + < Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> , Version , T , SegmentManager @@ -60,11 +61,20 @@ class adaptive_pool_base typedef typename SegmentManager::void_pointer void_pointer; typedef SegmentManager segment_manager; typedef adaptive_pool_base - self_t; - typedef detail::shared_adaptive_node_pool - < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; + self_t; + + /// @cond + + template + struct node_pool + { + typedef detail::shared_adaptive_node_pool + < SegmentManager, sizeof_value::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type; + + static type *get(void *p) + { return static_cast(p); } + }; + /// @endcond BOOST_STATIC_ASSERT((Version <=2)); @@ -95,7 +105,7 @@ class adaptive_pool_base template struct rebind { - typedef adaptive_pool_base other; + typedef adaptive_pool_base other; }; /// @cond @@ -105,8 +115,6 @@ class adaptive_pool_base adaptive_pool_base& operator= (const adaptive_pool_base&); - //!Not assignable from other adaptive_pool_base - adaptive_pool_base& operator=(const adaptive_pool_base&); /// @endcond public: @@ -114,14 +122,22 @@ class adaptive_pool_base //!pool. Increments the reference count of the associated node pool. //!Can throw boost::interprocess::bad_alloc adaptive_pool_base(segment_manager *segment_mngr) - : mp_node_pool(detail::get_or_create_node_pool(segment_mngr)) { } + : mp_node_pool(detail::get_or_create_node_pool::type>(segment_mngr)) { } //!Copy constructor from other adaptive_pool_base. Increments the reference //!count of the associated node pool. Never throws adaptive_pool_base(const adaptive_pool_base &other) : mp_node_pool(other.get_node_pool()) { - mp_node_pool->inc_ref_count(); + node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count(); + } + + //!Assignment from other adaptive_pool_base + adaptive_pool_base& operator=(const adaptive_pool_base &other) + { + adaptive_pool_base c(other); + swap(*this, c); + return *this; } //!Copy constructor from related adaptive_pool_base. If not present, constructs @@ -129,23 +145,23 @@ class adaptive_pool_base //!Can throw boost::interprocess::bad_alloc template adaptive_pool_base - (const adaptive_pool_base &other) - : mp_node_pool(detail::get_or_create_node_pool(other.get_segment_manager())) { } + (const adaptive_pool_base &other) + : mp_node_pool(detail::get_or_create_node_pool::type>(other.get_segment_manager())) { } //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws ~adaptive_pool_base() - { detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool)); } + { detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); } //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const + void* get_node_pool() const { return detail::get_pointer(mp_node_pool); } //!Returns the segment manager. //!Never throws segment_manager* get_segment_manager()const - { return mp_node_pool->get_segment_manager(); } + { return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); } //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -154,28 +170,28 @@ class adaptive_pool_base /// @cond private: - node_pool_ptr mp_node_pool; + void_pointer mp_node_pool; /// @endcond }; //!Equality test for same type //!of adaptive_pool_base -template inline -bool operator==(const adaptive_pool_base &alloc1, - const adaptive_pool_base &alloc2) +template inline +bool operator==(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type //!of adaptive_pool_base -template inline -bool operator!=(const adaptive_pool_base &alloc1, - const adaptive_pool_base &alloc2) +template inline +bool operator!=(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 - , std::size_t MaxFreeChunks = 2 + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 , unsigned char OverheadPercent = 5 > class adaptive_pool_v1 @@ -183,19 +199,19 @@ class adaptive_pool_v1 < 1 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > { public: typedef detail::adaptive_pool_base - < 1, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; template struct rebind { - typedef adaptive_pool_v1 other; + typedef adaptive_pool_v1 other; }; adaptive_pool_v1(SegmentManager *segment_mngr) @@ -204,7 +220,7 @@ class adaptive_pool_v1 template adaptive_pool_v1 - (const adaptive_pool_v1 &other) + (const adaptive_pool_v1 &other) : base_t(other) {} }; @@ -220,17 +236,17 @@ class adaptive_pool_v1 //! //!This node allocator shares a segregated storage between all instances //!of adaptive_pool with equal sizeof(T) placed in the same segment -//!group. NodesPerChunk is the number of nodes allocated at once when the allocator -//!needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks -//!that the adaptive node pool will hold. The rest of the totally free chunks will be +//!group. NodesPerBlock is the number of nodes allocated at once when the allocator +//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be //!deallocated with the segment manager. //! //!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: //!(memory usable for nodes / total memory allocated from the segment manager) template < class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class adaptive_pool @@ -239,8 +255,8 @@ class adaptive_pool < 2 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > /// @endcond @@ -248,14 +264,14 @@ class adaptive_pool #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::adaptive_pool_base - < 2, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: typedef detail::version_type version; template struct rebind { - typedef adaptive_pool other; + typedef adaptive_pool other; }; adaptive_pool(SegmentManager *segment_mngr) @@ -264,7 +280,7 @@ class adaptive_pool template adaptive_pool - (const adaptive_pool &other) + (const adaptive_pool &other) : base_t(other) {} @@ -287,7 +303,7 @@ class adaptive_pool template struct rebind { - typedef adaptive_pool other; + typedef adaptive_pool other; }; private: @@ -299,7 +315,7 @@ class adaptive_pool //!Not assignable from //!other adaptive_pool - adaptive_pool& operator=(const adaptive_pool&); + //adaptive_pool& operator=(const adaptive_pool&); public: //!Constructor from a segment manager. If not present, constructs a node @@ -316,7 +332,7 @@ class adaptive_pool //!Can throw boost::interprocess::bad_alloc template adaptive_pool - (const adaptive_pool &other); + (const adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -324,7 +340,7 @@ class adaptive_pool //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const; + void* get_node_pool() const; //!Returns the segment manager. //!Never throws @@ -342,9 +358,9 @@ class adaptive_pool //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -358,9 +374,9 @@ class adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -377,7 +393,7 @@ class adaptive_pool size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -386,11 +402,11 @@ class adaptive_pool multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -403,7 +419,7 @@ class adaptive_pool //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -416,7 +432,7 @@ class adaptive_pool //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -430,15 +446,15 @@ class adaptive_pool //!Equality test for same type //!of adaptive_pool -template inline -bool operator==(const adaptive_pool &alloc1, - const adaptive_pool &alloc2); +template inline +bool operator==(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); //!Inequality test for same type //!of adaptive_pool -template inline -bool operator!=(const adaptive_pool &alloc1, - const adaptive_pool &alloc2); +template inline +bool operator!=(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); #endif diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 08136dc..a6f1eee 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -48,15 +48,17 @@ namespace interprocess { template class allocator { + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + /// @cond private: //Self type typedef allocator self_t; - //Segment manager - typedef SegmentManager segment_manager; - //Pointer to void typedef typename segment_manager::void_pointer aux_pointer_t; @@ -106,8 +108,6 @@ class allocator multiallocation_chain; -// typedef typename SegmentManager:: -// multiallocation_chain multiallocation_chain; /// @endcond @@ -153,7 +153,7 @@ class allocator //!Deallocates memory previously allocated. //!Never throws void deallocate(const pointer &ptr, size_type) - { mp_mngr->deallocate(detail::get_pointer(ptr)); } + { mp_mngr->deallocate((void*)detail::get_pointer(ptr)); } //!Returns the number of elements that could be allocated. //!Never throws @@ -183,7 +183,7 @@ class allocator (command, limit_size, preferred_size, received_size, detail::get_pointer(reuse)); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -196,7 +196,7 @@ class allocator } //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) { @@ -204,7 +204,7 @@ class allocator (mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -219,7 +219,7 @@ class allocator pointer allocate_one() { return this->allocate(1); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -234,7 +234,7 @@ class allocator void deallocate_one(const pointer &p) { return this->deallocate(p, 1); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -253,10 +253,15 @@ class allocator const_pointer address(const_reference value) const { return const_pointer(boost::addressof(value)); } + //!Copy construct an object + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v) + { new((void*)detail::get_pointer(ptr)) value_type(v); } + //!Default construct an object. //!Throws if T's default constructor throws void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + { new((void*)detail::get_pointer(ptr)) value_type; } //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index ec75948..fc94fb7 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,8 +39,8 @@ namespace detail { template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 - , std::size_t MaxFreeChunks = 2 + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 , unsigned char OverheadPercent = 5 > class cached_adaptive_pool_v1 @@ -47,9 +48,9 @@ class cached_adaptive_pool_v1 < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 1> @@ -59,9 +60,9 @@ class cached_adaptive_pool_v1 < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 1> base_t; @@ -70,7 +71,7 @@ class cached_adaptive_pool_v1 struct rebind { typedef cached_adaptive_pool_v1 - other; + other; }; cached_adaptive_pool_v1(SegmentManager *segment_mngr, @@ -81,7 +82,7 @@ class cached_adaptive_pool_v1 template cached_adaptive_pool_v1 (const cached_adaptive_pool_v1 - &other) + &other) : base_t(other) {} }; @@ -100,17 +101,17 @@ class cached_adaptive_pool_v1 //!memory segment. But also caches some nodes privately to //!avoid some synchronization overhead. //! -//!NodesPerChunk is the minimum number of nodes of nodes allocated at once when -//!the allocator needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks -//!that the adaptive node pool will hold. The rest of the totally free chunks will be +//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when +//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be //!deallocated with the segment manager. //! //!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: //!(memory usable for nodes / total memory allocated from the segment manager) template < class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class cached_adaptive_pool @@ -119,9 +120,9 @@ class cached_adaptive_pool < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 2> @@ -134,9 +135,9 @@ class cached_adaptive_pool < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , sizeof_value::value + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 2> base_t; @@ -148,7 +149,7 @@ class cached_adaptive_pool struct rebind { typedef cached_adaptive_pool - other; + other; }; cached_adaptive_pool(SegmentManager *segment_mngr, @@ -158,7 +159,7 @@ class cached_adaptive_pool template cached_adaptive_pool - (const cached_adaptive_pool &other) + (const cached_adaptive_pool &other) : base_t(other) {} @@ -181,7 +182,7 @@ class cached_adaptive_pool template struct rebind { - typedef cached_adaptive_pool other; + typedef cached_adaptive_pool other; }; private: @@ -210,7 +211,7 @@ class cached_adaptive_pool //!Can throw boost::interprocess::bad_alloc template cached_adaptive_pool - (const cached_adaptive_pool &other); + (const cached_adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -236,9 +237,9 @@ class cached_adaptive_pool //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -252,9 +253,9 @@ class cached_adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -271,7 +272,7 @@ class cached_adaptive_pool size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -280,11 +281,11 @@ class cached_adaptive_pool multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -297,7 +298,7 @@ class cached_adaptive_pool //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -310,7 +311,7 @@ class cached_adaptive_pool //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -331,15 +332,15 @@ class cached_adaptive_pool //!Equality test for same type //!of cached_adaptive_pool -template inline -bool operator==(const cached_adaptive_pool &alloc1, - const cached_adaptive_pool &alloc2); +template inline +bool operator==(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); //!Inequality test for same type //!of cached_adaptive_pool -template inline -bool operator!=(const cached_adaptive_pool &alloc1, - const cached_adaptive_pool &alloc2); +template inline +bool operator!=(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); #endif diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 4ee4767..3801dc6 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -39,15 +40,15 @@ namespace detail { template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 + , std::size_t NodesPerBlock = 64 > class cached_node_allocator_v1 : public detail::cached_allocator_impl < T , detail::shared_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk + , sizeof_value::value + , NodesPerBlock > , 1> { @@ -56,8 +57,8 @@ class cached_node_allocator_v1 < T , detail::shared_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk + , sizeof_value::value + , NodesPerBlock > , 1> base_t; @@ -65,7 +66,7 @@ class cached_node_allocator_v1 struct rebind { typedef cached_node_allocator_v1 - other; + other; }; cached_node_allocator_v1(SegmentManager *segment_mngr, @@ -76,7 +77,7 @@ class cached_node_allocator_v1 template cached_node_allocator_v1 (const cached_node_allocator_v1 - &other) + &other) : base_t(other) {} }; @@ -87,7 +88,7 @@ class cached_node_allocator_v1 template < class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class cached_node_allocator /// @cond @@ -95,8 +96,8 @@ class cached_node_allocator < T , detail::shared_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk + , sizeof_value::value + , NodesPerBlock > , 2> /// @endcond @@ -108,8 +109,8 @@ class cached_node_allocator < T , detail::shared_node_pool < SegmentManager - , sizeof(T) - , NodesPerChunk + , sizeof_value::value + , NodesPerBlock > , 2> base_t; @@ -119,7 +120,7 @@ class cached_node_allocator template struct rebind { - typedef cached_node_allocator other; + typedef cached_node_allocator other; }; cached_node_allocator(SegmentManager *segment_mngr, @@ -129,7 +130,7 @@ class cached_node_allocator template cached_node_allocator - (const cached_node_allocator &other) + (const cached_node_allocator &other) : base_t(other) {} @@ -181,7 +182,7 @@ class cached_node_allocator //!Can throw boost::interprocess::bad_alloc template cached_node_allocator - (const cached_node_allocator &other); + (const cached_node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -207,9 +208,9 @@ class cached_node_allocator //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -225,7 +226,7 @@ class cached_node_allocator //!Default construct an object. //!Throws if T's default constructor throws - void construct(const pointer &ptr); + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -242,7 +243,7 @@ class cached_node_allocator size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -251,11 +252,11 @@ class cached_node_allocator multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -268,7 +269,7 @@ class cached_node_allocator //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -281,7 +282,7 @@ class cached_node_allocator //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -302,15 +303,15 @@ class cached_node_allocator //!Equality test for same type //!of cached_node_allocator -template inline -bool operator==(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2); +template inline +bool operator==(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); //!Inequality test for same type //!of cached_node_allocator -template inline -bool operator!=(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2); +template inline +bool operator!=(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 87fea06..c5ef2a4 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -49,7 +49,7 @@ class private_adaptive_node_pool_impl private_adaptive_node_pool_impl &operator=(const private_adaptive_node_pool_impl &); typedef typename SegmentManagerBase::void_pointer void_pointer; - + static const std::size_t PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation; public: typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; @@ -71,18 +71,18 @@ class private_adaptive_node_pool_impl std::size_t hdr_offset; }; - struct chunk_info_t + struct block_info_t : public hdr_offset_holder, public multiset_hook_t { - //An intrusive list of free node from this chunk + //An intrusive list of free node from this block free_nodes_t free_nodes; - friend bool operator <(const chunk_info_t &l, const chunk_info_t &r) + friend bool operator <(const block_info_t &l, const block_info_t &r) { // { return l.free_nodes.size() < r.free_nodes.size(); } //Let's order blocks first by free nodes and then by address - //so that highest address fully free chunks are deallocated. + //so that highest address fully free blocks are deallocated. //This improves returning memory to the OS (trimming). const bool is_less = l.free_nodes.size() < r.free_nodes.size(); const bool is_equal = l.free_nodes.size() == r.free_nodes.size(); @@ -90,11 +90,11 @@ class private_adaptive_node_pool_impl } }; typedef typename bi::make_multiset - >::type chunk_multiset_t; - typedef typename chunk_multiset_t::iterator chunk_iterator; + >::type block_multiset_t; + typedef typename block_multiset_t::iterator block_iterator; static const std::size_t MaxAlign = alignment_of::value; - static const std::size_t HdrSize = ((sizeof(chunk_info_t)-1)/MaxAlign+1)*MaxAlign; + static const std::size_t HdrSize = ((sizeof(block_info_t)-1)/MaxAlign+1)*MaxAlign; static const std::size_t HdrOffsetSize = ((sizeof(hdr_offset_holder)-1)/MaxAlign+1)*MaxAlign; static std::size_t calculate_alignment (std::size_t overhead_percent, std::size_t real_node_size) @@ -102,13 +102,15 @@ class private_adaptive_node_pool_impl //to-do: handle real_node_size != node_size const std::size_t divisor = overhead_percent*real_node_size; const std::size_t dividend = HdrOffsetSize*100; - std::size_t elements_per_subchunk = (dividend - 1)/divisor + 1; + std::size_t elements_per_subblock = (dividend - 1)/divisor + 1; std::size_t candidate_power_of_2 = - upper_power_of_2(elements_per_subchunk*real_node_size + HdrOffsetSize); + upper_power_of_2(elements_per_subblock*real_node_size + HdrOffsetSize); bool overhead_satisfied = false; + //Now calculate the wors-case overhead for a subblock + const std::size_t max_subblock_overhead = HdrSize + PayloadPerAllocation; while(!overhead_satisfied){ - elements_per_subchunk = (candidate_power_of_2 - HdrOffsetSize)/real_node_size; - std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*real_node_size; + elements_per_subblock = (candidate_power_of_2 - max_subblock_overhead)/real_node_size; + const std::size_t overhead_size = candidate_power_of_2 - elements_per_subblock*real_node_size; if(overhead_size*100/candidate_power_of_2 < overhead_percent){ overhead_satisfied = true; } @@ -119,18 +121,30 @@ class private_adaptive_node_pool_impl return candidate_power_of_2; } - static void calculate_num_subchunks - (std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_chunk - ,std::size_t &num_subchunks, std::size_t &real_num_node) + static void calculate_num_subblocks + (std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_block + ,std::size_t &num_subblocks, std::size_t &real_num_node, std::size_t overhead_percent) { - std::size_t elements_per_subchunk = (alignment - HdrOffsetSize)/real_node_size; - std::size_t possible_num_subchunk = (elements_per_chunk - 1)/elements_per_subchunk + 1; - std::size_t hdr_subchunk_elements = (alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/real_node_size; - while(((possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements) < elements_per_chunk){ - ++possible_num_subchunk; + std::size_t elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size; + std::size_t possible_num_subblock = (elements_per_block - 1)/elements_per_subblock + 1; + std::size_t hdr_subblock_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size; + while(((possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements) < elements_per_block){ + ++possible_num_subblock; } - num_subchunks = possible_num_subchunk; - real_num_node = (possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements; + elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size; + bool overhead_satisfied = false; + while(!overhead_satisfied){ + const std::size_t total_data = (elements_per_subblock*(possible_num_subblock-1) + hdr_subblock_elements)*real_node_size; + const std::size_t total_size = alignment*possible_num_subblock; + if((total_size - total_data)*100/total_size < overhead_percent){ + overhead_satisfied = true; + } + else{ + ++possible_num_subblock; + } + } + num_subblocks = possible_num_subblock; + real_num_node = (possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements; } public: @@ -140,27 +154,27 @@ class private_adaptive_node_pool_impl //!Constructor from a segment manager. Never throws private_adaptive_node_pool_impl ( segment_manager_base_type *segment_mngr_base, std::size_t node_size - , std::size_t nodes_per_chunk, std::size_t max_free_chunks + , std::size_t nodes_per_block, std::size_t max_free_blocks , unsigned char overhead_percent ) - : m_max_free_chunks(max_free_chunks) + : m_max_free_blocks(max_free_blocks) , m_real_node_size(lcm(node_size, std::size_t(alignment_of::value))) //Round the size to a power of two value. //This is the total memory size (including payload) that we want to //allocate from the general-purpose allocator - , m_real_chunk_alignment(calculate_alignment(overhead_percent, m_real_node_size)) - //This is the real number of nodes per chunk - , m_num_subchunks(0) + , m_real_block_alignment(calculate_alignment(overhead_percent, m_real_node_size)) + //This is the real number of nodes per block + , m_num_subblocks(0) , m_real_num_node(0) //General purpose allocator , mp_segment_mngr_base(segment_mngr_base) - , m_chunk_multiset() - , m_totally_free_chunks(0) + , m_block_multiset() + , m_totally_free_blocks(0) { - calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node); + calculate_num_subblocks(m_real_block_alignment, m_real_node_size, nodes_per_block, m_num_subblocks, m_real_num_node, overhead_percent); } - //!Destructor. Deallocates all allocated chunks. Never throws + //!Destructor. Deallocates all allocated blocks. Never throws ~private_adaptive_node_pool_impl() { priv_clear(); } @@ -176,8 +190,8 @@ class private_adaptive_node_pool_impl { priv_invariants(); //If there are no free nodes we allocate a new block - if (m_chunk_multiset.empty()){ - priv_alloc_chunk(1); + if (m_block_multiset.empty()){ + priv_alloc_block(1); } //We take the first free node the multiset can't be empty return priv_take_first_node(); @@ -186,11 +200,11 @@ class private_adaptive_node_pool_impl //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - this->priv_reinsert_nodes_in_chunk + this->priv_reinsert_nodes_in_block (multiallocation_iterator::create_simple_range(pElem)); - //Update free chunk count - if(m_totally_free_chunks > m_max_free_chunks){ - this->priv_deallocate_free_chunks(m_max_free_chunks); + //Update free block count + if(m_totally_free_blocks > m_max_free_blocks){ + this->priv_deallocate_free_blocks(m_max_free_blocks); } priv_invariants(); } @@ -201,17 +215,32 @@ class private_adaptive_node_pool_impl { try{ priv_invariants(); - for(std::size_t i = 0; i != n; ++i){ - //If there are no free nodes we allocate all needed chunks - if (m_chunk_multiset.empty()){ - priv_alloc_chunk(((n - i) - 1)/m_real_num_node + 1); + std::size_t i = 0; + while(i != n){ + //If there are no free nodes we allocate all needed blocks + if (m_block_multiset.empty()){ + priv_alloc_block(((n - i) - 1)/m_real_num_node + 1); } - nodes.push_front(priv_take_first_node()); + free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes; + const std::size_t free_nodes_count_before = free_nodes.size(); + if(free_nodes_count_before == m_real_num_node){ + --m_totally_free_blocks; + } + const std::size_t num_elems = ((n-i) < free_nodes_count_before) ? (n-i) : free_nodes_count_before; + for(std::size_t j = 0; j != num_elems; ++j){ + void *new_node = &free_nodes.front(); + free_nodes.pop_front(); + nodes.push_back(new_node); + } + + if(free_nodes.empty()){ + m_block_multiset.erase(m_block_multiset.begin()); + } + i += num_elems; } } catch(...){ this->deallocate_nodes(nodes, nodes.size()); - this->priv_deallocate_free_chunks(m_max_free_chunks); throw; } priv_invariants(); @@ -245,20 +274,20 @@ class private_adaptive_node_pool_impl //!Deallocates the nodes pointed by the multiallocation iterator. Never throws void deallocate_nodes(multiallocation_iterator it) { - this->priv_reinsert_nodes_in_chunk(it); - if(m_totally_free_chunks > m_max_free_chunks){ - this->priv_deallocate_free_chunks(m_max_free_chunks); + this->priv_reinsert_nodes_in_block(it); + if(m_totally_free_blocks > m_max_free_blocks){ + this->priv_deallocate_free_blocks(m_max_free_blocks); } } - void deallocate_free_chunks() - { this->priv_deallocate_free_chunks(0); } + void deallocate_free_blocks() + { this->priv_deallocate_free_blocks(0); } std::size_t num_free_nodes() { - typedef typename chunk_multiset_t::const_iterator citerator; + typedef typename block_multiset_t::const_iterator citerator; std::size_t count = 0; - citerator it (m_chunk_multiset.begin()), itend(m_chunk_multiset.end()); + citerator it (m_block_multiset.begin()), itend(m_block_multiset.end()); for(; it != itend; ++it){ count += it->free_nodes.size(); } @@ -267,76 +296,80 @@ class private_adaptive_node_pool_impl void swap(private_adaptive_node_pool_impl &other) { - assert(m_max_free_chunks == other.m_max_free_chunks); + assert(m_max_free_blocks == other.m_max_free_blocks); assert(m_real_node_size == other.m_real_node_size); - assert(m_real_chunk_alignment == other.m_real_chunk_alignment); + assert(m_real_block_alignment == other.m_real_block_alignment); assert(m_real_num_node == other.m_real_num_node); std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); - std::swap(m_totally_free_chunks, other.m_totally_free_chunks); - m_chunk_multiset.swap(other.m_chunk_multiset); + std::swap(m_totally_free_blocks, other.m_totally_free_blocks); + m_block_multiset.swap(other.m_block_multiset); } + //Deprecated, use deallocate_free_blocks + void deallocate_free_chunks() + { this->priv_deallocate_free_blocks(0); } + private: - void priv_deallocate_free_chunks(std::size_t max_free_chunks) + void priv_deallocate_free_blocks(std::size_t max_free_blocks) { priv_invariants(); //Now check if we've reached the free nodes limit - //and check if we have free chunks. If so, deallocate as much + //and check if we have free blocks. If so, deallocate as much //as we can to stay below the limit - for( chunk_iterator itend = m_chunk_multiset.end() - ; m_totally_free_chunks > max_free_chunks - ; --m_totally_free_chunks + for( block_iterator itend = m_block_multiset.end() + ; m_totally_free_blocks > max_free_blocks + ; --m_totally_free_blocks ){ - assert(!m_chunk_multiset.empty()); - chunk_iterator it = itend; + assert(!m_block_multiset.empty()); + block_iterator it = itend; --it; std::size_t num_nodes = it->free_nodes.size(); assert(num_nodes == m_real_num_node); (void)num_nodes; - m_chunk_multiset.erase_and_dispose - (it, chunk_destroyer(this)); + m_block_multiset.erase_and_dispose + (it, block_destroyer(this)); } } - void priv_reinsert_nodes_in_chunk(multiallocation_iterator it) + void priv_reinsert_nodes_in_block(multiallocation_iterator it) { multiallocation_iterator itend; - chunk_iterator chunk_it(m_chunk_multiset.end()); + block_iterator block_it(m_block_multiset.end()); while(it != itend){ void *pElem = &*it; ++it; priv_invariants(); - chunk_info_t *chunk_info = this->priv_chunk_from_node(pElem); - assert(chunk_info->free_nodes.size() < m_real_num_node); + block_info_t *block_info = this->priv_block_from_node(pElem); + assert(block_info->free_nodes.size() < m_real_num_node); //We put the node at the beginning of the free node list node_t * to_deallocate = static_cast(pElem); - chunk_info->free_nodes.push_front(*to_deallocate); + block_info->free_nodes.push_front(*to_deallocate); - chunk_iterator this_chunk(chunk_multiset_t::s_iterator_to(*chunk_info)); - chunk_iterator next_chunk(this_chunk); - ++next_chunk; + block_iterator this_block(block_multiset_t::s_iterator_to(*block_info)); + block_iterator next_block(this_block); + ++next_block; - //Cache the free nodes from the chunk - std::size_t this_chunk_free_nodes = this_chunk->free_nodes.size(); + //Cache the free nodes from the block + std::size_t this_block_free_nodes = this_block->free_nodes.size(); - if(this_chunk_free_nodes == 1){ - m_chunk_multiset.insert(m_chunk_multiset.begin(), *chunk_info); + if(this_block_free_nodes == 1){ + m_block_multiset.insert(m_block_multiset.begin(), *block_info); } else{ - chunk_iterator next_chunk(this_chunk); - ++next_chunk; - if(next_chunk != chunk_it){ - std::size_t next_free_nodes = next_chunk->free_nodes.size(); - if(this_chunk_free_nodes > next_free_nodes){ - //Now move the chunk to the new position - m_chunk_multiset.erase(this_chunk); - m_chunk_multiset.insert(*chunk_info); + block_iterator next_block(this_block); + ++next_block; + if(next_block != block_it){ + std::size_t next_free_nodes = next_block->free_nodes.size(); + if(this_block_free_nodes > next_free_nodes){ + //Now move the block to the new position + m_block_multiset.erase(this_block); + m_block_multiset.insert(*block_info); } } } - //Update free chunk count - if(this_chunk_free_nodes == m_real_num_node){ - ++m_totally_free_chunks; + //Update free block count + if(this_block_free_nodes == m_real_num_node){ + ++m_totally_free_blocks; } priv_invariants(); } @@ -344,40 +377,40 @@ class private_adaptive_node_pool_impl node_t *priv_take_first_node() { - assert(m_chunk_multiset.begin() != m_chunk_multiset.end()); + assert(m_block_multiset.begin() != m_block_multiset.end()); //We take the first free node the multiset can't be empty - free_nodes_t &free_nodes = m_chunk_multiset.begin()->free_nodes; + free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes; node_t *first_node = &free_nodes.front(); const std::size_t free_nodes_count = free_nodes.size(); assert(0 != free_nodes_count); free_nodes.pop_front(); if(free_nodes_count == 1){ - m_chunk_multiset.erase(m_chunk_multiset.begin()); + m_block_multiset.erase(m_block_multiset.begin()); } else if(free_nodes_count == m_real_num_node){ - --m_totally_free_chunks; + --m_totally_free_blocks; } priv_invariants(); return first_node; } - class chunk_destroyer; - friend class chunk_destroyer; + class block_destroyer; + friend class block_destroyer; - class chunk_destroyer + class block_destroyer { public: - chunk_destroyer(const private_adaptive_node_pool_impl *impl) + block_destroyer(const private_adaptive_node_pool_impl *impl) : mp_impl(impl) {} - void operator()(typename chunk_multiset_t::pointer to_deallocate) + void operator()(typename block_multiset_t::pointer to_deallocate) { std::size_t free_nodes = to_deallocate->free_nodes.size(); (void)free_nodes; assert(free_nodes == mp_impl->m_real_num_node); assert(0 == to_deallocate->hdr_offset); - hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subchunk_from_chunk((chunk_info_t*)detail::get_pointer(to_deallocate)); + hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block((block_info_t*)detail::get_pointer(to_deallocate)); mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder); } const private_adaptive_node_pool_impl *mp_impl; @@ -389,12 +422,12 @@ class private_adaptive_node_pool_impl #ifdef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS #undef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS { - //We iterate through the chunk list to free the memory - chunk_iterator it(m_chunk_multiset.begin()), - itend(m_chunk_multiset.end()), to_deallocate; + //We iterate through the block list to free the memory + block_iterator it(m_block_multiset.begin()), + itend(m_block_multiset.end()), to_deallocate; if(it != itend){ for(++it; it != itend; ++it){ - chunk_iterator prev(it); + block_iterator prev(it); --prev; std::size_t sp = prev->free_nodes.size(), si = it->free_nodes.size(); @@ -405,35 +438,35 @@ class private_adaptive_node_pool_impl { //Check that the total free nodes are correct - it = m_chunk_multiset.begin(); - itend = m_chunk_multiset.end(); + it = m_block_multiset.begin(); + itend = m_block_multiset.end(); std::size_t total_free_nodes = 0; for(; it != itend; ++it){ total_free_nodes += it->free_nodes.size(); } - assert(total_free_nodes >= m_totally_free_chunks*m_real_num_node); + assert(total_free_nodes >= m_totally_free_blocks*m_real_num_node); } { - //Check that the total totally free chunks are correct - it = m_chunk_multiset.begin(); - itend = m_chunk_multiset.end(); - std::size_t total_free_chunks = 0; + //Check that the total totally free blocks are correct + it = m_block_multiset.begin(); + itend = m_block_multiset.end(); + std::size_t total_free_blocks = 0; for(; it != itend; ++it){ - total_free_chunks += (it->free_nodes.size() == m_real_num_node); + total_free_blocks += (it->free_nodes.size() == m_real_num_node); } - assert(total_free_chunks == m_totally_free_chunks); + assert(total_free_blocks == m_totally_free_blocks); } { //Check that header offsets are correct - it = m_chunk_multiset.begin(); + it = m_block_multiset.begin(); for(; it != itend; ++it){ - hdr_offset_holder *hdr_off_holder = priv_first_subchunk_from_chunk(&*it); - for(std::size_t i = 0, max = m_num_subchunks; i < max; ++i){ + hdr_offset_holder *hdr_off_holder = priv_first_subblock_from_block(&*it); + for(std::size_t i = 0, max = m_num_subblocks; i < max; ++i){ assert(hdr_off_holder->hdr_offset == std::size_t((char*)&*it- (char*)hdr_off_holder)); - assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); - assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); - hdr_off_holder = (hdr_offset_holder *)((char*)hdr_off_holder + m_real_chunk_alignment); + assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1))); + assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1))); + hdr_off_holder = (hdr_offset_holder *)((char*)hdr_off_holder + m_real_block_alignment); } } } @@ -446,72 +479,72 @@ class private_adaptive_node_pool_impl void priv_clear() { #ifndef NDEBUG - chunk_iterator it = m_chunk_multiset.begin(); - chunk_iterator itend = m_chunk_multiset.end(); + block_iterator it = m_block_multiset.begin(); + block_iterator itend = m_block_multiset.end(); std::size_t num_free_nodes = 0; for(; it != itend; ++it){ //Check for memory leak assert(it->free_nodes.size() == m_real_num_node); ++num_free_nodes; } - assert(num_free_nodes == m_totally_free_chunks); + assert(num_free_nodes == m_totally_free_blocks); #endif priv_invariants(); - m_chunk_multiset.clear_and_dispose - (chunk_destroyer(this)); - m_totally_free_chunks = 0; + m_block_multiset.clear_and_dispose + (block_destroyer(this)); + m_totally_free_blocks = 0; } - chunk_info_t *priv_chunk_from_node(void *node) const + block_info_t *priv_block_from_node(void *node) const { hdr_offset_holder *hdr_off_holder = - (hdr_offset_holder*)((std::size_t)node & std::size_t(~(m_real_chunk_alignment - 1))); - assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); - assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); - chunk_info_t *chunk = (chunk_info_t *)(((char*)hdr_off_holder) + hdr_off_holder->hdr_offset); - assert(chunk->hdr_offset == 0); - return chunk; + (hdr_offset_holder*)((std::size_t)node & std::size_t(~(m_real_block_alignment - 1))); + assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1))); + assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1))); + block_info_t *block = (block_info_t *)(((char*)hdr_off_holder) + hdr_off_holder->hdr_offset); + assert(block->hdr_offset == 0); + return block; } - hdr_offset_holder *priv_first_subchunk_from_chunk(chunk_info_t *chunk) const + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const { hdr_offset_holder *hdr_off_holder = (hdr_offset_holder*) - (((char*)chunk) - (m_num_subchunks-1)*m_real_chunk_alignment); - assert(hdr_off_holder->hdr_offset == std::size_t((char*)chunk - (char*)hdr_off_holder)); - assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); - assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); + (((char*)block) - (m_num_subblocks-1)*m_real_block_alignment); + assert(hdr_off_holder->hdr_offset == std::size_t((char*)block - (char*)hdr_off_holder)); + assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1))); + assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1))); return hdr_off_holder; } - //!Allocates a several chunks of nodes. Can throw boost::interprocess::bad_alloc - void priv_alloc_chunk(std::size_t n) + //!Allocates a several blocks of nodes. Can throw boost::interprocess::bad_alloc + void priv_alloc_block(std::size_t n) { - std::size_t real_chunk_size = m_real_chunk_alignment*m_num_subchunks - SegmentManagerBase::PayloadPerAllocation; - std::size_t elements_per_subchunk = (m_real_chunk_alignment - HdrOffsetSize)/m_real_node_size; - std::size_t hdr_subchunk_elements = (m_real_chunk_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size; + std::size_t real_block_size = m_real_block_alignment*m_num_subblocks - SegmentManagerBase::PayloadPerAllocation; + std::size_t elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size; + std::size_t hdr_subblock_elements = (m_real_block_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size; for(std::size_t i = 0; i != n; ++i){ //We allocate a new NodeBlock and put it the last //element of the tree char *mem_address = detail::char_ptr_cast - (mp_segment_mngr_base->allocate_aligned(real_chunk_size, m_real_chunk_alignment)); + (mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment)); if(!mem_address) throw std::bad_alloc(); - ++m_totally_free_chunks; + ++m_totally_free_blocks; - //First initialize header information on the last subchunk - char *hdr_addr = mem_address + m_real_chunk_alignment*(m_num_subchunks-1); - chunk_info_t *c_info = new(hdr_addr)chunk_info_t; + //First initialize header information on the last subblock + char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1); + block_info_t *c_info = new(hdr_addr)block_info_t; //Some structural checks assert(static_cast(&static_cast(c_info)->hdr_offset) == static_cast(c_info)); typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin(); - for( std::size_t subchunk = 0, maxsubchunk = m_num_subchunks - 1 - ; subchunk < maxsubchunk - ; ++subchunk, mem_address += m_real_chunk_alignment){ + for( std::size_t subblock = 0, maxsubblock = m_num_subblocks - 1 + ; subblock < maxsubblock + ; ++subblock, mem_address += m_real_block_alignment){ //Initialize header offset mark new(mem_address) hdr_offset_holder(std::size_t(hdr_addr - mem_address)); char *pNode = mem_address + HdrOffsetSize; - for(std::size_t i = 0; i < elements_per_subchunk; ++i){ + for(std::size_t i = 0; i < elements_per_subblock; ++i){ prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t); pNode += m_real_node_size; } @@ -520,13 +553,13 @@ class private_adaptive_node_pool_impl char *pNode = hdr_addr + HdrSize; //We initialize all Nodes in Node Block to insert //them in the free Node list - for(std::size_t i = 0; i < hdr_subchunk_elements; ++i){ + for(std::size_t i = 0; i < hdr_subblock_elements; ++i){ prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t); pNode += m_real_node_size; } } - //Insert the chunk after the free node list is full - m_chunk_multiset.insert(m_chunk_multiset.end(), *c_info); + //Insert the block after the free node list is full + m_block_multiset.insert(m_block_multiset.end(), *c_info); } } @@ -534,25 +567,25 @@ class private_adaptive_node_pool_impl typedef typename pointer_to_other ::type segment_mngr_base_ptr_t; - const std::size_t m_max_free_chunks; + const std::size_t m_max_free_blocks; const std::size_t m_real_node_size; //Round the size to a power of two value. //This is the total memory size (including payload) that we want to //allocate from the general-purpose allocator - const std::size_t m_real_chunk_alignment; - std::size_t m_num_subchunks; - //This is the real number of nodes per chunk + const std::size_t m_real_block_alignment; + std::size_t m_num_subblocks; + //This is the real number of nodes per block //const std::size_t m_real_num_node; segment_mngr_base_ptr_t mp_segment_mngr_base;//Segment manager - chunk_multiset_t m_chunk_multiset; //Intrusive chunk list - std::size_t m_totally_free_chunks; //Free chunks + block_multiset_t m_block_multiset; //Intrusive block list + std::size_t m_totally_free_blocks; //Free blocks }; template< class SegmentManager , std::size_t NodeSize - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class private_adaptive_node_pool @@ -569,11 +602,14 @@ class private_adaptive_node_pool public: typedef SegmentManager segment_manager; - static const std::size_t nodes_per_chunk = NodesPerChunk; + static const std::size_t nodes_per_block = NodesPerBlock; + + //Deprecated, use node_per_block + static const std::size_t nodes_per_chunk = NodesPerBlock; //!Constructor from a segment manager. Never throws private_adaptive_node_pool(segment_manager *segment_mngr) - : base_t(segment_mngr, NodeSize, NodesPerChunk, MaxFreeChunks, OverheadPercent) + : base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent) {} //!Returns the segment manager. Never throws @@ -584,22 +620,22 @@ class private_adaptive_node_pool //!Pooled shared memory allocator using adaptive pool. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time template< class SegmentManager , std::size_t NodeSize - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class shared_adaptive_node_pool : public detail::shared_pool_impl < private_adaptive_node_pool - + > { typedef detail::shared_pool_impl < private_adaptive_node_pool - + > base_t; public: shared_adaptive_node_pool(SegmentManager *segment_mgnr) diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index da18fc9..f5ccddd 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -294,7 +294,7 @@ class array_allocation_impl (command, limit_size, preferred_size, received_size, detail::get_pointer(reuse)); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -307,7 +307,7 @@ class array_allocation_impl } //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) { @@ -315,7 +315,7 @@ class array_allocation_impl (this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T))); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -342,7 +342,12 @@ class array_allocation_impl //!Default construct an object. //!Throws if T's default constructor throws void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + { new((void*)detail::get_pointer(ptr)) value_type; } + + //!Copy construct an object + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v) + { new((void*)detail::get_pointer(ptr)) value_type(v); } //!Destroys object. Throws if object's //!destructor throws @@ -386,64 +391,94 @@ class node_pool_allocation_impl typedef typename SegmentManager:: multiallocation_chain multiallocation_chain; + template + struct node_pool + { + typedef typename Derived::template node_pool<0>::type type; + static type *get(void *p) + { return static_cast(p); } + }; + public: //!Allocate memory for an array of count elements. //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate(size_type count, cvoid_pointer hint = 0) { (void)hint; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); if(count > this->max_size()) throw bad_alloc(); else if(Version == 1 && count == 1) - return pointer(static_cast(this->derived()->get_node_pool()->allocate_node())); + return pointer(static_cast + (pool->allocate_node())); else return pointer(static_cast - (this->derived()->get_node_pool()->get_segment_manager()->allocate(sizeof(T)*count))); + (pool->get_segment_manager()->allocate(sizeof(T)*count))); } //!Deallocate allocated memory. Never throws void deallocate(const pointer &ptr, size_type count) { (void)count; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); if(Version == 1 && count == 1) - this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(ptr)); + pool->deallocate_node(detail::get_pointer(ptr)); else - this->derived()->get_node_pool()->get_segment_manager()->deallocate(detail::get_pointer(ptr)); + pool->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); } //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one() - { return pointer(static_cast(this->derived()->get_node_pool()->allocate_node())); } + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + return pointer(static_cast(pool->allocate_node())); + } - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. Memory allocated with this function //!must be deallocated only with deallocate_one(). multiallocation_iterator allocate_individual(std::size_t num_elements) - { return multiallocation_iterator(this->derived()->get_node_pool()->allocate_nodes(num_elements)); } + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + return multiallocation_iterator(pool->allocate_nodes(num_elements)); + } //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p) - { this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(p)); } + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + pool->deallocate_node(detail::get_pointer(p)); + } - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. Memory allocated with this function //!must be deallocated only with deallocate_one(). void deallocate_individual(multiallocation_iterator it) - { this->derived()->get_node_pool()->deallocate_nodes(it.base()); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } - //!Deallocates all free chunks of the pool + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } + + //!Deprecated, use deallocate_free_blocks. + //!Deallocates all free chunks of the pool. void deallocate_free_chunks() - { this->derived()->get_node_pool()->deallocate_free_chunks(); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } }; template @@ -536,7 +571,7 @@ class cached_allocator_impl m_cache.cached_deallocation(detail::get_pointer(ptr)); } else{ - this->get_segment_manager()->deallocate(detail::get_pointer(ptr)); + this->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); } } @@ -546,7 +581,7 @@ class cached_allocator_impl pointer allocate_one() { return pointer(static_cast(this->m_cache.cached_allocation())); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -561,7 +596,7 @@ class cached_allocator_impl void deallocate_one(const pointer &p) { this->m_cache.cached_deallocation(detail::get_pointer(p)); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -570,9 +605,9 @@ class cached_allocator_impl void deallocate_individual(multiallocation_iterator it) { m_cache.cached_deallocation(it.base()); } - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { m_cache.get_node_pool()->deallocate_free_chunks(); } + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() + { m_cache.get_node_pool()->deallocate_free_blocks(); } //!Swaps allocators. Does not throw. If each allocator is placed in a //!different shared memory segments, the result is undefined. @@ -586,6 +621,10 @@ class cached_allocator_impl void deallocate_cache() { m_cache.deallocate_all_cached_nodes(); } + //!Deprecated use deallocate_free_blocks. + void deallocate_free_chunks() + { m_cache.get_node_pool()->deallocate_free_blocks(); } + /// @cond private: cache_impl m_cache; @@ -609,7 +648,7 @@ bool operator!=(const cached_allocator_impl &alloc1, //!Pooled shared memory allocator using adaptive pool. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time template class shared_pool_impl : public private_node_allocator_t @@ -631,7 +670,7 @@ class shared_pool_impl : private_node_allocator_t(segment_mngr) {} - //!Destructor. Deallocates all allocated chunks. Never throws + //!Destructor. Deallocates all allocated blocks. Never throws ~shared_pool_impl() {} @@ -700,24 +739,24 @@ class shared_pool_impl private_node_allocator_t::deallocate_nodes(it); } - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::deallocate_free_chunks(); + private_node_allocator_t::deallocate_free_blocks(); } //!Deallocates all used memory from the common pool. //!Precondition: all nodes allocated from this pool should //!already be deallocated. Otherwise, undefined behavior. Never throws - void purge_chunks() + void purge_blocks() { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::purge_chunks(); + private_node_allocator_t::purge_blocks(); } //!Increments internal reference count and returns new count. Never throws @@ -739,6 +778,24 @@ class shared_pool_impl return --m_header.m_usecount; } + //!Deprecated, use deallocate_free_blocks. + void deallocate_free_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deprecated, use purge_blocks. + void purge_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::purge_blocks(); + } + private: //!This struct includes needed data and derives from //!interprocess_mutex to allow EBO when using null_mutex diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index cfcbcf8..23c032c 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -60,30 +60,30 @@ class private_node_pool_impl typedef typename bi::make_slist < node_t, bi::base_hook , bi::linear - , bi::constant_time_size >::type chunkslist_t; + , bi::constant_time_size >::type blockslist_t; public: //!Segment manager typedef typedef SegmentManagerBase segment_manager_base_type; //!Constructor from a segment manager. Never throws - private_node_pool_impl(segment_manager_base_type *segment_mngr_base, std::size_t node_size, std::size_t nodes_per_chunk) - : m_nodes_per_chunk(nodes_per_chunk) + private_node_pool_impl(segment_manager_base_type *segment_mngr_base, std::size_t node_size, std::size_t nodes_per_block) + : m_nodes_per_block(nodes_per_block) , m_real_node_size(detail::lcm(node_size, std::size_t(alignment_of::value))) //General purpose allocator , mp_segment_mngr_base(segment_mngr_base) - , m_chunklist() + , m_blocklist() , m_freelist() //Debug node count , m_allocated(0) {} - //!Destructor. Deallocates all allocated chunks. Never throws + //!Destructor. Deallocates all allocated blocks. Never throws ~private_node_pool_impl() - { this->purge_chunks(); } + { this->purge_blocks(); } std::size_t get_real_num_node() const - { return m_nodes_per_chunk; } + { return m_nodes_per_block; } //!Returns the segment manager. Never throws segment_manager_base_type* get_segment_manager_base()const @@ -94,7 +94,7 @@ class private_node_pool_impl { //If there are no free nodes we allocate a new block if (m_freelist.empty()) - priv_alloc_chunk(); + priv_alloc_block(); //We take the first free node node_t *n = (node_t*)&m_freelist.front(); m_freelist.pop_front(); @@ -173,36 +173,36 @@ class private_node_pool_impl } } - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() { typedef typename free_nodes_t::iterator nodelist_iterator; - typename chunkslist_t::iterator bit(m_chunklist.before_begin()), - it(m_chunklist.begin()), - itend(m_chunklist.end()); + typename blockslist_t::iterator bit(m_blocklist.before_begin()), + it(m_blocklist.begin()), + itend(m_blocklist.end()); free_nodes_t backup_list; nodelist_iterator backup_list_last = backup_list.before_begin(); //Execute the algorithm and get an iterator to the last value std::size_t blocksize = detail::get_rounded_size - (m_real_node_size*m_nodes_per_chunk, alignment_of::value); + (m_real_node_size*m_nodes_per_block, alignment_of::value); while(it != itend){ - //Collect all the nodes from the chunk pointed by it + //Collect all the nodes from the block pointed by it //and push them in the list free_nodes_t free_nodes; nodelist_iterator last_it = free_nodes.before_begin(); - const void *addr = get_chunk_from_hook(&*it, blocksize); + const void *addr = get_block_from_hook(&*it, blocksize); m_freelist.remove_and_dispose_if (is_between(addr, blocksize), push_in_list(free_nodes, last_it)); - //If the number of nodes is equal to m_nodes_per_chunk + //If the number of nodes is equal to m_nodes_per_block //this means that the block can be deallocated - if(free_nodes.size() == m_nodes_per_chunk){ + if(free_nodes.size() == m_nodes_per_block){ //Unlink the nodes free_nodes.clear(); - it = m_chunklist.erase_after(bit); + it = m_blocklist.erase_after(bit); mp_segment_mngr_base->deallocate((void*)addr); } //Otherwise, insert them in the backup list, since the @@ -240,20 +240,20 @@ class private_node_pool_impl //!Deallocates all used memory. Precondition: all nodes allocated from this pool should //!already be deallocated. Otherwise, undefined behaviour. Never throws - void purge_chunks() + void purge_blocks() { //check for memory leaks assert(m_allocated==0); std::size_t blocksize = detail::get_rounded_size - (m_real_node_size*m_nodes_per_chunk, alignment_of::value); - typename chunkslist_t::iterator - it(m_chunklist.begin()), itend(m_chunklist.end()), aux; + (m_real_node_size*m_nodes_per_block, alignment_of::value); + typename blockslist_t::iterator + it(m_blocklist.begin()), itend(m_blocklist.end()), aux; //We iterate though the NodeBlock list to free the memory - while(!m_chunklist.empty()){ - void *addr = get_chunk_from_hook(&m_chunklist.front(), blocksize); - m_chunklist.pop_front(); - mp_segment_mngr_base->deallocate(addr); + while(!m_blocklist.empty()){ + void *addr = get_block_from_hook(&m_blocklist.front(), blocksize); + m_blocklist.pop_front(); + mp_segment_mngr_base->deallocate((void*)addr); } //Just clear free node list m_freelist.clear(); @@ -262,7 +262,7 @@ class private_node_pool_impl void swap(private_node_pool_impl &other) { std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); - m_chunklist.swap(other.m_chunklist); + m_blocklist.swap(other.m_blocklist); m_freelist.swap(other.m_freelist); std::swap(m_allocated, other.m_allocated); } @@ -305,36 +305,44 @@ class private_node_pool_impl const char * end_; }; - //!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc - void priv_alloc_chunk() + //!Allocates a block of nodes. Can throw boost::interprocess::bad_alloc + void priv_alloc_block() { //We allocate a new NodeBlock and put it as first //element in the free Node list std::size_t blocksize = - detail::get_rounded_size(m_real_node_size*m_nodes_per_chunk, alignment_of::value); + detail::get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of::value); char *pNode = detail::char_ptr_cast (mp_segment_mngr_base->allocate(blocksize + sizeof(node_t))); if(!pNode) throw bad_alloc(); char *pBlock = pNode; - m_chunklist.push_front(get_chunk_hook(pBlock, blocksize)); + m_blocklist.push_front(get_block_hook(pBlock, blocksize)); //We initialize all Nodes in Node Block to insert //them in the free Node list - for(std::size_t i = 0; i < m_nodes_per_chunk; ++i, pNode += m_real_node_size){ + for(std::size_t i = 0; i < m_nodes_per_block; ++i, pNode += m_real_node_size){ m_freelist.push_front(*new (pNode) node_t); } } + //!Deprecated, use deallocate_free_blocks + void deallocate_free_chunks() + { this->deallocate_free_blocks(); } + + //!Deprecated, use purge_blocks + void purge_chunks() + { this->purge_blocks(); } + private: - //!Returns a reference to the chunk hook placed in the end of the chunk - static inline node_t & get_chunk_hook (void *chunk, std::size_t blocksize) + //!Returns a reference to the block hook placed in the end of the block + static inline node_t & get_block_hook (void *block, std::size_t blocksize) { return *static_cast( - static_cast((detail::char_ptr_cast(chunk) + blocksize))); + static_cast((detail::char_ptr_cast(block) + blocksize))); } - //!Returns the starting address of the chunk reference to the chunk hook placed in the end of the chunk - inline void *get_chunk_from_hook (node_t *hook, std::size_t blocksize) + //!Returns the starting address of the block reference to the block hook placed in the end of the block + inline void *get_block_from_hook (node_t *hook, std::size_t blocksize) { return static_cast((detail::char_ptr_cast(hook) - blocksize)); } @@ -343,10 +351,10 @@ class private_node_pool_impl typedef typename pointer_to_other ::type segment_mngr_base_ptr_t; - const std::size_t m_nodes_per_chunk; + const std::size_t m_nodes_per_block; const std::size_t m_real_node_size; segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager - chunkslist_t m_chunklist; //Intrusive container of chunks + blockslist_t m_blocklist; //Intrusive container of blocks free_nodes_t m_freelist; //Intrusive container of free nods std::size_t m_allocated; //Used nodes for debugging }; @@ -355,8 +363,8 @@ class private_node_pool_impl //!Pooled shared memory allocator using single segregated storage. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time -template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerChunk > +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerBlock > class private_node_pool //Inherit from the implementation to avoid template bloat : public private_node_pool_impl @@ -370,11 +378,13 @@ class private_node_pool public: typedef SegmentManager segment_manager; - static const std::size_t nodes_per_chunk = NodesPerChunk; + static const std::size_t nodes_per_block = NodesPerBlock; + //Deprecated, use nodes_per_block + static const std::size_t nodes_per_chunk = NodesPerBlock; //!Constructor from a segment manager. Never throws private_node_pool(segment_manager *segment_mngr) - : base_t(segment_mngr, NodeSize, NodesPerChunk) + : base_t(segment_mngr, NodeSize, NodesPerBlock) {} //!Returns the segment manager. Never throws @@ -386,24 +396,24 @@ class private_node_pool //!Pooled shared memory allocator using single segregated storage. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time //!Pooled shared memory allocator using adaptive pool. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time template< class SegmentManager , std::size_t NodeSize - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class shared_node_pool : public detail::shared_pool_impl < private_node_pool - + > { typedef detail::shared_pool_impl < private_node_pool - + > base_t; public: shared_node_pool(SegmentManager *segment_mgnr) diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index eed6e9e..0ee43c3 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -43,12 +43,12 @@ namespace detail{ template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class node_allocator_base : public node_pool_allocation_impl < node_allocator_base - < Version, T, SegmentManager, NodesPerChunk> + < Version, T, SegmentManager, NodesPerBlock> , Version , T , SegmentManager @@ -58,11 +58,20 @@ class node_allocator_base typedef typename SegmentManager::void_pointer void_pointer; typedef SegmentManager segment_manager; typedef node_allocator_base - self_t; - typedef detail::shared_node_pool - < SegmentManager, sizeof(T), NodesPerChunk> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; + self_t; + + /// @cond + + template + struct node_pool + { + typedef detail::shared_node_pool + < SegmentManager, sizeof_value::value, NodesPerBlock> type; + + static type *get(void *p) + { return static_cast(p); } + }; + /// @endcond BOOST_STATIC_ASSERT((Version <=2)); @@ -93,7 +102,7 @@ class node_allocator_base template struct rebind { - typedef node_allocator_base other; + typedef node_allocator_base other; }; /// @cond @@ -104,7 +113,7 @@ class node_allocator_base (const node_allocator_base&); //!Not assignable from other node_allocator_base - node_allocator_base& operator=(const node_allocator_base&); + //node_allocator_base& operator=(const node_allocator_base&); /// @endcond public: @@ -112,14 +121,14 @@ class node_allocator_base //!pool. Increments the reference count of the associated node pool. //!Can throw boost::interprocess::bad_alloc node_allocator_base(segment_manager *segment_mngr) - : mp_node_pool(detail::get_or_create_node_pool(segment_mngr)) { } + : mp_node_pool(detail::get_or_create_node_pool::type>(segment_mngr)) { } //!Copy constructor from other node_allocator_base. Increments the reference //!count of the associated node pool. Never throws node_allocator_base(const node_allocator_base &other) : mp_node_pool(other.get_node_pool()) { - mp_node_pool->inc_ref_count(); + node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count(); } //!Copy constructor from related node_allocator_base. If not present, constructs @@ -127,23 +136,31 @@ class node_allocator_base //!Can throw boost::interprocess::bad_alloc template node_allocator_base - (const node_allocator_base &other) - : mp_node_pool(detail::get_or_create_node_pool(other.get_segment_manager())) { } + (const node_allocator_base &other) + : mp_node_pool(detail::get_or_create_node_pool::type>(other.get_segment_manager())) { } + + //!Assignment from other node_allocator_base + node_allocator_base& operator=(const node_allocator_base &other) + { + node_allocator_base c(other); + swap(*this, c); + return *this; + } //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws ~node_allocator_base() - { detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool)); } + { detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); } //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const + void* get_node_pool() const { return detail::get_pointer(mp_node_pool); } //!Returns the segment manager. //!Never throws segment_manager* get_segment_manager()const - { return mp_node_pool->get_segment_manager(); } + { return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); } //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -152,44 +169,44 @@ class node_allocator_base /// @cond private: - node_pool_ptr mp_node_pool; + void_pointer mp_node_pool; /// @endcond }; //!Equality test for same type //!of node_allocator_base -template inline -bool operator==(const node_allocator_base &alloc1, - const node_allocator_base &alloc2) +template inline +bool operator==(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type //!of node_allocator_base -template inline -bool operator!=(const node_allocator_base &alloc1, - const node_allocator_base &alloc2) +template inline +bool operator!=(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 + , std::size_t NodesPerBlock = 64 > class node_allocator_v1 : public node_allocator_base < 1 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > { public: typedef detail::node_allocator_base - < 1, T, SegmentManager, NodesPerChunk> base_t; + < 1, T, SegmentManager, NodesPerBlock> base_t; template struct rebind { - typedef node_allocator_v1 other; + typedef node_allocator_v1 other; }; node_allocator_v1(SegmentManager *segment_mngr) @@ -198,7 +215,7 @@ class node_allocator_v1 template node_allocator_v1 - (const node_allocator_v1 &other) + (const node_allocator_v1 &other) : base_t(other) {} }; @@ -213,11 +230,11 @@ class node_allocator_v1 //!placing the allocator in shared memory, memory mapped-files, etc... //!This node allocator shares a segregated storage between all instances //!of node_allocator with equal sizeof(T) placed in the same segment -//!group. NodesPerChunk is the number of nodes allocated at once when the allocator +//!group. NodesPerBlock is the number of nodes allocated at once when the allocator //!needs runs out of nodes template < class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class node_allocator /// @cond @@ -225,21 +242,21 @@ class node_allocator < 2 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > /// @endcond { #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::node_allocator_base - < 2, T, SegmentManager, NodesPerChunk> base_t; + < 2, T, SegmentManager, NodesPerBlock> base_t; public: typedef detail::version_type version; template struct rebind { - typedef node_allocator other; + typedef node_allocator other; }; node_allocator(SegmentManager *segment_mngr) @@ -248,7 +265,7 @@ class node_allocator template node_allocator - (const node_allocator &other) + (const node_allocator &other) : base_t(other) {} @@ -271,7 +288,7 @@ class node_allocator template struct rebind { - typedef node_allocator other; + typedef node_allocator other; }; private: @@ -283,7 +300,7 @@ class node_allocator //!Not assignable from //!other node_allocator - node_allocator& operator=(const node_allocator&); + //node_allocator& operator=(const node_allocator&); public: //!Constructor from a segment manager. If not present, constructs a node @@ -300,7 +317,7 @@ class node_allocator //!Can throw boost::interprocess::bad_alloc template node_allocator - (const node_allocator &other); + (const node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -308,7 +325,7 @@ class node_allocator //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const; + void* get_node_pool() const; //!Returns the segment manager. //!Never throws @@ -326,9 +343,9 @@ class node_allocator //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -342,9 +359,9 @@ class node_allocator //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -361,7 +378,7 @@ class node_allocator size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -370,11 +387,11 @@ class node_allocator multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -387,7 +404,7 @@ class node_allocator //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -400,7 +417,7 @@ class node_allocator //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -414,15 +431,15 @@ class node_allocator //!Equality test for same type //!of node_allocator -template inline -bool operator==(const node_allocator &alloc1, - const node_allocator &alloc2); +template inline +bool operator==(const node_allocator &alloc1, + const node_allocator &alloc2); //!Inequality test for same type //!of node_allocator -template inline -bool operator!=(const node_allocator &alloc1, - const node_allocator &alloc2); +template inline +bool operator!=(const node_allocator &alloc1, + const node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index 5552348..c9b4e18 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -42,31 +42,34 @@ namespace detail { template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class private_adaptive_pool_base : public node_pool_allocation_impl - < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerChunk - , MaxFreeChunks, OverheadPercent> + < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock + , MaxFreeBlocks, OverheadPercent> , Version , T , SegmentManager > { + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + /// @cond private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef SegmentManager segment_manager; typedef private_adaptive_pool_base - < Version, T, SegmentManager, NodesPerChunk - , MaxFreeChunks, OverheadPercent> self_t; + < Version, T, SegmentManager, NodesPerBlock + , MaxFreeBlocks, OverheadPercent> self_t; typedef detail::private_adaptive_node_pool ::value + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > node_pool_t; @@ -100,10 +103,26 @@ class private_adaptive_pool_base struct rebind { typedef private_adaptive_pool_base - other; + other; }; /// @cond + + template + struct node_pool + { + typedef detail::private_adaptive_node_pool + ::value + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + > type; + + static type *get(void *p) + { return static_cast(p); } + }; + private: //!Not assignable from related private_adaptive_pool_base template @@ -129,7 +148,7 @@ class private_adaptive_pool_base template private_adaptive_pool_base (const private_adaptive_pool_base - &other) + &other) : m_node_pool(other.get_segment_manager()) {} @@ -157,21 +176,21 @@ class private_adaptive_pool_base }; //!Equality test for same type of private_adaptive_pool_base -template inline -bool operator==(const private_adaptive_pool_base &alloc1, - const private_adaptive_pool_base &alloc2) +template inline +bool operator==(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) { return &alloc1 == &alloc2; } //!Inequality test for same type of private_adaptive_pool_base -template inline -bool operator!=(const private_adaptive_pool_base &alloc1, - const private_adaptive_pool_base &alloc2) +template inline +bool operator!=(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) { return &alloc1 != &alloc2; } template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 - , std::size_t MaxFreeChunks = 2 + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 , unsigned char OverheadPercent = 5 > class private_adaptive_pool_v1 @@ -179,19 +198,19 @@ class private_adaptive_pool_v1 < 1 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > { public: typedef detail::private_adaptive_pool_base - < 1, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; template struct rebind { - typedef private_adaptive_pool_v1 other; + typedef private_adaptive_pool_v1 other; }; private_adaptive_pool_v1(SegmentManager *segment_mngr) @@ -200,7 +219,7 @@ class private_adaptive_pool_v1 template private_adaptive_pool_v1 - (const private_adaptive_pool_v1 &other) + (const private_adaptive_pool_v1 &other) : base_t(other) {} }; @@ -215,17 +234,17 @@ class private_adaptive_pool_v1 //!placing the allocator in shared memory, memory mapped-files, etc... //!This allocator has its own node pool. //! -//!NodesPerChunk is the minimum number of nodes of nodes allocated at once when -//!the allocator needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks -//!that the adaptive node pool will hold. The rest of the totally free chunks will be +//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when +//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be //!deallocated with the segment manager. //! //!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: //!(memory usable for nodes / total memory allocated from the segment manager) template < class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class private_adaptive_pool @@ -234,8 +253,8 @@ class private_adaptive_pool < 2 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > /// @endcond @@ -243,7 +262,7 @@ class private_adaptive_pool #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::private_adaptive_pool_base - < 2, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: typedef detail::version_type version; @@ -251,7 +270,7 @@ class private_adaptive_pool struct rebind { typedef private_adaptive_pool - other; + other; }; private_adaptive_pool(SegmentManager *segment_mngr) @@ -260,7 +279,7 @@ class private_adaptive_pool template private_adaptive_pool - (const private_adaptive_pool &other) + (const private_adaptive_pool &other) : base_t(other) {} @@ -284,7 +303,7 @@ class private_adaptive_pool struct rebind { typedef private_adaptive_pool - other; + other; }; private: @@ -313,7 +332,7 @@ class private_adaptive_pool //!Can throw boost::interprocess::bad_alloc template private_adaptive_pool - (const private_adaptive_pool &other); + (const private_adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -339,9 +358,9 @@ class private_adaptive_pool //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -355,9 +374,9 @@ class private_adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -374,7 +393,7 @@ class private_adaptive_pool size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -383,11 +402,11 @@ class private_adaptive_pool multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -400,7 +419,7 @@ class private_adaptive_pool //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -413,7 +432,7 @@ class private_adaptive_pool //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -427,15 +446,15 @@ class private_adaptive_pool //!Equality test for same type //!of private_adaptive_pool -template inline -bool operator==(const private_adaptive_pool &alloc1, - const private_adaptive_pool &alloc2); +template inline +bool operator==(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); //!Inequality test for same type //!of private_adaptive_pool -template inline -bool operator!=(const private_adaptive_pool &alloc1, - const private_adaptive_pool &alloc2); +template inline +bool operator!=(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); #endif diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index 608bacc..a7320f1 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -1,208 +1,3 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/interprocess for documentation. -// -////////////////////////////////////////////////////////////////////////////// -/* -#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP -#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP - -#if (defined _MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//!\file -//!Describes private_node_allocator pooled shared memory STL compatible allocator - -namespace boost { -namespace interprocess { - -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This allocator has its own node pool. NodesPerChunk is the number of nodes allocated -//!at once when the allocator needs runs out of nodes -template -class private_node_allocator -{ - /// @cond - private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; - typedef SegmentManager segment_manager; - typedef typename detail::pointer_to_other - ::type segment_mngr_ptr_t; - typedef private_node_allocator - self_t; - typedef detail::private_node_pool - priv_node_pool_t; - /// @endcond - - public: - //------- - typedef typename detail:: - pointer_to_other::type pointer; - typedef typename detail:: - pointer_to_other::type const_pointer; - typedef T value_type; - typedef typename detail::add_reference - ::type reference; - typedef typename detail::add_reference - ::type const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - //!Obtains node_allocator from other node_allocator - template - struct rebind - { - typedef private_node_allocator other; - }; - - /// @cond - private: - //!Not assignable from related private_node_allocator - template - private_node_allocator& operator= - (const private_node_allocator&); - - //!Not assignable from other private_node_allocator - private_node_allocator& operator=(const private_node_allocator&); - /// @endcond - - public: - - //!Constructor from a segment manager - private_node_allocator(segment_manager *segment_mngr) - : m_node_pool(segment_mngr){} - - //!Copy constructor from other private_node_allocator. Never throws - private_node_allocator(const private_node_allocator &other) - : m_node_pool(other.get_segment_manager()){} - - //!Copy constructor from related private_node_allocator. Never throws. - template - private_node_allocator - (const private_node_allocator &other) - : m_node_pool(other.get_segment_manager()) - {} - - //!Destructor, frees all used memory. Never throws - ~private_node_allocator() - {} - - //!Returns the segment manager. Never throws - segment_manager* get_segment_manager()const - { return m_node_pool.get_segment_manager(); } - - //!Returns the number of elements that could be allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } - - //!Allocate memory for an array of count elements. - //!Throws boost::interprocess::bad_alloc if there is no enough memory - pointer allocate(size_type count, cvoid_pointer hint = 0) - { - (void)hint; - if(count > this->max_size()) - throw bad_alloc(); - else if(count == 1) - return pointer(static_cast(m_node_pool.allocate_node())); - else - return pointer(static_cast - (m_node_pool.get_segment_manager()->allocate(sizeof(T)*count))); - } - - //!Deallocate allocated memory. Never throws - void deallocate(const pointer &ptr, size_type count) - { - if(count == 1) - m_node_pool.deallocate_node(detail::get_pointer(ptr)); - else - m_node_pool.get_segment_manager()->deallocate(detail::get_pointer(ptr)); - } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { m_node_pool.deallocate_free_chunks(); } - - //!Swaps allocators. Does not throw. If each allocator is placed in a - //!different shared memory segments, the result is undefined. - friend void swap(self_t &alloc1,self_t &alloc2) - { alloc1.m_node_pool.swap(alloc2.m_node_pool); } - - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... - - //!Returns address of mutable object. - //!Never throws - pointer address(reference value) const - { return pointer(boost::addressof(value)); } - - //!Returns address of non mutable object. - //!Never throws - const_pointer address(const_reference value) const - { return const_pointer(boost::addressof(value)); } - - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } - - //!Destroys object. Throws if object's - //!destructor throws - void destroy(const pointer &ptr) - { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } - - /// @cond - private: - priv_node_pool_t m_node_pool; - /// @endcond -}; - -//!Equality test for same type of private_node_allocator -template inline -bool operator==(const private_node_allocator &alloc1, - const private_node_allocator &alloc2) -{ return &alloc1 == &alloc2; } - -//!Inequality test for same type of private_node_allocator -template inline -bool operator!=(const private_node_allocator &alloc1, - const private_node_allocator &alloc2) -{ - return &alloc1 != &alloc2; -} - -} //namespace interprocess { -} //namespace boost { - -#include - -#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP - -*/ - ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost @@ -247,26 +42,29 @@ namespace detail { template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class private_node_allocator_base : public node_pool_allocation_impl - < private_node_allocator_base < Version, T, SegmentManager, NodesPerChunk> + < private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock> , Version , T , SegmentManager > { + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + /// @cond private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef SegmentManager segment_manager; typedef private_node_allocator_base - < Version, T, SegmentManager, NodesPerChunk> self_t; + < Version, T, SegmentManager, NodesPerBlock> self_t; typedef detail::private_node_pool ::value + , NodesPerBlock > node_pool_t; BOOST_STATIC_ASSERT((Version <=2)); @@ -299,10 +97,23 @@ class private_node_allocator_base struct rebind { typedef private_node_allocator_base - other; + other; }; /// @cond + template + struct node_pool + { + typedef detail::private_node_pool + ::value + , NodesPerBlock + > type; + + static type *get(void *p) + { return static_cast(p); } + }; + private: //!Not assignable from related private_node_allocator_base template @@ -328,7 +139,7 @@ class private_node_allocator_base template private_node_allocator_base (const private_node_allocator_base - &other) + &other) : m_node_pool(other.get_segment_manager()) {} @@ -356,37 +167,37 @@ class private_node_allocator_base }; //!Equality test for same type of private_node_allocator_base -template inline -bool operator==(const private_node_allocator_base &alloc1, - const private_node_allocator_base &alloc2) +template inline +bool operator==(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) { return &alloc1 == &alloc2; } //!Inequality test for same type of private_node_allocator_base -template inline -bool operator!=(const private_node_allocator_base &alloc1, - const private_node_allocator_base &alloc2) +template inline +bool operator!=(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) { return &alloc1 != &alloc2; } template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 + , std::size_t NodesPerBlock = 64 > class private_node_allocator_v1 : public private_node_allocator_base < 1 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > { public: typedef detail::private_node_allocator_base - < 1, T, SegmentManager, NodesPerChunk> base_t; + < 1, T, SegmentManager, NodesPerBlock> base_t; template struct rebind { - typedef private_node_allocator_v1 other; + typedef private_node_allocator_v1 other; }; private_node_allocator_v1(SegmentManager *segment_mngr) @@ -395,7 +206,7 @@ class private_node_allocator_v1 template private_node_allocator_v1 - (const private_node_allocator_v1 &other) + (const private_node_allocator_v1 &other) : base_t(other) {} }; @@ -408,11 +219,11 @@ class private_node_allocator_v1 //!source. The internal pointer type will of the same type (raw, smart) as //!"typename SegmentManager::void_pointer" type. This allows //!placing the allocator in shared memory, memory mapped-files, etc... -//!This allocator has its own node pool. NodesPerChunk is the number of nodes allocated +//!This allocator has its own node pool. NodesPerBlock is the number of nodes allocated //!at once when the allocator needs runs out of nodes template < class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class private_node_allocator /// @cond @@ -420,14 +231,14 @@ class private_node_allocator < 2 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > /// @endcond { #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::private_node_allocator_base - < 2, T, SegmentManager, NodesPerChunk> base_t; + < 2, T, SegmentManager, NodesPerBlock> base_t; public: typedef detail::version_type version; @@ -435,7 +246,7 @@ class private_node_allocator struct rebind { typedef private_node_allocator - other; + other; }; private_node_allocator(SegmentManager *segment_mngr) @@ -444,7 +255,7 @@ class private_node_allocator template private_node_allocator - (const private_node_allocator &other) + (const private_node_allocator &other) : base_t(other) {} @@ -468,7 +279,7 @@ class private_node_allocator struct rebind { typedef private_node_allocator - other; + other; }; private: @@ -497,7 +308,7 @@ class private_node_allocator //!Can throw boost::interprocess::bad_alloc template private_node_allocator - (const private_node_allocator &other); + (const private_node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -523,9 +334,9 @@ class private_node_allocator //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -539,9 +350,9 @@ class private_node_allocator //!Never throws const_pointer address(const_reference value) const; - //!Default construct an object. - //!Throws if T's default constructor throws - void construct(const pointer &ptr); + //!Copy construct an object. + //!Throws if T's copy constructor throws + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -558,7 +369,7 @@ class private_node_allocator size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -567,11 +378,11 @@ class private_node_allocator multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -584,7 +395,7 @@ class private_node_allocator //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -597,7 +408,7 @@ class private_node_allocator //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!Allocates many elements of size == 1 in a contiguous block //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is //!preferred_elements. The number of actually allocated elements is @@ -611,15 +422,15 @@ class private_node_allocator //!Equality test for same type //!of private_node_allocator -template inline -bool operator==(const private_node_allocator &alloc1, - const private_node_allocator &alloc2); +template inline +bool operator==(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); //!Inequality test for same type //!of private_node_allocator -template inline -bool operator!=(const private_node_allocator &alloc1, - const private_node_allocator &alloc2); +template inline +bool operator!=(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp new file mode 100644 index 0000000..3e8a57c --- /dev/null +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -0,0 +1,129 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP + +#include +#include +#include +#include +#include +#include +#include + +#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +# include //open, O_CREAT, O_*... +# include //mmap +# include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#else +#include +#endif + + +//!\file +//!Describes a function that creates anonymous shared memory that can be +//!shared between forked processes + +namespace boost { +namespace interprocess { + +/// @cond + +namespace detail{ + + class raw_mapped_region_creator + { + public: + static + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + mapped_region + #else + move_return + #endif + create_posix_mapped_region(void *address, offset_t offset, std::size_t size) + { + mapped_region region; + region.m_base = address; + region.m_offset = offset; + region.m_extra_offset = 0; + region.m_size = size; + return region; + } + }; +} + +/// @endcond + +//!A function that creates an anonymous shared memory segment of size "size". +//!If "address" is passed the function will try to map the segment in that address. +//!Otherwise the operating system will choose the mapping address. +//!The function returns a mapped_region holding that segment or throws +//!interprocess_exception if the function fails. +static +#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +mapped_region +#else +detail::move_return +#endif +anonymous_shared_memory(std::size_t size, void *address = 0) +#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +{ + int flags; + int fd = -1; + + #if defined(MAP_ANONYMOUS) //Use MAP_ANONYMOUS + flags = MAP_ANONYMOUS | MAP_SHARED; + #elif !defined(MAP_ANONYMOUS) && defined(MAP_ANON) //use MAP_ANON + flags = MAP_ANON | MAP_SHARED; + #else // Use "/dev/zero" + fd = open("/dev/zero", O_RDWR); + flags = MAP_SHARED; + if(fd == -1){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + #endif + + + address = mmap( (void*)address + , size + , PROT_READ|PROT_WRITE + , flags + , fd + , 0); + + if(address == MAP_FAILED){ + if(fd != -1) + close(fd); + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + if(fd != -1) + close(fd); + + return detail::raw_mapped_region_creator::create_posix_mapped_region(address, 0, size); +} +#else +{ + windows_shared_memory anonymous_mapping(create_only, 0, read_write, size); + mapped_region region(anonymous_mapping, read_write, 0, size, address); + return region; +} + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index 0b7183d..d73b501 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -580,7 +580,7 @@ class deque : protected deque_base { this->swap(mx.get()); } #else deque(deque &&x) - : Base(x)) + : Base(detail::move_impl(x)) { this->swap(x); } #endif @@ -658,7 +658,7 @@ class deque : protected deque_base void push_back(const value_type& t) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); ++this->members_.m_finish.m_cur; } else @@ -669,7 +669,7 @@ class deque : protected deque_base void push_back(const detail::moved_object &mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); ++this->members_.m_finish.m_cur; } else @@ -679,18 +679,18 @@ class deque : protected deque_base void push_back(value_type &&mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(detail::move_impl(mt)); ++this->members_.m_finish.m_cur; } else - this->priv_push_back_aux(move(mt)); + this->priv_push_back_aux(detail::move_impl(mt)); } #endif void push_front(const value_type& t) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(t); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(t); --this->members_.m_start.m_cur; } else @@ -701,7 +701,7 @@ class deque : protected deque_base void push_front(const detail::moved_object &mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(mt); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(mt); --this->members_.m_start.m_cur; } else @@ -711,11 +711,11 @@ class deque : protected deque_base void push_front(value_type &&mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(move(mt)); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(detail::move_impl(mt)); --this->members_.m_start.m_cur; } else - this->priv_push_front_aux(move(mt)); + this->priv_push_front_aux(detail::move_impl(mt)); } #endif @@ -777,17 +777,17 @@ class deque : protected deque_base iterator insert(iterator position, value_type &&mx) { if (position.m_cur == this->members_.m_start.m_cur) { - this->push_front(move(mx)); + this->push_front(detail::move_impl(mx)); return this->members_.m_start; } else if (position.m_cur == this->members_.m_finish.m_cur) { - this->push_back(move(mx)); + this->push_back(detail::move_impl(mx)); iterator tmp = this->members_.m_finish; --tmp; return tmp; } else { - return this->priv_insert_aux(position, move(mx)); + return this->priv_insert_aux(position, detail::move_impl(mx)); } } #endif @@ -824,13 +824,13 @@ class deque : protected deque_base this->priv_reserve_elements_at_back(new_size); while(n--){ - //T default_constructed = move(T()); + //T default_constructed = detail::move_impl(T()); T default_constructed; /* if(boost::is_scalar::value){ //Value initialization new(&default_constructed)T(); }*/ - this->push_back(move(default_constructed)); + this->push_back(detail::move_impl(default_constructed)); } } } @@ -1217,7 +1217,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node + 1); this->members_.m_finish.m_cur = this->members_.m_finish.m_first; } @@ -1235,7 +1235,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node + 1); this->members_.m_finish.m_cur = this->members_.m_finish.m_first; } @@ -1251,7 +1251,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(detail::move_impl(mt)); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node + 1); this->members_.m_finish.m_cur = this->members_.m_finish.m_first; } @@ -1271,7 +1271,7 @@ class deque : protected deque_base BOOST_TRY { this->members_.m_start.priv_set_node(this->members_.m_start.m_node - 1); this->members_.m_start.m_cur = this->members_.m_start.m_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(t); } BOOST_CATCH(...){ ++this->members_.m_start; @@ -1289,7 +1289,7 @@ class deque : protected deque_base BOOST_TRY { this->members_.m_start.priv_set_node(this->members_.m_start.m_node - 1); this->members_.m_start.m_cur = this->members_.m_start.m_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); } BOOST_CATCH(...){ ++this->members_.m_start; @@ -1306,7 +1306,7 @@ class deque : protected deque_base BOOST_TRY { this->members_.m_start.priv_set_node(this->members_.m_start.m_node - 1); this->members_.m_start.m_cur = this->members_.m_start.m_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(detail::move_impl(mt)); } BOOST_CATCH(...){ ++this->members_.m_start; diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/detail/flat_tree.hpp index 5901a2f..b4777f2 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/detail/flat_tree.hpp @@ -135,11 +135,11 @@ class flat_tree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_tree(const detail::moved_object &x) - : m_data(move(x.get().m_data)) + : m_data(detail::move_impl(x.get().m_data)) { } #else flat_tree(flat_tree &&x) - : m_data(move(x.m_data)) + : m_data(detail::move_impl(x.m_data)) { } #endif @@ -151,10 +151,10 @@ class flat_tree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_tree& operator=(const detail::moved_object& mx) - { m_data = move(mx.get().m_data); return *this; } + { m_data = detail::move_impl(mx.get().m_data); return *this; } #else flat_tree& operator=(flat_tree &&mx) - { m_data = move(mx.m_data); return *this; } + { m_data = detail::move_impl(mx.m_data); return *this; } #endif public: @@ -250,7 +250,7 @@ class flat_tree insert_commit_data data; std::pair ret = priv_insert_unique_prepare(mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, move(mval)); + ret.first = priv_insert_commit(data, detail::move_impl(mval)); } return ret; } @@ -275,7 +275,7 @@ class flat_tree iterator insert_equal(value_type && mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, move(mval)); + i = this->m_data.m_vect.insert(i, detail::move_impl(mval)); return i; } #endif @@ -306,7 +306,7 @@ class flat_tree insert_commit_data data; std::pair ret = priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, move(mval)); + ret.first = priv_insert_commit(data, detail::move_impl(mval)); } return ret.first; } @@ -331,7 +331,7 @@ class flat_tree { insert_commit_data data; priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, move(mval)); + return priv_insert_commit(data, detail::move_impl(mval)); } #endif @@ -547,7 +547,7 @@ class flat_tree template iterator priv_insert_commit (insert_commit_data &commit_data, Convertible &&convertible) - { return this->m_data.m_vect.insert(commit_data.position, forward(convertible)); } + { return this->m_data.m_vect.insert(commit_data.position, detail::forward_impl(convertible)); } #endif template diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 19901ca..5eca3fe 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -88,11 +88,11 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE node_alloc_holder(const detail::moved_object &other) - : members_(move(other.get().node_alloc())) + : members_(detail::move_impl(other.get().node_alloc())) { this->swap(other.get()); } #else node_alloc_holder(node_alloc_holder &&other) - : members_(move(other.node_alloc())) + : members_(detail::move_impl(other.node_alloc())) { this->swap(other); } #endif @@ -145,15 +145,15 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static void construct(const NodePtr &ptr, const Convertible &value) - { new(detail::get_pointer(ptr)) Node(value); } + { new((void*)detail::get_pointer(ptr)) Node(value); } #else template static void construct(const NodePtr &ptr, Convertible &&value) - { new(detail::get_pointer(ptr)) Node(forward(value)); } + { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(value)); } #endif static void construct(const NodePtr &ptr) - { new(detail::get_pointer(ptr)) Node(); } + { new((void*)detail::get_pointer(ptr)) Node(); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template @@ -169,9 +169,9 @@ struct node_alloc_holder new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->m_data; - new((void*)&valueptr->first) first_type(move(value.get().first)); + new((void*)&valueptr->first) first_type(detail::move_impl(value.get().first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(move(value.get().second)); + new((void*)&valueptr->second) second_type(detail::move_impl(value.get().second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -194,9 +194,9 @@ struct node_alloc_holder new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->m_data; - new((void*)&valueptr->first) first_type(move(value.first)); + new((void*)&valueptr->first) first_type(detail::move_impl(value.first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(move(value.second)); + new((void*)&valueptr->second) second_type(detail::move_impl(value.second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -226,7 +226,7 @@ struct node_alloc_holder { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, forward(x)); + self_t::construct(p, detail::forward_impl(x)); node_deallocator.release(); return (p); } @@ -275,7 +275,7 @@ struct node_alloc_holder { typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; - //Try to allocate memory in a single chunk + //Try to allocate memory in a single block multiallocation_iterator itbeg = this->node_alloc().allocate_individual(n), itend, itold; int constructed = 0; diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/detail/tree.hpp index b2e4428..2bd77bb 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/detail/tree.hpp @@ -109,7 +109,7 @@ struct rbtree_node #else template rbtree_node(Convertible &&conv) - : m_data(forward(conv)){} + : m_data(detail::forward_impl(conv)){} #endif rbtree_node &operator=(const rbtree_node &other) @@ -130,7 +130,7 @@ struct rbtree_node { m_data = v; } public: - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) template static void construct(node_type *ptr, const Convertible &value) @@ -149,11 +149,11 @@ struct rbtree_node new((void*)ptr) hack_node_t(value); } - #else + #elif !defined(BOOST_INTERPROCESS_RVALUE_PAIR) template static void construct(node_type *ptr, Convertible &&value) - { new(ptr) node_type(forward(value)); } + { new(ptr) node_type(detail::forward_impl(value)); } template static void construct(node_type *ptr, @@ -167,19 +167,18 @@ struct rbtree_node new((void*)ptr) hack_node_t(value); } - #endif }; }//namespace detail { - +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) template struct has_own_construct_from_it < boost::interprocess::detail::rbtree_node > { static const bool value = true; }; - +#endif namespace detail { template @@ -578,7 +577,7 @@ class rbtree iterator insert_unique_commit (MovableConvertible && mv, insert_commit_data &data) { - NodePtr tmp = AllocHolder::create_node(forward(mv)); + NodePtr tmp = AllocHolder::create_node(detail::forward_impl(mv)); iiterator it(this->icont().insert_unique_commit(*tmp, data)); return iterator(it); } @@ -618,7 +617,7 @@ class rbtree if(!ret.second) return ret; return std::pair - (this->insert_unique_commit(forward(mv), data), true); + (this->insert_unique_commit(detail::forward_impl(mv), data), true); } #endif @@ -654,7 +653,7 @@ class rbtree this->insert_unique_check(hint, KeyOfValue()(mv), data); if(!ret.second) return ret.first; - return this->insert_unique_commit(forward(mv), data); + return this->insert_unique_commit(detail::forward_impl(mv), data); } #endif @@ -691,7 +690,7 @@ class rbtree template iterator insert_equal(MovableConvertible &&mv) { - NodePtr p(AllocHolder::create_node(forward(mv))); + NodePtr p(AllocHolder::create_node(detail::forward_impl(mv))); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } #endif @@ -713,7 +712,7 @@ class rbtree template iterator insert_equal(const_iterator hint, MovableConvertible &&mv) { - NodePtr p(AllocHolder::create_node(move(mv))); + NodePtr p(AllocHolder::create_node(detail::move_impl(mv))); return iterator(this->icont().insert_equal(hint.get(), *p)); } #endif diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 0478e2c..56e265d 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -70,14 +70,6 @@ class flat_map { /// @cond private: - //This is the real tree stored here. It's based on a movable pair - typedef detail::flat_tree, - detail::select1st< detail::pair >, - Pred, - typename Alloc::template - rebind >::other> impl_tree_t; - //This is the tree that we should store if pair was movable typedef detail::flat_tree, @@ -85,7 +77,18 @@ class flat_map Pred, Alloc> tree_t; -// tree_t m_flat_tree; // flat tree representing flat_map + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + //This is the real tree stored here. It's based on a movable pair + typedef detail::flat_tree, + detail::select1st< detail::pair >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + #else + typedef tree_t impl_tree_t; + #endif + impl_tree_t m_flat_tree; // flat tree representing flat_map typedef typename impl_tree_t::value_type impl_value_type; @@ -101,19 +104,23 @@ class flat_map typedef typename impl_tree_t::allocator_type impl_allocator_type; #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE typedef detail::moved_object impl_moved_value_type; - #else - typedef impl_value_type&& impl_moved_value_type; #endif + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static D &force(const S &s) - { return *const_cast((reinterpret_cast(&s))); } + { return *((D*)(void*)(const void*)(&s)); } + #else + //For rvalue-aware compilers, just forward + template + static const Type &force(const Type &t) + { return t; } - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &&force(S &&s) - { return reinterpret_cast(s); } + template + static Type &force(Type &t) + { return t; } #endif + /// @endcond public: @@ -168,11 +175,11 @@ class flat_map //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_map(const detail::moved_object >& x) - : m_flat_tree(move(x.get().m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} #else flat_map(flat_map && x) - : m_flat_tree(move(x.m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} #endif //! Effects: Makes *this a copy of x. @@ -189,10 +196,10 @@ class flat_map //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_map& operator=(const detail::moved_object >& mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_map& operator=(flat_map && mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -210,7 +217,7 @@ class flat_map { return value_compare(force(m_flat_tree.key_comp())); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -315,7 +322,7 @@ class flat_map { return m_flat_tree.max_size(); } //! Effects: If there is no key equivalent to x in the flat_map, inserts - //! value_type(move(x), T()) into the flat_map (the key is move-constructed) + //! value_type(detail::move_impl(x), T()) into the flat_map (the key is move-constructed) //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! @@ -342,7 +349,7 @@ class flat_map iterator i = lower_bound(k); // i->first is greater than or equivalent to k. if (i == end() || key_comp()(k, (*i).first)) - i = insert(i, value_type(k, move(T()))); + i = insert(i, value_type(k, detail::move_impl(T()))); return (*i).second; } #else @@ -358,7 +365,7 @@ class flat_map iterator i = lower_bound(k); // i->first is greater than or equivalent to k. if (i == end() || key_comp()(k, (*i).first)) - i = insert(i, value_type(forward(k), move(T()))); + i = insert(i, value_type(detail::forward_impl(k), detail::move_impl(T()))); return (*i).second; } #endif @@ -418,8 +425,7 @@ class flat_map m_flat_tree.insert_unique(force(x))); } #else std::pair insert(value_type &&x) - { return force >( - m_flat_tree.insert_unique(force(move(x)))); } + { return m_flat_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -452,8 +458,7 @@ class flat_map m_flat_tree.insert_unique(force(position), force(x))); } #else iterator insert(iterator position, value_type &&x) - { return force( - m_flat_tree.insert_unique(force(position), force(move(x)))); } + { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -479,8 +484,8 @@ class flat_map //! //! Note: Invalidates elements with keys //! not less than the erased element. - void erase(const_iterator position) - { m_flat_tree.erase(force(position)); } + iterator erase(const_iterator position) + { return force(m_flat_tree.erase(force(position))); } //! Effects: Erases all elements in the container with key equivalent to x. //! @@ -499,8 +504,8 @@ class flat_map //! //! Complexity: Logarithmic search time plus erasure time //! linear to the elements with bigger keys. - void erase(const_iterator first, const_iterator last) - { m_flat_tree.erase(force(first), force(last)); } + iterator erase(const_iterator first, const_iterator last) + { return force(m_flat_tree.erase(force(first), force(last))); } //! Effects: erase(a.begin(),a.end()). //! @@ -715,6 +720,12 @@ class flat_multimap { /// @cond private: + typedef detail::flat_tree, + detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE //This is the real tree stored here. It's based on a movable pair typedef detail::flat_tree, @@ -722,13 +733,10 @@ class flat_multimap Pred, typename Alloc::template rebind >::other> impl_tree_t; + #else + typedef tree_t impl_tree_t; + #endif - typedef detail::flat_tree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; -// tree_t m_flat_tree; // flat tree representing flat_multimap impl_tree_t m_flat_tree; // flat tree representing flat_map typedef typename impl_tree_t::value_type impl_value_type; @@ -744,18 +752,21 @@ class flat_multimap typedef typename impl_tree_t::allocator_type impl_allocator_type; #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE typedef detail::moved_object impl_moved_value_type; - #else - typedef impl_value_type&& impl_moved_value_type; #endif + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static D &force(const S &s) { return *const_cast((reinterpret_cast(&s))); } + #else + //For rvalue-aware compilers, just forward + template + static const Type &force(const Type &t) + { return t; } - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &&force(S &&s) - { return reinterpret_cast(s); } + template + static Type &force(Type &t) + { return t; } #endif /// @endcond @@ -812,10 +823,10 @@ class flat_multimap //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multimap(const detail::moved_object >& x) - : m_flat_tree(move(x.get().m_flat_tree)) { } + : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) { } #else flat_multimap(flat_multimap && x) - : m_flat_tree(move(x.m_flat_tree)) { } + : m_flat_tree(detail::move_impl(x.m_flat_tree)) { } #endif //! Effects: Makes *this a copy of x. @@ -831,11 +842,11 @@ class flat_multimap #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multimap& operator=(const detail::moved_object >& mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_multimap& operator=(flat_multimap && mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -853,7 +864,7 @@ class flat_multimap { return value_compare(force(m_flat_tree.key_comp())); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -1002,7 +1013,7 @@ class flat_multimap { return force(m_flat_tree.insert_equal(force(x))); } #else iterator insert(value_type &&x) - { return force(m_flat_tree.insert_equal(force(move(x)))); } + { return m_flat_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -1035,7 +1046,7 @@ class flat_multimap { return force(m_flat_tree.insert_equal(force(position), force(x))); } #else iterator insert(iterator position, value_type &&x) - { return force(m_flat_tree.insert_equal(force(position), force(move(x)))); } + { return m_flat_tree.insert_equal(force(position), detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -1060,8 +1071,8 @@ class flat_multimap //! //! Note: Invalidates elements with keys //! not less than the erased element. - void erase(const_iterator position) - { m_flat_tree.erase(force(position)); } + iterator erase(const_iterator position) + { return force(m_flat_tree.erase(force(position))); } //! Effects: Erases all elements in the container with key equivalent to x. //! @@ -1080,8 +1091,8 @@ class flat_multimap //! //! Complexity: Logarithmic search time plus erasure time //! linear to the elements with bigger keys. - void erase(const_iterator first, const_iterator last) - { m_flat_tree.erase(force(first), force(last)); } + iterator erase(const_iterator first, const_iterator last) + { return force(m_flat_tree.erase(force(first), force(last))); } //! Effects: erase(a.begin(),a.end()). //! diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index d98677a..bdffbf5 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -117,10 +117,10 @@ class flat_set //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_set(const detail::moved_object >& mx) - : m_flat_tree(move(mx.get().m_flat_tree)) {} + : m_flat_tree(detail::move_impl(mx.get().m_flat_tree)) {} #else flat_set(flat_set && mx) - : m_flat_tree(move(mx.m_flat_tree)) {} + : m_flat_tree(detail::move_impl(mx.m_flat_tree)) {} #endif //! Effects: Makes *this a copy of x. @@ -134,11 +134,11 @@ class flat_set //! Complexity: Linear in x.size(). #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_set& operator=(const detail::moved_object > &mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_set& operator=(flat_set &&mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif @@ -157,7 +157,7 @@ class flat_set { return m_flat_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -314,7 +314,7 @@ class flat_set { return m_flat_tree.insert_unique(x); } #else std::pair insert(value_type && x) - { return m_flat_tree.insert_unique(move(x)); } + { return m_flat_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -345,7 +345,7 @@ class flat_set { return m_flat_tree.insert_unique(position, x); } #else iterator insert(iterator position, value_type && x) - { return m_flat_tree.insert_unique(position, move(x)); } + { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -588,6 +588,17 @@ inline bool operator<(const flat_multiset& x, const flat_multiset& y); /// @endcond +//! flat_multiset is a Sorted Associative Container that stores objects of type Key. +//! flat_multiset is a Simple Associative Container, meaning that its value type, +//! as well as its key type, is Key. +//! flat_Multiset can store multiple copies of the same key value. +//! +//! flat_multiset is similar to std::multiset but it's implemented like an ordered vector. +//! This means that inserting a new element into a flat_multiset invalidates +//! previous iterators and references +//! +//! Erasing an element of a flat_multiset invalidates iterators and references +//! pointing to elements that come after (their keys are equal or bigger) the erased element. template class flat_multiset { @@ -633,10 +644,10 @@ class flat_multiset #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multiset(const detail::moved_object >& x) - : m_flat_tree(move(x.get().m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} #else flat_multiset(flat_multiset && x) - : m_flat_tree(move(x.m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} #endif flat_multiset& operator=(const flat_multiset& x) @@ -644,10 +655,10 @@ class flat_multiset #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multiset& operator=(const detail::moved_object >& mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_multiset& operator=(flat_multiset && mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -665,7 +676,7 @@ class flat_multiset { return m_flat_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -814,7 +825,7 @@ class flat_multiset { return m_flat_tree.insert_equal(x); } #else iterator insert(value_type && x) - { return m_flat_tree.insert_equal(move(x)); } + { return m_flat_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -845,7 +856,7 @@ class flat_multiset { return m_flat_tree.insert_equal(position, x); } #else iterator insert(iterator position, value_type && x) - { return m_flat_tree.insert_equal(position, move(x)); } + { return m_flat_tree.insert_equal(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index b9e0801..751408d 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -93,7 +93,7 @@ struct list_node #else template list_node(Convertible &&conv) - : m_data(forward(conv)) + : m_data(detail::forward_impl(conv)) {} #endif @@ -323,7 +323,7 @@ class list {} // list(size_type n) -// : AllocHolder(move(allocator_type())) +// : AllocHolder(detail::move_impl(allocator_type())) // { this->resize(n); } //! Effects: Constructs a list that will use a copy of allocator a @@ -355,11 +355,11 @@ class list //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE list(const detail::moved_object &x) - : AllocHolder(move((AllocHolder&)x.get())) + : AllocHolder(detail::move_impl((AllocHolder&)x.get())) {} #else list(list &&x) - : AllocHolder(move((AllocHolder&)x)) + : AllocHolder(detail::move_impl((AllocHolder&)x)) {} #endif @@ -518,7 +518,7 @@ class list { this->insert(this->begin(), x); } #else void push_front(T &&x) - { this->insert(this->begin(), move(x)); } + { this->insert(this->begin(), detail::move_impl(x)); } #endif //! Effects: Removes the last element from the list. @@ -539,7 +539,7 @@ class list { this->insert(this->end(), x); } #else void push_back (T &&x) - { this->insert(this->end(), move(x)); } + { this->insert(this->end(), detail::move_impl(x)); } #endif //! Effects: Removes the first element from the list. @@ -610,7 +610,7 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - iterator i = this->begin(), iend = this->end(); + iterator iend = this->end(); size_type len = this->size(); if(len > new_size){ @@ -633,15 +633,26 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - iterator i = this->begin(), iend = this->end(); + iterator iend = this->end(); size_type len = this->size(); if(len > new_size){ size_type to_erase = len - new_size; - while(to_erase--){ - --iend; + iterator ifirst; + if(to_erase < len/2u){ + ifirst = iend; + while(to_erase--){ + --ifirst; + } } - this->erase(iend, this->end()); + else{ + ifirst = this->begin(); + size_type to_skip = len - to_erase; + while(to_skip--){ + ++ifirst; + } + } + this->erase(ifirst, iend); } else{ this->priv_create_and_insert_nodes(this->end(), new_size - len); @@ -763,7 +774,7 @@ class list #else iterator insert(iterator p, T &&x) { - NodePtr tmp = AllocHolder::create_node(move(x)); + NodePtr tmp = AllocHolder::create_node(detail::move_impl(x)); return iterator(this->icont().insert(p.get(), *tmp)); } #endif diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index b8d45f3..bfd6333 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -8,7 +8,7 @@ // ////////////////////////////////////////////////////////////////////////////// // -// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gazta�ga 2004. +// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gaztanaga. // Renaming, isolating and porting to generic algorithms. Pointer typedef // set to allocator::pointer to allow placing it in shared memory. // @@ -166,11 +166,11 @@ class map //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE map(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else map(map &&x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -185,10 +185,10 @@ class map //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE map& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else map& operator=(map &&x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -206,7 +206,7 @@ class map { return value_compare(m_tree.key_comp()); } //! Effects: Returns a copy of the Allocator that - //! was passed to the objects constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -322,14 +322,14 @@ class map iterator i = lower_bound(k); // i->first is greater than or equivalent to k. if (i == end() || key_comp()(k, (*i).first)){ - value_type val(k, move(T())); - i = insert(i, move(val)); + value_type val(k, detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(move(x), T()) into the map (the key is move-constructed) + //! value_type(detail::move_impl(x), T()) into the map (the key is move-constructed) //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! @@ -342,8 +342,8 @@ class map iterator i = lower_bound(k); // i->first is greater than or equivalent to k. if (i == end() || key_comp()(k, (*i).first)){ - value_type val(k, move(T())); - i = insert(i, move(val)); + value_type val(k, detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } @@ -355,8 +355,8 @@ class map iterator i = lower_bound(k); // i->first is greater than or equivalent to k. if (i == end() || key_comp()(k, (*i).first)){ - value_type val(move(k), move(T())); - i = insert(i, move(val)); + value_type val(detail::move_impl(k), detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } @@ -364,7 +364,7 @@ class map /* //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(move(x), T()) into the map (the key is move-constructed) + //! value_type(detail::move_impl(x), T()) into the map (the key is move-constructed) //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! @@ -379,8 +379,8 @@ class map iterator i = lower_bound(k); // i->first is greater than or equivalent to k. if (i == end() || key_comp()(k, (*i).first)){ - value_type val(k, move(T())); - i = insert(i, move(val)); + value_type val(k, detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } @@ -449,7 +449,7 @@ class map { return m_tree.insert_unique(x); } #else std::pair insert(std::pair &&x) - { return m_tree.insert_unique(move(x)); } + { return m_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Move constructs a new value from x if and only if there is @@ -465,7 +465,7 @@ class map { return m_tree.insert_unique(x); } #else std::pair insert(value_type &&x) - { return m_tree.insert_unique(move(x)); } + { return m_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -494,7 +494,7 @@ class map { return m_tree.insert_unique(position, x); } #else iterator insert(iterator position, std::pair &&x) - { return m_tree.insert_unique(position, move(x)); } + { return m_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -517,7 +517,7 @@ class map { return m_tree.insert_unique(position, x); } #else iterator insert(iterator position, value_type &&x) - { return m_tree.insert_unique(position, move(x)); } + { return m_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -813,11 +813,11 @@ class multimap //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multimap(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else multimap(multimap && x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -834,11 +834,11 @@ class multimap #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multimap& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else multimap& operator=(multimap && x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -856,7 +856,7 @@ class multimap { return value_compare(m_tree.key_comp()); } //! Effects: Returns a copy of the Allocator that - //! was passed to the objects constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -1006,7 +1006,7 @@ class multimap { return m_tree.insert_equal(x); } #else iterator insert(std::pair && x) - { return m_tree.insert_equal(move(x)); } + { return m_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -1044,7 +1044,7 @@ class multimap { return m_tree.insert_equal(position, x); } #else iterator insert(iterator position, std::pair && x) - { return m_tree.insert_equal(position, move(x)); } + { return m_tree.insert_equal(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index bc4b364..a0a3a52 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -143,11 +143,11 @@ class set //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE set(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else set(set &&x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -162,10 +162,10 @@ class set //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE set& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else set& operator=(set &&x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -183,7 +183,7 @@ class set { return m_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -334,7 +334,7 @@ class set { return m_tree.insert_unique(x); } #else std::pair insert(value_type &&x) - { return m_tree.insert_unique(move(x)); } + { return m_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -360,7 +360,7 @@ class set { return m_tree.insert_unique(p, x); } #else iterator insert(const_iterator p, value_type &&x) - { return m_tree.insert_unique(p, move(x)); } + { return m_tree.insert_unique(p, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -632,11 +632,11 @@ class multiset //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multiset(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else multiset(multiset &&x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -651,10 +651,10 @@ class multiset //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multiset& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else multiset& operator=(multiset &&x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -672,7 +672,7 @@ class multiset { return m_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -818,7 +818,7 @@ class multiset { return m_tree.insert_equal(x); } #else iterator insert(value_type && x) - { return m_tree.insert_equal(move(x)); } + { return m_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -845,7 +845,7 @@ class multiset { return m_tree.insert_equal(p, x); } #else iterator insert(const_iterator p, value_type && x) - { return m_tree.insert_equal(p, move(x)); } + { return m_tree.insert_equal(p, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 3424175..a0724e2 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -87,7 +87,7 @@ struct slist_node #else template slist_node(Convertible &&value) - : m_data(forward(value)){} + : m_data(detail::forward_impl(value)){} #endif T m_data; @@ -321,7 +321,7 @@ class slist {} // explicit slist(size_type n) -// : AllocHolder(move(allocator_type())) +// : AllocHolder(detail::move_impl(allocator_type())) // { this->resize(n); } //! Effects: Constructs a list that will use a copy of allocator a @@ -367,11 +367,11 @@ class slist //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE slist(const detail::moved_object &x) - : AllocHolder(move((AllocHolder&)x.get())) + : AllocHolder(detail::move_impl((AllocHolder&)x.get())) {} #else slist(slist &&x) - : AllocHolder(move((AllocHolder&)x)) + : AllocHolder(detail::move_impl((AllocHolder&)x)) {} #endif @@ -594,7 +594,7 @@ class slist { this->icont().push_front(*this->create_node(x)); } #else void push_front(T && x) - { this->icont().push_front(*this->create_node(move(x))); } + { this->icont().push_front(*this->create_node(detail::move_impl(x))); } #endif //! Effects: Removes the first element from the list. @@ -659,7 +659,7 @@ class slist { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } #else iterator insert_after(iterator prev_pos, value_type && x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(move(x)))); } + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(detail::move_impl(x)))); } #endif //! Requires: prev_pos must be a valid iterator of *this. @@ -717,7 +717,7 @@ class slist { return this->insert_after(previous(p), x); } #else iterator insert(iterator p, value_type && x) - { return this->insert_after(previous(p), move(x)); } + { return this->insert_after(previous(p), detail::move_impl(x)); } #endif //! Requires: p must be a valid iterator of *this. @@ -1426,7 +1426,8 @@ struct has_trivial_destructor_after_move > // Specialization of insert_iterator so that insertions will be constant // time rather than linear time. -//iG +///@cond + //Ummm, I don't like to define things in namespace std, but //there is no other way namespace std { @@ -1464,7 +1465,7 @@ class insert_iterator > } //namespace std; - +///@endcond #include diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 1c83a75..33ca269 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -281,7 +281,7 @@ class basic_string_base (void)limit_size; (void)reuse; if(!(command & allocate_new)) - return std::pair(0, 0); + return std::pair(pointer(0), 0); received_size = preferred_size; return std::make_pair(this->alloc().allocate(received_size), false); } @@ -308,7 +308,7 @@ class basic_string_base } void construct(pointer p, const value_type &value = value_type()) - { new(detail::get_pointer(p)) value_type(value); } + { new((void*)detail::get_pointer(p)) value_type(value); } void destroy(pointer p, size_type n) { @@ -520,8 +520,9 @@ class basic_string /// @endcond public: // Constructor, destructor, assignment. - + /// @cond struct reserve_t {}; + /// @endcond basic_string(reserve_t, std::size_t n, const allocator_type& a = allocator_type()) @@ -551,11 +552,11 @@ class basic_string //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_string(const detail::moved_object& s) - : base_t(move((base_t&)s.get())) + : base_t(detail::move_impl((base_t&)s.get())) {} #else basic_string(basic_string && s) - : base_t(move((base_t&)s)) + : base_t(detail::move_impl((base_t&)s)) {} #endif @@ -1940,7 +1941,7 @@ operator+(basic_string && mx, const basic_string& y) { mx += y; - return move(mx); + return detail::move_impl(mx); } #endif @@ -1994,7 +1995,7 @@ operator+(const CharT* s, basic_string && my) { typedef typename basic_string::size_type size_type; - return move(my.get().replace(size_type(0), size_type(0), s)); + return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); } #endif @@ -2061,7 +2062,7 @@ operator+(basic_string && mx, const CharT* s) { mx += s; - return move(mx); + return detail::move_impl(mx); } #endif @@ -2093,7 +2094,7 @@ basic_string && operator+(basic_string && mx, const CharT c) { mx += c; - return move(mx); + return detail::move_impl(mx); } #endif diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index f1af804..85bd620 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -288,7 +288,7 @@ struct vector_alloc_holder (void)limit_size; (void)reuse; if(!(command & allocate_new)) - return std::pair(0, 0); + return std::pair(pointer(0), 0); received_size = preferred_size; return std::make_pair(this->alloc().allocate(received_size), false); } @@ -301,8 +301,8 @@ struct vector_alloc_holder const pointer &reuse, allocator_v2) { - return this->alloc().allocation_command(command, limit_size, preferred_size, - received_size, reuse); + return this->alloc().allocation_command + (command, limit_size, preferred_size, received_size, reuse); } size_type next_capacity(size_type additional_objects) const @@ -434,7 +434,10 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for copy constructors //so that std::copy and similar can use memcpy typedef typename detail::if_c - ::value + #endif ,T* ,detail::move_iterator >::type copy_move_it; @@ -443,6 +446,9 @@ class vector : private detail::vector_alloc_holder //so that std::uninitialized_copy and similar can use memcpy typedef typename detail::if_c ::value + #endif ,T* ,detail::move_iterator >::type assign_move_it; @@ -491,7 +497,7 @@ class vector : private detail::vector_alloc_holder { this->swap(mx.get()); } #else vector(vector && mx) - : base_t(mx) + : base_t(detail::move_impl(mx)) { this->swap(mx); } #endif @@ -859,7 +865,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start) + this->members_.m_size)value_type(x); + new((void*)(detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); ++this->members_.m_size; } else{ @@ -878,7 +884,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(mx); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(mx); ++this->members_.m_size; } else{ @@ -890,11 +896,11 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(move(mx)); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(detail::move_impl(mx)); ++this->members_.m_size; } else{ - this->insert(this->end(), move(mx)); + this->insert(this->end(), detail::move_impl(mx)); } } #endif @@ -1101,7 +1107,7 @@ class vector : private detail::vector_alloc_holder T *ptr = detail::get_pointer(this->members_.m_start + this->members_.m_size); while(n--){ //Default construct - new(ptr++)T(); + new((void*)ptr++)T(); ++this->members_.m_size; } } @@ -1148,8 +1154,15 @@ class vector : private detail::vector_alloc_holder } else{ size_type received_size; - this->alloc().allocation_command(shrink_in_place, this->size(), this->capacity() - ,received_size, this->members_.m_start); + if(this->alloc().allocation_command + ( shrink_in_place | nothrow_allocation + , this->capacity(), this->size() + , received_size, this->members_.m_start).first){ + this->members_.m_capacity = received_size; + #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS + ++this->num_shrink; + #endif + } } } } @@ -1241,9 +1254,9 @@ class vector : private detail::vector_alloc_holder std::uninitialized_copy(copy_move_it(old_finish - n), copy_move_it(old_finish), old_finish); this->members_.m_size += n; //Copy previous to last objects to the initialized end - std::copy_backward(assign_move_it(detail::get_pointer(pos)), assign_move_it(old_finish - n), old_finish); + std::copy_backward(assign_move_it(pos), assign_move_it(old_finish - n), old_finish); //Insert new objects in the pos - std::copy(first, last, detail::get_pointer(pos)); + std::copy(first, last, pos); } else { //The new elements don't fit in the [pos, end()) range. Copy @@ -1254,12 +1267,12 @@ class vector : private detail::vector_alloc_holder this->members_.m_size += n - elems_after; //Copy old [pos, end()) elements to the uninitialized memory std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) + ( copy_move_it(pos) , copy_move_it(old_finish) , detail::get_pointer(this->members_.m_start) + this->members_.m_size); this->members_.m_size += elems_after; //Copy first new elements in pos - std::copy(first, mid, detail::get_pointer(pos)); + std::copy(first, mid, pos); } } @@ -1277,7 +1290,7 @@ class vector : private detail::vector_alloc_holder //the start of the new buffer new_finish = std::uninitialized_copy ( copy_move_it(detail::get_pointer(this->members_.m_start)) - , copy_move_it(detail::get_pointer(pos)) + , copy_move_it(pos) , old_finish = new_finish); construted_values_destroyer.increment_size(new_finish - old_finish); //Initialize new objects, starting from previous point @@ -1287,9 +1300,9 @@ class vector : private detail::vector_alloc_holder //Initialize from the rest of the old buffer, //starting from previous point new_finish = std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) + ( copy_move_it(pos) , copy_move_it(detail::get_pointer(this->members_.m_start) + this->members_.m_size) - , detail::get_pointer(new_finish)); + , new_finish); //All construction successful, disable rollbacks construted_values_destroyer.release(); @@ -1345,13 +1358,11 @@ class vector : private detail::vector_alloc_holder //Copy first old values before pos, after that the //new objects boost::interprocess::uninitialized_copy_copy - (copy_move_it(old_start), copy_move_it(detail::get_pointer(pos)), first, last, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); //Now initialize the rest of memory with the last old values std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) - , copy_move_it(old_finish) - , detail::get_pointer(new_start) + elemsbefore + n); + (copy_move_it(pos), copy_move_it(old_finish), new_start + elemsbefore + n); //All new elements correctly constructed, avoid new element destruction new_values_destroyer.release(); this->members_.m_size = old_size + n; @@ -1376,17 +1387,13 @@ class vector : private detail::vector_alloc_holder //Copy first old values before pos, after that the //new objects boost::interprocess::uninitialized_copy_copy - ( copy_move_it(old_start) - , copy_move_it(detail::get_pointer(pos)) - , first, last, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); size_type raw_gap = s_before - (elemsbefore + n); //Now initialize the rest of s_before memory with the //first of elements after new values std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) - , copy_move_it(detail::get_pointer(pos) + raw_gap) - , detail::get_pointer(new_start) + elemsbefore + n); + (copy_move_it(pos), copy_move_it(pos + raw_gap), new_start + elemsbefore + n); //All new elements correctly constructed, avoid new element destruction new_values_destroyer.release(); //All new elements correctly constructed, avoid old element destruction @@ -1394,7 +1401,7 @@ class vector : private detail::vector_alloc_holder //Update size since we have a contiguous buffer this->members_.m_size = old_size + s_before; //Now copy remaining last objects in the old buffer begin - T *to_destroy = std::copy(assign_move_it(detail::get_pointer(pos) + raw_gap), assign_move_it(old_finish), old_start); + T *to_destroy = std::copy(assign_move_it(pos + raw_gap), assign_move_it(old_finish), old_start); //Now destroy redundant elements except if they were moved and //they have trivial destructor after move size_type n_destroy = old_finish - to_destroy; @@ -1460,24 +1467,22 @@ class vector : private detail::vector_alloc_holder //Copy the first part of old_begin to raw_mem T *start_n = old_start + difference_type(s_before); std::uninitialized_copy - ( copy_move_it(old_start) - , copy_move_it(start_n) - , detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(start_n), new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); this->members_.m_size = old_size + s_before; //Now copy the second part of old_begin overwriting himself - T* next = std::copy(assign_move_it(start_n), assign_move_it(detail::get_pointer(pos)), old_start); + T* next = std::copy(assign_move_it(start_n), assign_move_it(pos), old_start); if(do_after){ //Now copy the new_beg elements - std::copy(first, before_end, detail::get_pointer(next)); + std::copy(first, before_end, next); } else{ //Now copy the all the new elements - T* move_start = std::copy(first, last, detail::get_pointer(next)); + T* move_start = std::copy(first, last, next); //Now displace old_end elements - T* move_end = std::copy(assign_move_it(detail::get_pointer(pos)), assign_move_it(old_finish), detail::get_pointer(move_start)); + T* move_end = std::copy(assign_move_it(pos), assign_move_it(old_finish), move_start); //Destroy remaining moved elements from old_end except if //they have trivial destructor after being moved difference_type n_destroy = s_before - n; @@ -1513,9 +1518,7 @@ class vector : private detail::vector_alloc_holder size_type n_new_init = difference_type(s_before) - elemsbefore; std::advance(mid, n_new_init); boost::interprocess::uninitialized_copy_copy - ( copy_move_it(old_start) - , copy_move_it(detail::get_pointer(pos)) - , first, mid, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, mid, new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); @@ -1529,7 +1532,7 @@ class vector : private detail::vector_alloc_holder //Copy all new elements T* move_start = std::copy(mid, last, old_start); //Displace old_end - T* move_end = std::copy(copy_move_it(detail::get_pointer(pos)), copy_move_it(old_finish), detail::get_pointer(move_start)); + T* move_end = std::copy(copy_move_it(pos), copy_move_it(old_finish), move_start); //Destroy remaining moved elements from old_end except if they //have trivial destructor after being moved difference_type n_destroy = s_before - n; @@ -1584,14 +1587,12 @@ class vector : private detail::vector_alloc_holder //First copy the part of old_end raw_mem T* finish_n = old_finish - difference_type(n_after); std::uninitialized_copy - ( copy_move_it(detail::get_pointer(finish_n)) - , copy_move_it(old_finish) - , old_finish); + (copy_move_it(finish_n), copy_move_it(old_finish), old_finish); this->members_.m_size += n_after; //Displace the rest of old_end to the new position - std::copy_backward(assign_move_it(detail::get_pointer(pos)), assign_move_it(detail::get_pointer(finish_n)), old_finish); + std::copy_backward(assign_move_it(pos), assign_move_it(finish_n), old_finish); //Now overwrite with new_end - std::copy(first, last, detail::get_pointer(pos)); + std::copy(first, last, pos); } else { //The raw_mem from end will divide new_end part @@ -1610,13 +1611,10 @@ class vector : private detail::vector_alloc_holder std::advance(mid, elemsafter); //First initialize data in raw memory boost::interprocess::uninitialized_copy_copy - ( mid, last - , copy_move_it(detail::get_pointer(pos)) - , copy_move_it(old_finish) - , old_finish); + ( mid, last, copy_move_it(pos), copy_move_it(old_finish), old_finish); this->members_.m_size += n_after; //Now copy the part of new_end over constructed elements - std::copy(first, mid, detail::get_pointer(pos)); + std::copy(first, mid, pos); } } } @@ -1727,8 +1725,9 @@ class vector : private detail::vector_alloc_holder //Backup old buffer data size_type old_offset = old_start - detail::get_pointer(ret.first); size_type first_count = min_value(n, old_offset); - FwdIt mid = boost::interprocess::n_uninitialized_copy_n + boost::interprocess::uninitialized_copy_n (first, first_count, detail::get_pointer(ret.first)); + FwdIt mid = first + first_count; if(old_offset > n){ //All old elements will be destroyed by "old_values_destroyer" @@ -1742,12 +1741,13 @@ class vector : private detail::vector_alloc_holder this->members_.m_size = first_count + old_size; //Now overwrite the old values size_type second_count = min_value(old_size, n - first_count); - mid = copy_n(mid, second_count, old_start); + copy_n(mid, second_count, old_start); + mid += second_count; //Check if we still have to append elements in the //uninitialized end if(second_count == old_size){ - boost::interprocess::n_uninitialized_copy_n + boost::interprocess::uninitialized_copy_n ( mid , n - first_count - second_count , old_start + old_size); @@ -1801,9 +1801,10 @@ class vector : private detail::vector_alloc_holder public: unsigned int num_expand_fwd; unsigned int num_expand_bwd; + unsigned int num_shrink; unsigned int num_alloc; void reset_alloc_stats() - { num_expand_fwd = num_expand_bwd = num_alloc = 0; } + { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } #endif /// @endcond }; diff --git a/include/boost/interprocess/creation_tags.hpp b/include/boost/interprocess/creation_tags.hpp index 190c6bd..61d537a 100644 --- a/include/boost/interprocess/creation_tags.hpp +++ b/include/boost/interprocess/creation_tags.hpp @@ -25,21 +25,37 @@ struct create_only_t {}; //!be only opened struct open_only_t {}; +//!Tag to indicate that the resource must +//!be only opened for reading +struct open_read_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened for reading +struct open_copy_on_write_t {}; + //!Tag to indicate that the resource must //!be created. If already created, it must be opened. struct open_or_create_t {}; //!Value to indicate that the resource must //!be only created -static const create_only_t create_only = create_only_t(); +static const create_only_t create_only = create_only_t(); //!Value to indicate that the resource must //!be only opened -static const open_only_t open_only = open_only_t(); +static const open_only_t open_only = open_only_t(); + +//!Value to indicate that the resource must +//!be only opened for reading +static const open_read_only_t open_read_only = open_read_only_t(); //!Value to indicate that the resource must //!be created. If already created, it must be opened. -static const open_or_create_t open_or_create = open_or_create_t(); +static const open_or_create_t open_or_create = open_or_create_t(); + +//!Value to indicate that the resource must +//!be only opened for reading +static const open_copy_on_write_t open_copy_on_write = open_copy_on_write_t(); namespace detail { diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index 233080d..a949e96 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -20,12 +20,18 @@ #include #include #include -#include +#include +#include +#include #include +#include +#include namespace boost { namespace interprocess { +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) + template struct has_own_construct_from_it { @@ -43,7 +49,7 @@ inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_) template inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_) { - new(dest)T(*source); + new((void*)dest)T(*source); } } //namespace detail { @@ -55,25 +61,81 @@ inline void construct_in_place(T* dest, InpIt source) detail::construct_in_place_impl(dest, source, boolean_t()); } +#else +template +inline void construct_in_place(T* dest, InpIt source) +{ new((void*)dest)T(*source); } +#endif + template inline void construct_in_place(T *dest, default_construct_iterator) { - new(dest)T(); + new((void*)dest)T(); } + template -InIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) +struct optimize_assign +{ + static const bool value = false; +}; + +template +struct optimize_assign +{ + static const bool value = boost::has_trivial_assign::value; +}; + +template +struct optimize_assign + : public optimize_assign +{}; + +template +struct optimize_copy +{ + static const bool value = false; +}; + +template +struct optimize_copy +{ + static const bool value = boost::has_trivial_copy::value; +}; + +template +struct optimize_copy + : public optimize_copy +{}; + + +template inline +OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, detail::bool_) { for (; length--; ++dest, ++first) *dest = *first; - return first; + return dest; +} + +template inline +T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +{ + std::size_t size = length*sizeof(T); + return ((T*)std::memmove(dest, first, size)) + size; +} + +template inline +OutIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) +{ + const bool do_optimized_assign = optimize_assign::value; + return copy_n_dispatch(first, length, dest, detail::bool_()); } template inline -InIt n_uninitialized_copy_n +FwdIt uninitialized_copy_n_dispatch (InIt first, typename std::iterator_traits::difference_type count, - FwdIt dest) + FwdIt dest, detail::bool_) { typedef typename std::iterator_traits::value_type value_type; //Save initial destination position @@ -95,9 +157,28 @@ InIt n_uninitialized_copy_n BOOST_RETHROW } BOOST_CATCH_END - return first; + return dest; } + +template inline +T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +{ + std::size_t size = length*sizeof(T); + return ((T*)std::memmove(dest, first, size)) + size; +} + +template inline +FwdIt uninitialized_copy_n + (InIt first, + typename std::iterator_traits::difference_type count, + FwdIt dest) +{ + const bool do_optimized_copy = optimize_copy::value; + return uninitialized_copy_n_dispatch(first, count, dest, detail::bool_()); +} + + // uninitialized_copy_copy // Copies [first1, last1) into [result, result + (last1 - first1)), and // copies [first2, last2) into diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp index 4db523a..e872b53 100644 --- a/include/boost/interprocess/detail/config_begin.hpp +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -30,4 +30,5 @@ #pragma warning (disable : 4711) // function selected for automatic inline expansion #pragma warning (disable : 4786) // identifier truncated in debug info #pragma warning (disable : 4996) // 'function': was declared deprecated + #pragma warning (disable : 4197) // top-level volatile in cast is ignored #endif diff --git a/include/boost/interprocess/detail/file_wrapper.hpp b/include/boost/interprocess/detail/file_wrapper.hpp index e172f19..22f92e9 100644 --- a/include/boost/interprocess/detail/file_wrapper.hpp +++ b/include/boost/interprocess/detail/file_wrapper.hpp @@ -51,7 +51,7 @@ class file_wrapper //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE file_wrapper - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else file_wrapper(file_wrapper &&moved) @@ -63,7 +63,7 @@ class file_wrapper //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE file_wrapper &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { file_wrapper tmp(moved); this->swap(tmp); @@ -72,7 +72,7 @@ class file_wrapper #else file_wrapper &operator=(file_wrapper &&moved) { - file_wrapper tmp(move(moved)); + file_wrapper tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } diff --git a/include/boost/interprocess/detail/intersegment_ptr.hpp b/include/boost/interprocess/detail/intersegment_ptr.hpp new file mode 100644 index 0000000..6b885b0 --- /dev/null +++ b/include/boost/interprocess/detail/intersegment_ptr.hpp @@ -0,0 +1,1054 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP +#define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include //vector +#include //set +#include +#include +#include +#include +#include //BOOST_STATIC_ASSERT +#include //CHAR_BIT +#include +#include //assert +#include + +//!\file +//! +namespace boost { + +//Predeclarations +template +struct has_trivial_constructor; + +template +struct has_trivial_destructor; + +namespace interprocess { + +template +struct is_multisegment_ptr; + +struct intersegment_base +{ + typedef intersegment_base self_t; + BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*))); + BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64)); + static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64; + static const std::size_t ctrl_bits = 2; + static const std::size_t align_bits = 12; + static const std::size_t align = std::size_t(1) << align_bits; + static const std::size_t max_segment_size_bits = size_t_bits - 2; + static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits; + + static const std::size_t begin_bits = max_segment_size_bits - align_bits; + static const std::size_t pow_size_bits_helper = static_log2::value; + static const std::size_t pow_size_bits = + (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ? + pow_size_bits_helper : pow_size_bits_helper + 1; + static const std::size_t frc_size_bits = + size_t_bits - ctrl_bits - begin_bits - pow_size_bits; + + BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits )); + + static const std::size_t relative_size_bits = + size_t_bits - max_segment_size_bits - ctrl_bits; + + static const std::size_t is_pointee_outside = 0; + static const std::size_t is_in_stack = 1; + static const std::size_t is_relative = 2; + static const std::size_t is_segmented = 3; + static const std::size_t is_max_mode = 4; + + intersegment_base() + { + this->set_mode(is_pointee_outside); + this->set_null(); + } + + struct relative_addressing + { + std::size_t ctrl : 2; + std::size_t pow : pow_size_bits; + std::size_t frc : frc_size_bits; + std::size_t beg : begin_bits; + std::ptrdiff_t off : sizeof(ptrdiff_t)*CHAR_BIT - 2; + std::ptrdiff_t bits : 2; + }; + + struct direct_addressing + { + std::size_t ctrl : 2; + std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2; + void * addr; + }; + + struct segmented_addressing + { + std::size_t ctrl : 2; + std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2; + std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2; + std::size_t bits : 2; + }; + + union members_t{ + relative_addressing relative; + direct_addressing direct; + segmented_addressing segmented; + } members; + + BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t)); + + void *relative_calculate_begin_addr() const + { + const std::size_t mask = ~(align - 1); + std::size_t beg = this->members.relative.beg; + return (void*)((((std::size_t)this) & mask) - (beg << align_bits)); + } + + void relative_set_begin_from_base(void *addr) + { + assert(addr < (void*)this); + std::size_t off = (char*)this - (char*)addr; + members.relative.beg = off >> align_bits; + } + + //!Obtains the address pointed by the + //!object + std::size_t relative_size() const + { + std::size_t pow = members.relative.pow; + std::size_t size = (std::size_t(1u) << pow); + assert(pow >= frc_size_bits); + size |= members.relative.frc << (pow - frc_size_bits); + return size; + } + + static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc) + { + if(orig_size < align) + orig_size = align; + orig_size = detail::get_rounded_size_po2(orig_size, align); + pow = detail::floor_log2(orig_size); + std::size_t low_size = (std::size_t(1) << pow); + std::size_t diff = orig_size - low_size; + assert(pow >= frc_size_bits); + std::size_t rounded = detail::get_rounded_size_po2 + (diff, (1u << (pow - frc_size_bits))); + if(rounded == low_size){ + ++pow; + frc = 0; + rounded = 0; + } + else{ + frc = rounded >> (pow - frc_size_bits); + } + assert(((frc << (pow - frc_size_bits)) & (align-1))==0); + return low_size + rounded; + } + + std::size_t get_mode()const + { return members.direct.ctrl; } + + void set_mode(std::size_t mode) + { + assert(mode < is_max_mode); + members.direct.ctrl = mode; + } + + //!Returns true if object represents + //!null pointer + bool is_null() const + { + return (this->get_mode() < is_relative) && + !members.direct.dummy && + !members.direct.addr; + } + + //!Sets the object to represent + //!the null pointer + void set_null() + { + if(this->get_mode() >= is_relative){ + this->set_mode(is_pointee_outside); + } + members.direct.dummy = 0; + members.direct.addr = 0; + } + + static std::size_t round_size(std::size_t orig_size) + { + std::size_t pow, frc; + return calculate_size(orig_size, pow, frc); + } +}; + + + +//!Configures intersegment_ptr with the capability to address: +//!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups +//!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group. +//!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment. +//!The mapping is implemented through flat_maps synchronized with mutexes. +template +struct flat_map_intersegment + : public intersegment_base +{ + typedef flat_map_intersegment self_t; + + void set_from_pointer(const volatile void *ptr) + { this->set_from_pointer((const void *)ptr); } + + //!Obtains the address pointed + //!by the object + void *get_pointer() const + { + if(is_null()){ + return 0; + } + switch(this->get_mode()){ + case is_relative: + return (char*)this + members.relative.off; + break; + case is_segmented: + { + segment_info_t segment_info; + std::size_t offset; + void *this_base; + get_segment_info_and_offset(this, segment_info, offset, this_base); + char *base = (char*)segment_info.group->address_of(this->members.segmented.segment); + return base + this->members.segmented.off; + } + break; + case is_in_stack: + case is_pointee_outside: + return members.direct.addr; + break; + default: + return 0; + break; + } + } + + //!Calculates the distance between two basic_intersegment_ptr-s. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment. Otherwise undefined + std::ptrdiff_t diff(const self_t &other) const + { return (char*)this->get_pointer() - (char*)other.get_pointer(); } + + //!Returns true if both point to + //!the same object + bool equal(const self_t &y) const + { return this->get_pointer() == y.get_pointer(); } + + //!Returns true if *this is less than other. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment group. Otherwise undefined. Never throws + bool less(const self_t &y) const + { return this->get_pointer() < y.get_pointer(); } + + void swap(self_t &other) + { + void *ptr_this = this->get_pointer(); + void *ptr_other = other.get_pointer(); + other.set_from_pointer(ptr_this); + this->set_from_pointer(ptr_other); + } + + //!Sets the object internals to represent the + //!address pointed by ptr + void set_from_pointer(const void *ptr) + { + if(!ptr){ + this->set_null(); + return; + } + + std::size_t mode = this->get_mode(); + if(mode == is_in_stack){ + members.direct.addr = (void*)ptr; + return; + } + if(mode == is_relative){ + char *beg_addr = (char*)this->relative_calculate_begin_addr(); + std::size_t seg_size = this->relative_size(); + if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){ + members.relative.off = (char*)ptr - (char*)this; + return; + } + } + std::size_t ptr_offset; + std::size_t this_offset; + segment_info_t ptr_info; + segment_info_t this_info; + void *ptr_base; + void *this_base; + get_segment_info_and_offset(this, this_info, this_offset, this_base); + + if(!this_info.group){ + this->set_mode(is_in_stack); + this->members.direct.addr = (void*)ptr; + } + else{ + get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base); + + if(ptr_info.group != this_info.group){ + this->set_mode(is_pointee_outside); + this->members.direct.addr = (void*)ptr; + } + else if(ptr_info.id == this_info.id){ + this->set_mode(is_relative); + members.relative.off = ((char*)ptr - (char*)this); + this->relative_set_begin_from_base(this_base); + std::size_t pow, frc; + std::size_t s = calculate_size(this_info.size, pow, frc); + assert(this_info.size == s); + this->members.relative.pow = pow; + this->members.relative.frc = frc; + } + else{ + this->set_mode(is_segmented); + this->members.segmented.segment = ptr_info.id; + this->members.segmented.off = ptr_offset; + } + } + } + + //!Sets the object internals to represent the address pointed + //!by another flat_map_intersegment + void set_from_other(const self_t &other) + { + this->set_from_pointer(other.get_pointer()); + } + + //!Increments internal + //!offset + void inc_offset(std::ptrdiff_t bytes) + { + this->set_from_pointer((char*)this->get_pointer()+bytes); + } + + //!Decrements internal + //!offset + void dec_offset(std::ptrdiff_t bytes) + { + this->set_from_pointer((char*)this->get_pointer()-bytes); + } + + ////////////////////////////////////// + ////////////////////////////////////// + ////////////////////////////////////// + + flat_map_intersegment() + : intersegment_base() + {} + + ~flat_map_intersegment() + {} + + private: + + class segment_group_t + { + struct segment_data + { + void *addr; + std::size_t size; + }; + vector m_segments; + multi_segment_services &m_ms_services; + + public: + segment_group_t(multi_segment_services &ms_services) + : m_ms_services(ms_services) + {} + + void push_back(void *addr, std::size_t size) + { + segment_data d = { addr, size }; + m_segments.push_back(d); + } + + void pop_back() + { + assert(!m_segments.empty()); + m_segments.erase(--m_segments.end()); + } + + + void *address_of(std::size_t segment_id) + { + assert(segment_id < (std::size_t)m_segments.size()); + return m_segments[segment_id].addr; + } + + void clear_segments() + { m_segments.clear(); } + + std::size_t get_size() const + { return m_segments.size(); } + + multi_segment_services &get_multi_segment_services() const + { return m_ms_services; } + + friend bool operator< (const segment_group_t&l, const segment_group_t &r) + { return &l.m_ms_services < &r.m_ms_services; } + }; + + struct segment_info_t + { + std::size_t size; + std::size_t id; + segment_group_t *group; + segment_info_t() + : size(0), id(0), group(0) + {} + }; + + typedef set segment_groups_t; + + typedef boost::interprocess::flat_map + > ptr_to_segment_info_t; + + struct mappings_t : Mutex + { + //!Mutex to preserve integrity in multi-threaded + //!enviroments + typedef Mutex mutex_type; + //!Maps base addresses and segment information + //!(size and segment group and id)* + + ptr_to_segment_info_t m_ptr_to_segment_info; + + ~mappings_t() + { + //Check that all mappings have been erased + assert(m_ptr_to_segment_info.empty()); + } + }; + + //Static members + static mappings_t s_map; + static segment_groups_t s_groups; + public: + + typedef segment_group_t* segment_group_id; + + //!Returns the segment and offset + //!of an address + static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base) + { + //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + base = 0; + if(s_map.m_ptr_to_segment_info.empty()){ + segment = segment_info_t(); + offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + return; + } + //Find the first base address greater than ptr + typename ptr_to_segment_info_t::iterator it + = s_map.m_ptr_to_segment_info.upper_bound(ptr); + if(it == s_map.m_ptr_to_segment_info.begin()){ + segment = segment_info_t(); + offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + } + //Go to the previous one + --it; + char * segment_base = detail::char_ptr_cast(it->first); + std::size_t segment_size = it->second.size; + + if(segment_base <= detail::char_ptr_cast(ptr) && + (segment_base + segment_size) >= detail::char_ptr_cast(ptr)){ + segment = it->second; + offset = detail::char_ptr_cast(ptr) - segment_base; + base = segment_base; + } + else{ + segment = segment_info_t(); + offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + } + } + + //!Associates a segment defined by group/id with a base address and size. + //!Returns false if the group is not found or there is an error + static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size) + { + //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + + typedef typename ptr_to_segment_info_t::value_type value_type; + typedef typename ptr_to_segment_info_t::iterator iterator; + typedef std::pair it_b_t; + + segment_info_t info; + info.group = group_id; + info.size = size; + info.id = group_id->get_size(); + + it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info)); + assert(ret.second); + + value_eraser v_eraser(s_map.m_ptr_to_segment_info, ret.first); + group_id->push_back(ptr, size); + v_eraser.release(); + } + + static bool erase_last_mapping(segment_group_id group_id) + { + //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + if(!group_id->get_size()){ + return false; + } + else{ + void *addr = group_id->address_of(group_id->get_size()-1); + group_id->pop_back(); + std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr); + assert(erased); + return true; + } + } + + static segment_group_id new_segment_group(multi_segment_services *services) + { + { //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + typedef typename segment_groups_t::iterator iterator; + std::pair ret = + s_groups.insert(segment_group_t(*services)); + assert(ret.second); + return &*ret.first; + } + } + + static bool delete_group(segment_group_id id) + { + { //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + bool success = 1u == s_groups.erase(segment_group_t(*id)); + if(success){ + typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it; + ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin()); + while(it != s_map.m_ptr_to_segment_info.end()){ + if(it->second.group == id){ + it = s_map.m_ptr_to_segment_info.erase(it); + } + else{ + ++it; + } + } + } + return success; + } + } +}; + +//!Static map-segment_info associated with +//!flat_map_intersegment<> +template +typename flat_map_intersegment::mappings_t + flat_map_intersegment::s_map; + +//!Static segment group container associated with +//!flat_map_intersegment<> +template +typename flat_map_intersegment::segment_groups_t + flat_map_intersegment::s_groups; + +//!A smart pointer that can point to a pointee that resides in another memory +//!memory mapped or shared memory segment. +template +class intersegment_ptr : public flat_map_intersegment +{ + typedef flat_map_intersegment PT; + typedef intersegment_ptr self_t; + typedef PT base_t; + + void unspecified_bool_type_func() const {} + typedef void (self_t::*unspecified_bool_type)() const; + + public: + typedef T * pointer; + typedef typename detail::add_reference::type reference; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + + public: //Public Functions + + //!Constructor from raw pointer (allows "0" pointer conversion). + //!Never throws. + intersegment_ptr(pointer ptr = 0) + { base_t::set_from_pointer(ptr); } + + //!Constructor from other pointer. + //!Never throws. + template + intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); } + + //!Constructor from other intersegment_ptr + //!Never throws + intersegment_ptr(const intersegment_ptr& ptr) + { base_t::set_from_other(ptr); } + + //!Constructor from other intersegment_ptr. If pointers of pointee types are + //!convertible, intersegment_ptrs will be convertibles. Never throws. + template + intersegment_ptr(const intersegment_ptr &ptr) + { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } + + //!Emulates static_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::static_cast_tag) + { base_t::set_from_pointer(static_cast(r.get())); } +/* + { + if(r.is_null()){ + base_t::set_from_pointer(0); + } + else{ + //Some dirty tricks to safe segment operations. + //Calculate pointer adjustment and adjust offset. + pointer ptr = reinterpret_cast(this); + std::ptrdiff_t difference = detail::char_ptr_cast(static_cast(ptr)) - + detail::char_ptr_cast(ptr); + base_t::set_from_other(r); + base_t::inc_offset(difference*sizeof(T)); + } + }*/ + + //!Emulates const_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::const_cast_tag) + { base_t::set_from_pointer(const_cast(r.get())); } + + //!Emulates dynamic_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::dynamic_cast_tag) + { base_t::set_from_pointer(dynamic_cast(r.get())); } + + //!Emulates reinterpret_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::reinterpret_cast_tag) + { base_t::set_from_pointer(reinterpret_cast(r.get())); } + + //!Obtains raw pointer from offset. + //!Never throws. + pointer get()const + { return (pointer)base_t::get_pointer(); } + + //!Pointer-like -> operator. It can return 0 pointer. + //!Never throws. + pointer operator->() const + { return self_t::get(); } + + //!Dereferencing operator, if it is a null intersegment_ptr behavior + //!is undefined. Never throws. + reference operator* () const + { return *(self_t::get()); } + + //!Indexing operator. + //!Never throws. + reference operator[](std::ptrdiff_t idx) const + { return self_t::get()[idx]; } + + //!Assignment from pointer (saves extra conversion). + //!Never throws. + intersegment_ptr& operator= (pointer from) + { base_t::set_from_pointer(from); return *this; } + + //!Assignment from other intersegment_ptr. + //!Never throws. + intersegment_ptr& operator= (const intersegment_ptr &ptr) + { base_t::set_from_other(ptr); return *this; } + + //!Assignment from related intersegment_ptr. If pointers of pointee types + //!are assignable, intersegment_ptrs will be assignable. Never throws. + template + intersegment_ptr& operator= (const intersegment_ptr & ptr) + { + pointer p(ptr.get()); (void)p; + base_t::set_from_other(ptr); return *this; + } + + //!intersegment_ptr + std::ptrdiff_t. + //!Never throws. + intersegment_ptr operator+ (std::ptrdiff_t idx) const + { + intersegment_ptr result (*this); + result.inc_offset(idx*sizeof(T)); + return result; + } + + //!intersegment_ptr - std::ptrdiff_t. + //!Never throws. + intersegment_ptr operator- (std::ptrdiff_t idx) const + { + intersegment_ptr result (*this); + result.dec_offset(idx*sizeof(T)); + return result; + } + + //!intersegment_ptr += std::ptrdiff_t. + //!Never throws. + intersegment_ptr &operator+= (std::ptrdiff_t offset) + { base_t::inc_offset(offset*sizeof(T)); return *this; } + + //!intersegment_ptr -= std::ptrdiff_t. + //!Never throws. + intersegment_ptr &operator-= (std::ptrdiff_t offset) + { base_t::dec_offset(offset*sizeof(T)); return *this; } + + //!++intersegment_ptr. + //!Never throws. + intersegment_ptr& operator++ (void) + { base_t::inc_offset(sizeof(T)); return *this; } + + //!intersegment_ptr++. + //!Never throws. + intersegment_ptr operator++ (int) + { intersegment_ptr temp(*this); ++*this; return temp; } + + //!--intersegment_ptr. + //!Never throws. + intersegment_ptr& operator-- (void) + { base_t::dec_offset(sizeof(T)); return *this; } + + //!intersegment_ptr--. + //!Never throws. + intersegment_ptr operator-- (int) + { intersegment_ptr temp(*this); --*this; return temp; } + + //!Safe bool conversion operator. + //!Never throws. + operator unspecified_bool_type() const + { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; } + + //!Not operator. Not needed in theory, but improves portability. + //!Never throws. + bool operator! () const + { return base_t::is_null(); } + + //!Swaps two intersegment_ptr-s. More efficient than std::swap. + //!Never throws. + void swap(intersegment_ptr &other) + { base_t::swap(other); } + + //!Calculates the distance between two intersegment_ptr-s. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment. Otherwise undefined + template + ptrdiff_t _diff(const intersegment_ptr &other) const + { return base_t::diff(other); } + + //!Returns true if both point to the + //!same object + template + bool _equal(const intersegment_ptr&other) const + { return base_t::equal(other); } + + //!Returns true if *this is less than other. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment group. Otherwise undefined. Never throws + template + bool _less(const intersegment_ptr &other) const + { return base_t::less(other); } +}; + +//!Compares the equality of two intersegment_ptr-s. +//!Never throws. +template inline +bool operator ==(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) == + typename intersegment_ptr::pointer(0); + (void)e; + return left._equal(right); +} + +//!Returns true if *this is less than other. +//!This only works with two basic_intersegment_ptr pointing +//!to the same segment group. Otherwise undefined. Never throws +template inline +bool operator <(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) < + typename intersegment_ptr::pointer(0); + (void)e; + return left._less(right); +} + +template inline +bool operator!= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 ==pt2); } + +//!intersegment_ptr <= intersegment_ptr. +//!Never throws. +template inline +bool operator<= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 > pt2); } + +//!intersegment_ptr > intersegment_ptr. +//!Never throws. +template inline +bool operator> (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return (pt2 < pt1); } + +//!intersegment_ptr >= intersegment_ptr. +//!Never throws. +template inline +bool operator>= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 < pt2); } + +//!operator<< +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, const intersegment_ptr & p) +{ return os << p.get(); } + +//!operator>> +template inline +std::basic_istream & operator>> + (std::basic_istream & os, intersegment_ptr & p) +{ U * tmp; return os >> tmp; p = tmp; } + +//!std::ptrdiff_t + intersegment_ptr. +//!The result is another pointer of the same segment +template inline +intersegment_ptr operator+ + (std::ptrdiff_t diff, const intersegment_ptr& right) +{ return right + diff; } + +//!intersegment_ptr - intersegment_ptr. +//!This only works with two intersegment_ptr-s that point to the +//!same segment +template inline +std::ptrdiff_t operator- (const intersegment_ptr &pt, + const intersegment_ptr &pt2) +{ return pt._diff(pt2)/sizeof(T); } + +//! swap specialization +template inline +void swap (boost::interprocess::intersegment_ptr &pt, + boost::interprocess::intersegment_ptr &pt2) +{ pt.swap(pt2); } + +//!get_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!Never throws. +template inline +T * get_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } + +//!Simulation of static_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr static_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::static_cast_tag()); } + +//!Simulation of const_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr const_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::const_cast_tag()); } + +//!Simulation of dynamic_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr dynamic_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::dynamic_cast_tag()); } + +//!Simulation of reinterpret_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::reinterpret_cast_tag()); } + +//!Trait class to detect if an smart pointer has +//!multi-segment addressing capabilities. +template +struct is_multisegment_ptr + > +{ + static const bool value = true; +}; + +} //namespace interprocess { + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +//!get_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!Never throws. +template inline +T * get_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } +#endif + +//!has_trivial_constructor<> == true_type specialization +//!for optimizations +template +struct has_trivial_constructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +//!has_trivial_destructor<> == true_type specialization +//!for optimizations +template +struct has_trivial_destructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +} //namespace boost { + +#include + +#if 0 + +//bits +//-> is_segmented +//-> is_relative +//-> is_in_stack +//-> is_pointee_outside + +//Data + + + + +//segmented: +// +// std::size_t ctrl : CTRL_BITS; +// std::size_t segment : MAX_SEGMENT_BITS; +// std::size_t offset; + +//RELATIVE_SIZE_BITS = SIZE_T_BITS - +// MAX_SEGMENT_BITS - +// CTRL_BITS 10 10 +//MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52 + +//SIZE_T_BITS - 1 - ALIGN_BITS 19 51 +//POW_SIZE_BITS = upper_log2 +// (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6 +//FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS +// MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5 + +//relative: +// +// std::size_t ctrl : CTRL_BITS; 2 2 +// std::size_t size_pow : POW_SIZE_BITS 5 6 +// std::size_t size_frc : FRC_SIZE_BITS; 6 5 +// std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51 +// std::ptrdiff_t distance : SIZE_T_BITS; 32 64 + +//direct: +// +// std::size_t ctrl : CTRL_BITS; 2 2 +// std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62 +// void *addr : SIZE_T_BITS; 32 64 + +//32 bits systems: +//Page alignment: 2**12 +// + +//!Obtains the address pointed by the +//!object +void *get_pointer() const +{ + if(this->is_pointee_outside() || this->is_in_stack()){ + return raw_address(); + } + else if(this->is_relative()){ + return ((char*)this) + this->relative_pointee_offset(); + } + else{ + group_manager *m = get_segment_group_manager(addr); + char *base = (char*)m->get_id_address(this->segmented_id()); + return base + this->segmented_offset(); + } +} + +void set_from_pointer(const void *ptr) +{ + if(!ptr){ + this->set_pointee_outside(); + this->raw_address(ptr); + } + else if(this->is_in_stack()){ + this->raw_address(ptr); + } + else if(this->is_relative() && + ( (ptr >= this->relative_start()) + &&(ptr < this->relative_start() + this->relative_size())) + ){ + this->relative_offset(ptr - this); + } + else{ + segment_info_t ptr_info = get_id_from_addr(ptr); + segment_info_t this_info = get_id_from_addr(this); + if(ptr_info.segment_group != this_info.segment_group){ + if(!ptr_info.segment_group){ + this->set_in_stack(); + } + else{ + this->set_pointee_outside(); + } + } + else if(ptr_info.segment_id == this_info.segment_id){ + set_relative(); + this->relative_size (ptr_info.size); + this->relative_offset((char*)ptr - (char*)this); + this->relative_start (ptr_info.base); + } + } +} + +void set_from_other(const self_t &other) +{ this->set_from_pointer(other.get_pointer()); } + +#endif + +#endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP + diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index c659d9d..fee200e 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -94,6 +94,8 @@ class basic_managed_memory_impl /// @cond + typedef typename + segment_manager::char_ptr_holder_t char_ptr_holder_t; //Experimental. Don't use. typedef typename segment_manager::multiallocation_iterator multiallocation_iterator; @@ -105,9 +107,6 @@ class basic_managed_memory_impl private: typedef basic_managed_memory_impl self_t; - typedef typename - segment_manager::char_ptr_holder_t char_ptr_holder_t; - protected: template static bool grow(const char *filename, std::size_t extra_bytes) @@ -687,6 +686,15 @@ class basic_managed_memory_impl get_deleter() { return mp_header->get_deleter(); } + /// @cond + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find_no_lock (char_ptr_holder_t name) + { return mp_header->template find_no_lock(name); } + /// @endcond + protected: //!Swaps the segment manager's managed by this managed memory segment. //!NOT thread-safe. Never throws. diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp new file mode 100644 index 0000000..03aaa85 --- /dev/null +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -0,0 +1,389 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include //list +#include //mapped_region +#include +#include //managed_open_or_create_impl +#include +#include +#include +#include + +//!\file +//!Describes a named shared memory object allocation user class. + +namespace boost { + +namespace interprocess { + +//!A basic shared memory named object creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl +template + < + class CharType, + class MemoryAlgorithm, + template class IndexType + > +class basic_managed_multi_shared_memory + : public detail::basic_managed_memory_impl + +{ + + typedef basic_managed_multi_shared_memory + self_t; + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename detail:: + managed_open_or_create_impl managed_impl; + typedef typename void_pointer::segment_group_id segment_group_id; + //////////////////////////////////////////////////////////////////////// + // + // Some internal helper structs/functors + // + //////////////////////////////////////////////////////////////////////// + //!This class defines an operator() that creates a shared memory + //!of the requested size. The rest of the parameters are + //!passed in the constructor. The class a template parameter + //!to be used with create_from_file/create_from_istream functions + //!of basic_named_object classes + +// class segment_creator +// { +// public: +// segment_creator(shared_memory &shmem, +// const char *mem_name, +// const void *addr) +// : m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){} +// +// void *operator()(std::size_t size) +// { +// if(!m_shmem.create(m_mem_name, size, m_addr)) +// return 0; +// return m_shmem.get_address(); +// } +// private: +// shared_memory &m_shmem; +// const char *m_mem_name; +// const void *m_addr; +// }; + + class group_services + : public multi_segment_services + { + public: + typedef std::pair result_type; + typedef basic_managed_multi_shared_memory frontend_t; + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + typedef typename void_pointer::segment_group_id segment_group_id; + group_services(frontend_t *const frontend) + : mp_frontend(frontend), m_group(0), m_min_segment_size(0){} + + virtual std::pair create_new_segment(std::size_t alloc_size) + { + //We should allocate an extra byte so that the + //[base_addr + alloc_size] byte belongs to this segment + alloc_size += 1; + + //If requested size is less than minimum, update that + alloc_size = (m_min_segment_size > alloc_size) ? + m_min_segment_size : alloc_size; + if(mp_frontend->priv_new_segment(create_open_func::DoCreate, + alloc_size, 0)){ + shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin(); + return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1); + } + return result_type((void *)0, 0); + } + + virtual bool update_segments () + { return true; } + + virtual ~group_services(){} + + void set_group(segment_group_id group) + { m_group = group; } + + segment_group_id get_group() const + { return m_group; } + + void set_min_segment_size(std::size_t min_segment_size) + { m_min_segment_size = min_segment_size; } + + std::size_t get_min_segment_size() const + { return m_min_segment_size; } + + private: + + frontend_t * const mp_frontend; + segment_group_id m_group; + std::size_t m_min_segment_size; + }; + + //!Functor to execute atomically when opening or creating a shared memory + //!segment. + struct create_open_func + { + enum type_t { DoCreate, DoOpen, DoOpenOrCreate }; + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + create_open_func(self_t * const frontend, + type_t type, std::size_t segment_number) + : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){} + + bool operator()(void *addr, std::size_t size, bool created) const + { + if(((m_type == DoOpen) && created) || + ((m_type == DoCreate) && !created)) + return false; + segment_group_id group = mp_frontend->m_group_services.get_group(); + bool mapped = false; + bool impl_done = false; + + //Associate this newly created segment as the + //segment id = 0 of this group + void_pointer::insert_mapping + ( group + , (char*)addr - managed_impl::ManagedOpenOrCreateUserOffset + , size + managed_impl::ManagedOpenOrCreateUserOffset); + //Check if this is the master segment + if(!m_segment_number){ + //Create or open the Interprocess machinery + if((impl_done = created ? + mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){ + return true; + } + } + else{ + return true; + } + + //This is the cleanup part + //--------------- + if(impl_done){ + mp_frontend->close_impl(); + } + if(mapped){ + bool ret = void_pointer::erase_last_mapping(group); + assert(ret);(void)ret; + } + return false; + } + self_t * const mp_frontend; + type_t m_type; + std::size_t m_segment_number; + }; + + //!Functor to execute atomically when closing a shared memory segment. + struct close_func + { + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + close_func(self_t * const frontend) + : mp_frontend(frontend){} + + void operator()(const mapped_region ®ion, bool last) const + { + if(last) mp_frontend->destroy_impl(); + else mp_frontend->close_impl(); + } + self_t * const mp_frontend; + }; + + typedef detail::basic_managed_memory_impl + base_t; + + //Friend declarations + friend struct basic_managed_multi_shared_memory::create_open_func; + friend struct basic_managed_multi_shared_memory::close_func; + friend class basic_managed_multi_shared_memory::group_services; + + typedef list shmem_list_t; + + basic_managed_multi_shared_memory *get_this_pointer() + { return this; } + + public: + + basic_managed_multi_shared_memory(create_only_t, + const char *name, + std::size_t size) + : m_group_services(get_this_pointer()) + { + priv_open_or_create(create_open_func::DoCreate,name, size); + } + + basic_managed_multi_shared_memory(open_or_create_t, + const char *name, + std::size_t size) + : m_group_services(get_this_pointer()) + { + priv_open_or_create(create_open_func::DoOpenOrCreate, name, size); + } + + basic_managed_multi_shared_memory(open_only_t, const char *name) + : m_group_services(get_this_pointer()) + { + priv_open_or_create(create_open_func::DoOpen, name, 0); + } + + ~basic_managed_multi_shared_memory() + { this->priv_close(); } + + private: + bool priv_open_or_create(typename create_open_func::type_t type, + const char *name, + std::size_t size) + { + if(!m_shmem_list.empty()) + return false; + typename void_pointer::segment_group_id group = 0; + BOOST_TRY{ + m_root_name = name; + //Insert multi segment services and get a group identifier + group = void_pointer::new_segment_group(&m_group_services); + size = void_pointer::round_size(size); + m_group_services.set_group(group); + m_group_services.set_min_segment_size(size); + + if(group){ + if(this->priv_new_segment(type, size, 0)){ + return true; + } + } + } + BOOST_CATCH(const std::bad_alloc&){ + } + BOOST_CATCH_END + if(group){ + void_pointer::delete_group(group); + } + return false; + } + + bool priv_new_segment(typename create_open_func::type_t type, + std::size_t size, + const void *addr) + { + BOOST_TRY{ + //Get the number of groups of this multi_segment group + std::size_t segment_id = m_shmem_list.size(); + //Format the name of the shared memory: append segment number. + boost::interprocess::basic_ovectorstream formatter; + //Pre-reserve string size + std::size_t str_size = m_root_name.length()+10; + if(formatter.vector().size() < str_size){ + //This can throw. + formatter.reserve(str_size); + } + //Format segment's name + formatter << m_root_name + << static_cast(segment_id) << std::ends; + //This functor will be executed when constructing + create_open_func func(this, type, segment_id); + const char *name = formatter.vector().c_str(); + //This can throw. + managed_impl mshm; + + switch(type){ + case create_open_func::DoCreate: + { + managed_impl shm(create_only, name, size, read_write, addr, func); + mshm = detail::move_impl(shm); + } + break; + + case create_open_func::DoOpen: + { + managed_impl shm(open_only, name,read_write, addr, func); + mshm = detail::move_impl(shm); + } + break; + + case create_open_func::DoOpenOrCreate: + { + managed_impl shm(open_or_create, name, size, read_write, addr, func); + mshm = detail::move_impl(shm); + } + break; + + default: + return false; + break; + } + + //This can throw. + m_shmem_list.push_back(detail::move_impl(mshm)); + return true; + } + BOOST_CATCH(const std::bad_alloc&){ + } + BOOST_CATCH_END + return false; + } + + //!Frees resources. Never throws. + void priv_close() + { + if(!m_shmem_list.empty()){ + bool ret; + //Obtain group identifier + segment_group_id group = m_group_services.get_group(); + //Erase main segment and its resources + shmem_list_t::iterator itbeg = m_shmem_list.begin(), + itend = m_shmem_list.end(), + it = itbeg; + //(*itbeg)->close_with_func(close_func(this)); + //Delete group. All mappings are erased too. + ret = void_pointer::delete_group(group); + assert(ret); + m_shmem_list.clear(); + } + } + + private: + shmem_list_t m_shmem_list; + group_services m_group_services; + std::string m_root_name; +}; + +typedef basic_managed_multi_shared_memory + < char + , rbtree_best_fit > + , iset_index> + managed_multi_shared_memory; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index 068223e..2f498b4 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace boost { @@ -36,7 +37,6 @@ template class managed_open_or_create_impl { //Non-copyable - managed_open_or_create_impl(); managed_open_or_create_impl(const managed_open_or_create_impl &); managed_open_or_create_impl &operator=(const managed_open_or_create_impl &); @@ -56,6 +56,9 @@ class managed_open_or_create_impl < sizeof(boost::uint32_t) , detail::alignment_of::value>::value; + managed_open_or_create_impl() + {} + managed_open_or_create_impl(create_only_t, const char *name, std::size_t size, @@ -151,29 +154,29 @@ class managed_open_or_create_impl , construct_func); } + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl - (detail::moved_object &moved) + managed_open_or_create_impl(detail::moved_object moved) { this->swap(moved.get()); } #else - managed_open_or_create_impl - (managed_open_or_create_impl &&moved) + managed_open_or_create_impl(managed_open_or_create_impl &&moved) { this->swap(moved); } #endif + //!Move assignment. If *this owns a memory mapped region, it will be + //!destroyed and it will take ownership of "other"'s memory mapped region. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl &operator= - (detail::moved_object &moved) + managed_open_or_create_impl &operator=(detail::moved_object moved) { managed_open_or_create_impl tmp(moved); this->swap(tmp); return *this; } + #else - managed_open_or_create_impl &operator= - (managed_open_or_create_impl &&moved) + managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved) { - managed_open_or_create_impl tmp(move(moved)); + managed_open_or_create_impl tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -206,6 +209,10 @@ class managed_open_or_create_impl bool flush() { return m_mapped_region.flush(); } + + const mapped_region &get_mapped_region() const + { return m_mapped_region; } + private: //These are templatized to allow explicit instantiations @@ -276,17 +283,31 @@ class managed_open_or_create_impl (void)mode; error_info err; bool created = false; + bool ronly = false; + bool cow = false; DeviceAbstraction dev; if(type != detail::DoOpen && size < ManagedOpenOrCreateUserOffset){ throw interprocess_exception(error_info(size_error)); } - if(type == detail::DoOpen){ + if(type == detail::DoOpen && mode == read_write){ DeviceAbstraction tmp(open_only, m_name.c_str(), read_write); tmp.swap(dev); created = false; } + else if(type == detail::DoOpen && mode == read_only){ + DeviceAbstraction tmp(open_only, m_name.c_str(), read_only); + tmp.swap(dev); + created = false; + ronly = true; + } + else if(type == detail::DoOpen && mode == copy_on_write){ + DeviceAbstraction tmp(open_only, m_name.c_str(), read_only); + tmp.swap(dev); + created = false; + cow = true; + } else if(type == detail::DoCreate){ create_device(dev, m_name.c_str(), size, file_like_t()); created = true; @@ -379,7 +400,7 @@ class managed_open_or_create_impl } } - mapped_region region(dev, read_write, 0, 0, addr); + mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr); boost::uint32_t *patomic_word = static_cast(region.get_address()); boost::uint32_t value = detail::atomic_read32(patomic_word); @@ -392,7 +413,9 @@ class managed_open_or_create_impl if(value != InitializedSegment) throw interprocess_exception(error_info(corrupted_error)); - construct_func((char*)region.get_address() + ManagedOpenOrCreateUserOffset, region.get_size(), false); + construct_func( (char*)region.get_address() + ManagedOpenOrCreateUserOffset + , region.get_size() - ManagedOpenOrCreateUserOffset + , false); //All ok, just move resources to the external mapped region m_mapped_region.swap(region); } @@ -413,6 +436,21 @@ inline void swap(managed_open_or_create_impl &x { x.swap(y); } } //namespace detail { + + +///@cond + +//!Trait class to detect if a type is +//!movable +template + +struct is_movable > +{ + enum { value = true }; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 362b1cd..7094b78 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -16,6 +16,9 @@ #ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP #define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP +#include +#include + namespace boost { namespace interprocess { namespace detail { @@ -80,6 +83,26 @@ inline Integer upper_power_of_2(const Integer & A) return power_of_2; } +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true)); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + } // namespace detail } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index aab0455..6159df9 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include //!\file //!Describes a function and a type to emulate move semantics. @@ -79,7 +81,7 @@ class move_return public: typedef T type; - move_return(T& returned) + move_return(const T& returned) : m_moved(moved_object(returned)) {} @@ -106,16 +108,25 @@ struct return_type namespace boost { namespace interprocess { +namespace detail{ + //!A function that converts an object to a moved object so that //!it can match a function taking a detail::moved_object object. template -typename detail::move_type::type move - (const Object &object) +typename detail::move_type::type move_impl(const Object &object) { typedef typename detail::move_type::type type; return type(object); } +} //namespace detail { + +//!A function that converts an object to a moved object so that +//!it can match a function taking a detail::moved_object object. +template +typename detail::move_type::type move(const Object &object) +{ return detail::move_impl(object); } + } //namespace interprocess { } //namespace boost { @@ -126,15 +137,20 @@ typename detail::move_type::type move namespace boost { namespace interprocess { +namespace detail { + template -inline typename detail::remove_reference::type&& -move(T&& t) +inline typename detail::remove_reference::type&& move_impl(T&& t) { return t; } template -inline -T&& -forward(typename identity::type&& t) +inline T&& forward_impl(typename detail::identity::type&& t) +{ return t; } + +} //namespace detail { + +template +inline typename detail::remove_reference::type&& move(T&& t) { return t; } } //namespace interprocess { diff --git a/include/boost/interprocess/detail/move_iterator.hpp b/include/boost/interprocess/detail/move_iterator.hpp index 83af256..4c9f282 100644 --- a/include/boost/interprocess/detail/move_iterator.hpp +++ b/include/boost/interprocess/detail/move_iterator.hpp @@ -53,7 +53,7 @@ class move_iterator reference operator*() const #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - { return move(*m_it); } + { return detail::move_impl(*m_it); } #else { return *m_it; } #endif @@ -86,7 +86,7 @@ class move_iterator { m_it -= n; return *this; } reference operator[](difference_type n) const - { return move(m_it[n]); } + { return detail::move_impl(m_it[n]); } private: It m_it; diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index 0ae2392..dfdd38c 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -17,7 +17,7 @@ # pragma once #endif -//#include +#include namespace boost { namespace interprocess { @@ -117,10 +117,29 @@ template struct identity // : public std::unary_function { + typedef T type; const T& operator()(const T& x) const { return x; } }; +template +struct ls_zeros +{ + static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value); +}; + +template<> +struct ls_zeros<0> +{ + static const std::size_t value = 0; +}; + +template<> +struct ls_zeros<1> +{ + static const std::size_t value = 0; +}; + } //namespace detail { } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/multi_segment_services.hpp b/include/boost/interprocess/detail/multi_segment_services.hpp new file mode 100644 index 0000000..ac50b33 --- /dev/null +++ b/include/boost/interprocess/detail/multi_segment_services.hpp @@ -0,0 +1,46 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP +#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + + +/*!\file + Describes a named shared memory allocation user class. +*/ + +namespace boost { + +namespace interprocess { + +class multi_segment_services +{ + public: + virtual std::pair create_new_segment(std::size_t mem) = 0; + virtual bool update_segments () = 0; + virtual ~multi_segment_services() = 0; +}; + +inline multi_segment_services::~multi_segment_services() +{} + + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index 98a28ee..be6ee84 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -48,13 +48,13 @@ struct Ctor0Arg : public placement_destroy self_t operator++(int) { return *this; } void construct(void *mem) - { new(mem)T; } + { new((void*)mem)T; } virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) { - T* memory = static_cast(mem); + T* memory = (T*)(mem); for(constructed = 0; constructed < num; ++constructed) - new(memory++)T; + new((void*)memory++)T; } }; @@ -88,13 +88,13 @@ struct Ctor0Arg : public placement_destroy // : p1((P1 &)p_1), p2((P2 &)p_2) {} // // void construct(void *mem) -// { new(object)T(m_p1, m_p2); } +// { new((void*)object)T(m_p1, m_p2); } // // virtual void construct_n(void *mem // , std::size_t num // , std::size_t &constructed) // { -// T* memory = static_cast(mem); +// T* memory = (T*)(mem); // for(constructed = 0; constructed < num; ++constructed){ // this->construct(memory++, IsIterator()); // this->do_increment(IsIterator()); @@ -103,10 +103,10 @@ struct Ctor0Arg : public placement_destroy // // private: // void construct(void *mem, detail::true_) -// { new(mem)T(*m_p1, *m_p2); } +// { new((void*)mem)T(*m_p1, *m_p2); } // // void construct(void *mem, detail::false_) -// { new(mem)T(m_p1, m_p2); } +// { new((void*)mem)T(m_p1, m_p2); } // // P1 &m_p1; P2 &m_p2; // }; @@ -163,7 +163,7 @@ struct Ctor0Arg : public placement_destroy , std::size_t num \ , std::size_t &constructed) \ { \ - T* memory = static_cast(mem); \ + T* memory = (T*)(mem); \ for(constructed = 0; constructed < num; ++constructed){ \ this->construct(memory++, IsIterator()); \ this->do_increment(IsIterator()); \ @@ -172,10 +172,10 @@ struct Ctor0Arg : public placement_destroy \ private: \ void construct(void *mem, detail::true_) \ - { new(mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ + { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ \ void construct(void *mem, detail::false_) \ - { new(mem)T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \ + { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \ \ BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ }; \ diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 58bbb56..08a6e79 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -215,24 +215,6 @@ inline void array_construct(void *mem, std::size_t num, detail::in_place_interfa BOOST_CATCH_END } -//Anti-exception node eraser -template -class value_eraser -{ - public: - value_eraser(Cont & cont, typename Cont::iterator it) - : m_cont(cont), m_index_it(it), m_erase(true){} - ~value_eraser() - { if(m_erase) m_cont.erase(m_index_it); } - - void release() { m_erase = false; } - - private: - Cont &m_cont; - typename Cont::iterator m_index_it; - bool m_erase; -}; - template struct intrusive_compare_key { diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index 7cb2eef..f4043de 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -373,11 +373,24 @@ inline std::size_t get_rounded_size(std::size_t orig_size, std::size_t round_to) return ((orig_size-1)/round_to+1)*round_to; } +//Truncates "orig_size" to a multiple of "multiple" bytes. inline std::size_t get_truncated_size(std::size_t orig_size, std::size_t multiple) { return orig_size/multiple*multiple; } - + +//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two +inline std::size_t get_rounded_size_po2(std::size_t orig_size, std::size_t round_to) +{ + return ((orig_size-1)&(~(round_to-1))) + round_to; +} + +//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two +inline std::size_t get_truncated_size_po2(std::size_t orig_size, std::size_t multiple) +{ + return (orig_size & (~(multiple-1))); +} + template struct ct_rounded_size { @@ -513,61 +526,61 @@ struct pair #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object >& p) - : first(move(p.get().first)), second(move(p.get().second)) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else template pair(std::pair && p) - : first(move(p.first)), second(move(p.second)) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object >& p) - : first(move(p.get().first)), second(move(p.get().second)) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else template pair(pair && p) - : first(move(p.first)), second(move(p.second)) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object &x, const detail::moved_object &y) - : first(move(x.get())), second(move(y.get())) + : first(detail::move_impl(x.get())), second(detail::move_impl(y.get())) {} #else template pair(U &&x, V &&y) - : first(move(x)), second(move(y)) + : first(detail::move_impl(x)), second(detail::move_impl(y)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE pair(const detail::moved_object &p) - : first(move(p.get().first)), second(move(p.get().second)) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else pair(pair &&p) - : first(move(p.first)), second(move(p.second)) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE pair& operator=(const detail::moved_object &p) { - first = move(p.get().first); - second = move(p.get().second); + first = detail::move_impl(p.get().first); + second = detail::move_impl(p.get().second); return *this; } #else pair& operator=(pair &&p) { - first = move(p.first); - second = move(p.second); + first = detail::move_impl(p.first); + second = detail::move_impl(p.second); return *this; } #endif @@ -583,16 +596,16 @@ struct pair template pair& operator=(const detail::moved_object > &p) { - first = move(p.get().first); - second = move(p.get().second); + first = detail::move_impl(p.get().first); + second = detail::move_impl(p.get().second); return *this; } #else template pair& operator=(std::pair &&p) { - first = move(p.first); - second = move(p.second); + first = detail::move_impl(p.first); + second = detail::move_impl(p.second); return *this; } #endif @@ -754,6 +767,54 @@ addressof(T& v) &const_cast(reinterpret_cast(v))); } +//Anti-exception node eraser +template +class value_eraser +{ + public: + value_eraser(Cont & cont, typename Cont::iterator it) + : m_cont(cont), m_index_it(it), m_erase(true){} + ~value_eraser() + { if(m_erase) m_cont.erase(m_index_it); } + + void release() { m_erase = false; } + + private: + Cont &m_cont; + typename Cont::iterator m_index_it; + bool m_erase; +}; + +template +struct sizeof_value +{ + static const std::size_t value = sizeof(T); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index b6771d0..b07910d 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -225,7 +225,7 @@ extern "C" __declspec(dllimport) void * __stdcall OpenSemaphoreA(unsigned long, extern "C" __declspec(dllimport) void * __stdcall CreateFileMappingA (void *, interprocess_security_attributes*, unsigned long, unsigned long, unsigned long, const char *); extern "C" __declspec(dllimport) void * __stdcall MapViewOfFileEx (void *, unsigned long, unsigned long, unsigned long, std::size_t, void*); extern "C" __declspec(dllimport) void * __stdcall OpenFileMappingA (unsigned long, int, const char *); -extern "C" __declspec(dllimport) void * __stdcall CreateFileA (const char *, unsigned long, unsigned long, struct _SECURITY_ATTRIBUTES*, unsigned long, unsigned long, void *); +extern "C" __declspec(dllimport) void * __stdcall CreateFileA (const char *, unsigned long, unsigned long, struct interprocess_security_attributes*, unsigned long, unsigned long, void *); extern "C" __declspec(dllimport) int __stdcall DeleteFileA (const char *); extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *); extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t); diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index b22e283..9e4f3fa 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -13,6 +13,8 @@ #include +#undef BOOST_DISABLE_WIN32 + #if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) #include @@ -105,8 +107,11 @@ // defined by some very early development versions of GCC 4.3; we will // remove this part of the check in the near future. # if defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(__GXX_EXPERIMENTAL_CXX0X__) -# define BOOST_INTERPROCESS_RVALUE_REFERENCE -# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES +# define BOOST_INTERPROCESS_RVALUE_REFERENCE +# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES +# if defined(__GLIBCPP__) || defined(__GLIBCXX__) +# define BOOST_INTERPROCESS_RVALUE_PAIR +# endif # endif #endif diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index 1374c8e..ecf3698 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -10,8 +10,8 @@ // ////////////////////////////////////////////////////////////////////////////// // -// Copyright © 2002 Beman Dawes -// Copyright © 2001 Dietmar Kühl +// Copyright (C) 2002 Beman Dawes +// Copyright (C) 2001 Dietmar Kuehl // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index a55ff03..acab048 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include //std::string #include //std::remove #include @@ -55,10 +56,12 @@ class file_mapping //!After the call, "moved" does not represent any shared memory object. //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_mapping(detail::moved_object &moved) + file_mapping(detail::moved_object moved) + : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved.get()); } #else file_mapping(file_mapping &&moved) + : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } #endif @@ -67,7 +70,7 @@ class file_mapping //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE file_mapping &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { file_mapping tmp(moved); this->swap(tmp); @@ -76,7 +79,7 @@ class file_mapping #else file_mapping &operator=(file_mapping &&moved) { - file_mapping tmp(move(moved)); + file_mapping tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -157,6 +160,8 @@ inline file_mapping::file_mapping m_mode = mode; } +///@cond + inline void file_mapping::priv_close() { if(m_handle != detail::invalid_file()){ @@ -165,6 +170,33 @@ inline void file_mapping::priv_close() } } + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; + +///@endcond + +//!A class that stores the name of a a file +//!and call std::remove(name) in its destructor +//!Useful to remove temporary files in the presence +//!of exceptions +class remove_file_on_destroy +{ + const char * m_name; + public: + remove_file_on_destroy(const char *name) + : m_name(name) + {} + + ~remove_file_on_destroy() + { std::remove(m_name); } +}; + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/indexes/map_index.hpp b/include/boost/interprocess/indexes/map_index.hpp index 024c647..78974af 100644 --- a/include/boost/interprocess/indexes/map_index.hpp +++ b/include/boost/interprocess/indexes/map_index.hpp @@ -77,7 +77,7 @@ class map_index //!This tries to free previously allocate //!unused memory. void shrink_to_fit() - { base_type::get_stored_allocator().deallocate_free_chunks(); } + { base_type::get_stored_allocator().deallocate_free_blocks(); } }; /// @cond diff --git a/include/boost/interprocess/indexes/unordered_map_index.hpp b/include/boost/interprocess/indexes/unordered_map_index.hpp index 8c2f670..7c91148 100644 --- a/include/boost/interprocess/indexes/unordered_map_index.hpp +++ b/include/boost/interprocess/indexes/unordered_map_index.hpp @@ -27,6 +27,8 @@ namespace boost { namespace interprocess { +///@cond + //!Helper class to define typedefs from //!IndexTraits template @@ -55,6 +57,8 @@ struct unordered_map_index_aux key_equal, allocator_type> index_t; }; +///@endcond + //!Index type based in unordered_map. Just derives from unordered_map and //!defines the interface needed by managed memory segments template diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index acb1b3e..0681782 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -120,26 +120,26 @@ class sharable_lock; template class allocator; -template +template class node_allocator; -template +template class private_node_allocator; -template +template class cached_node_allocator; -template class adaptive_pool; -template class private_adaptive_pool; -template class cached_adaptive_pool; diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index b28ba68..757a367 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -98,7 +98,7 @@ class message_queue //!Sends a message stored in buffer "buffer" with size "buffer_size" in the //!message queue with priority "priority". If the message queue is full - //!the sender is retries until time "abs_time" is reached. Returns true if + //!the sender retries until time "abs_time" is reached. Returns true if //!the message has been successfully sent. Returns false if timeout is reached. //!Throws interprocess_error on error. bool timed_send (const void *buffer, std::size_t buffer_size, @@ -106,23 +106,23 @@ class message_queue //!Receives a message from the message queue. The message is stored in buffer //!"buffer", which has size "buffer_size". The received message has size - //!"recvd_size" and priority "priority". If the message queue is full - //!the sender is blocked. Throws interprocess_error on error. + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver is blocked. Throws interprocess_error on error. void receive (void *buffer, std::size_t buffer_size, std::size_t &recvd_size,unsigned int &priority); //!Receives a message from the message queue. The message is stored in buffer //!"buffer", which has size "buffer_size". The received message has size - //!"recvd_size" and priority "priority". If the message queue is full - //!the sender is not blocked and returns false, otherwise returns true. + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver is not blocked and returns false, otherwise returns true. //!Throws interprocess_error on error. bool try_receive (void *buffer, std::size_t buffer_size, std::size_t &recvd_size,unsigned int &priority); //!Receives a message from the message queue. The message is stored in buffer //!"buffer", which has size "buffer_size". The received message has size - //!"recvd_size" and priority "priority". If the message queue is full - //!the sender is retries until time "abs_time" is reached. Returns true if + //!"recvd_size" and priority "priority". If the message queue is empty + //!the receiver retries until time "abs_time" is reached. Returns true if //!the message has been successfully sent. Returns false if timeout is reached. //!Throws interprocess_error on error. bool timed_receive (void *buffer, std::size_t buffer_size, @@ -368,7 +368,6 @@ class initialization_func_t }; } //namespace detail { -/// @endcond inline message_queue::~message_queue() {} @@ -611,6 +610,8 @@ inline std::size_t message_queue::get_num_msg() inline bool message_queue::remove(const char *name) { return shared_memory_object::remove(name); } +/// @endcond + }} //namespace boost{ namespace interprocess{ #include diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index be18e4d..8faea6d 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -46,6 +46,12 @@ class basic_managed_external_buffer /// @endcond public: + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_external_buffer() + {} + //!Creates and places the segment manager. This can throw basic_managed_external_buffer (create_only_t, void *addr, std::size_t size) @@ -71,7 +77,7 @@ class basic_managed_external_buffer //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_external_buffer - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_external_buffer @@ -82,7 +88,7 @@ class basic_managed_external_buffer //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_external_buffer &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_external_buffer &operator= @@ -100,6 +106,26 @@ class basic_managed_external_buffer }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp index 36e97bd..4ed9869 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -50,7 +50,8 @@ class basic_managed_heap_memory public: //functions - //!Constructor. Never throws. + //!Default constructor. Does nothing. + //!Useful in combination with move semantics basic_managed_heap_memory(){} //!Destructor. Liberates the heap memory holding the managed data. @@ -72,7 +73,7 @@ class basic_managed_heap_memory //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_heap_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_heap_memory(basic_managed_heap_memory &&moved) @@ -82,7 +83,7 @@ class basic_managed_heap_memory //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_heap_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_heap_memory &operator= @@ -139,6 +140,25 @@ class basic_managed_heap_memory /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index cdd6267..be3a15a 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -22,15 +22,13 @@ #include #include #include - -//!\file -//!Describes a named shared memory object allocation user class. +#include namespace boost { namespace interprocess { -//!A basic shared memory named object creation class. Initializes the -//!shared memory segment. Inherits all basic functionality from +//!A basic mapped file named object creation class. Initializes the +//!mapped file. Inherits all basic functionality from //!basic_managed_memory_impl template < @@ -57,11 +55,19 @@ class basic_managed_mapped_file basic_managed_mapped_file *get_this_pointer() { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; /// @endcond public: //functions - //!Creates shared memory and creates and places the segment manager. + //!Creates mapped file and creates and places the segment manager. + //!This can throw. + basic_managed_mapped_file() + {} + + //!Creates mapped file and creates and places the segment manager. //!This can throw. basic_managed_mapped_file(create_only_t create_only, const char *name, std::size_t size, const void *addr = 0) @@ -69,7 +75,7 @@ class basic_managed_mapped_file create_open_func_t(get_this_pointer(), detail::DoCreate)) {} - //!Creates shared memory and creates and places the segment manager if + //!Creates mapped file and creates and places the segment manager if //!segment was not created. If segment was created it connects to the //!segment. //!This can throw. @@ -81,8 +87,8 @@ class basic_managed_mapped_file detail::DoOpenOrCreate)) {} - //!Connects to a created shared memory and it's the segment manager. - //!Never throws. + //!Connects to a created mapped file and its segment manager. + //!This can throw. basic_managed_mapped_file (open_only_t open_only, const char* name, const void *addr = 0) : m_mfile(open_only, name, read_write, addr, @@ -90,11 +96,31 @@ class basic_managed_mapped_file detail::DoOpen)) {} + //!Connects to a created mapped file and its segment manager + //!in copy_on_write mode. + //!This can throw. + basic_managed_mapped_file (open_copy_on_write_t, const char* name, + const void *addr = 0) + : m_mfile(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), + detail::DoOpen)) + {} + + //!Connects to a created mapped file and its segment manager + //!in read-only mode. + //!This can throw. + basic_managed_mapped_file (open_read_only_t, const char* name, + const void *addr = 0) + : m_mfile(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), + detail::DoOpen)) + {} + //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_mapped_file - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_mapped_file(basic_managed_mapped_file &&moved) @@ -105,7 +131,7 @@ class basic_managed_mapped_file //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_mapped_file &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved) @@ -156,11 +182,45 @@ class basic_managed_mapped_file } /// @cond + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(m_mfile.get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + private: managed_open_or_create_type m_mfile; /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index 551a7d3..21d9b5b 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -23,9 +23,6 @@ #include #include -//!\file -//!Describes a named shared memory object allocation user class. - namespace boost { namespace interprocess { @@ -58,10 +55,11 @@ class basic_managed_shared_memory typedef detail::create_open_func create_open_func_t; - basic_managed_shared_memory(); - basic_managed_shared_memory *get_this_pointer() { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; /// @endcond public: //functions @@ -75,6 +73,11 @@ class basic_managed_shared_memory ~basic_managed_shared_memory() {} + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_shared_memory() + {} + //!Creates shared memory and creates and places the segment manager. //!This can throw. basic_managed_shared_memory(create_only_t create_only, const char *name, @@ -97,10 +100,32 @@ class basic_managed_shared_memory detail::DoOpenOrCreate)) {} - //!Connects to a created shared memory and it's the segment manager. - //!Never throws. + //!Connects to a created shared memory and its segment manager. + //!in copy_on_write mode. + //!This can throw. + basic_managed_shared_memory (open_copy_on_write_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), + detail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!in read-only mode. + //!This can throw. + basic_managed_shared_memory (open_read_only_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), + detail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!This can throw. basic_managed_shared_memory (open_only_t open_only, const char* name, - const void *addr = 0) + const void *addr = 0) : base_t() , base2_t(open_only, name, read_write, addr, create_open_func_t(get_this_pointer(), @@ -111,7 +136,7 @@ class basic_managed_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_shared_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_shared_memory(basic_managed_shared_memory &&moved) @@ -122,7 +147,7 @@ class basic_managed_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_shared_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved) @@ -157,8 +182,45 @@ class basic_managed_shared_memory return base_t::template shrink_to_fit (filename); } + + /// @cond + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(base2_t::get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index b4acdf0..805a481 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -23,9 +23,6 @@ #include #include -//!\file -//!Describes a named shared memory object allocation user class. - namespace boost { namespace interprocess { @@ -60,9 +57,18 @@ class basic_managed_windows_shared_memory basic_managed_windows_shared_memory *get_this_pointer() { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; /// @endcond public: //functions + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_windows_shared_memory() + {} + //!Creates shared memory and creates and places the segment manager. //!This can throw. basic_managed_windows_shared_memory @@ -85,20 +91,39 @@ class basic_managed_windows_shared_memory detail::DoOpenOrCreate)) {} - //!Connects to a created shared memory and it's the segment manager. - //!Never throws. - basic_managed_windows_shared_memory (open_only_t open_only, const char* name, - const void *addr = 0) + //!Connects to a created shared memory and its segment manager. + //!This can throw. + basic_managed_windows_shared_memory + (open_only_t open_only, const char* name, const void *addr = 0) : m_wshm(open_only, name, read_write, addr, create_open_func_t(get_this_pointer(), detail::DoOpen)) {} + //!Connects to a created shared memory and its segment manager + //!in copy_on_write mode. + //!This can throw. + basic_managed_windows_shared_memory + (open_copy_on_write_t, const char* name, const void *addr = 0) + : m_wshm(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), detail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager + //!in read-only mode. + //!This can throw. + basic_managed_windows_shared_memory + (open_read_only_t, const char* name, const void *addr = 0) + : base_t() + , m_wshm(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), detail::DoOpen)) + {} + //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_windows_shared_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_windows_shared_memory(basic_managed_windows_shared_memory &&moved) @@ -109,7 +134,7 @@ class basic_managed_windows_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_windows_shared_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_windows_shared_memory &operator= @@ -133,11 +158,45 @@ class basic_managed_windows_shared_memory m_wshm.swap(other.m_wshm); } /// @cond + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(m_wshm.get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + private: detail::managed_open_or_create_impl m_wshm; /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 71a28fb..b3808a0 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -45,6 +45,8 @@ namespace interprocess { /// @cond namespace detail{ class interprocess_tester; } +namespace detail{ class raw_mapped_region_creator; } + /// @endcond //!The mapped_region class represents a portion or region created from a @@ -107,6 +109,10 @@ class mapped_region //!mapped memory. Never throws. offset_t get_offset() const; + //!Returns the mode of the mapping used to contruct the mapped file. + //!Never throws. + mode_t get_mode() const; + //!Flushes to the disk a byte range within the mapped memory. //!Never throws bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0); @@ -135,15 +141,19 @@ class mapped_region std::size_t m_size; offset_t m_offset; offset_t m_extra_offset; + mode_t m_mode; #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) file_handle_t m_file_mapping_hnd; #endif friend class detail::interprocess_tester; + friend class detail::raw_mapped_region_creator; void dont_close_on_destruction(); /// @endcond }; +///@cond + inline void swap(mapped_region &x, mapped_region &y) { x.swap(y); } @@ -161,16 +171,19 @@ inline mapped_region::~mapped_region() inline std::size_t mapped_region::get_size() const { return m_size; } -inline offset_t mapped_region::get_offset() const +inline offset_t mapped_region::get_offset() const { return m_offset; } +inline mode_t mapped_region::get_mode() const +{ return m_mode; } + inline void* mapped_region::get_address() const { return m_base; } #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) inline mapped_region::mapped_region() - : m_base(0), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) {} @@ -178,12 +191,14 @@ inline mapped_region::mapped_region() inline mapped_region::mapped_region(detail::moved_object other) : m_base(0), m_size(0), m_offset(0) , m_extra_offset(0) + , m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) { this->swap(other.get()); } #else inline mapped_region::mapped_region(mapped_region &&other) : m_base(0), m_size(0), m_offset(0) , m_extra_offset(0) + , m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) { this->swap(other); } #endif @@ -203,7 +218,7 @@ inline mapped_region::mapped_region ,offset_t offset ,std::size_t size ,const void *address) - : m_base(0), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode) , m_file_mapping_hnd(detail::invalid_file()) { mapping_handle_t mhandle = mapping.get_mapping_handle(); @@ -362,9 +377,9 @@ inline void mapped_region::priv_close() m_base = 0; } #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) - if(m_file_mapping_hnd){ + if(m_file_mapping_hnd != detail::invalid_file()){ winapi::close_handle(m_file_mapping_hnd); - m_file_mapping_hnd = 0; + m_file_mapping_hnd = detail::invalid_file(); } #endif } @@ -375,16 +390,16 @@ inline void mapped_region::dont_close_on_destruction() #else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) inline mapped_region::mapped_region() - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) {} #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE inline mapped_region::mapped_region(detail::moved_object other) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) { this->swap(other.get()); } #else inline mapped_region::mapped_region(mapped_region &&other) - : m_base(MAP_FAILED), m_size(0), m_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_mode(read_only) , m_extra_offset(0) { this->swap(other); } #endif @@ -400,7 +415,7 @@ inline mapped_region::mapped_region offset_t offset, std::size_t size, const void *address) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode) { if(size == 0){ // offset_t filesize = lseek64 @@ -441,7 +456,7 @@ inline mapped_region::mapped_region break; case copy_on_write: - prot |= PROT_READ; + prot |= (PROT_WRITE | PROT_READ); flags |= MAP_PRIVATE; break; @@ -537,19 +552,26 @@ inline void mapped_region::swap(mapped_region &other) detail::do_swap(this->m_size, other.m_size); detail::do_swap(this->m_offset, other.m_offset); detail::do_swap(this->m_extra_offset, other.m_extra_offset); + detail::do_swap(this->m_mode, other.m_mode); #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) detail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd); #endif } -/// @cond - //!No-op functor struct null_mapped_region_function { bool operator()(void *, std::size_t , bool) const { return true; } }; + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; /// @endcond } //namespace interprocess { diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index c98ec06..bd6b89b 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -281,6 +283,101 @@ class memory_algorithm_common return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); } + static bool calculate_lcm_and_needs_backwards_lcmed + (std::size_t backwards_multiple, std::size_t received_size, std::size_t size_to_achieve, + std::size_t &lcm_out, std::size_t &needs_backwards_lcmed_out) + { + // Now calculate lcm + std::size_t max = backwards_multiple; + std::size_t min = Alignment; + std::size_t needs_backwards; + std::size_t needs_backwards_lcmed; + std::size_t lcm; + std::size_t current_forward; + //Swap if necessary + if(max < min){ + std::size_t tmp = min; + min = max; + max = tmp; + } + //Check if it's power of two + if((backwards_multiple & (backwards_multiple-1)) == 0){ + if(0 != (size_to_achieve & ((backwards_multiple-1)))){ + return false; + } + + lcm = max; + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = detail::get_truncated_size_po2(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = detail::get_rounded_size_po2(needs_backwards, lcm); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of alignment + else if((backwards_multiple & (Alignment - 1u)) == 0){ + lcm = backwards_multiple; + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + //No need to round needs_backwards because backwards_multiple == lcm + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards_lcmed & (Alignment - 1u)) == 0); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the half of the alignmment + else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){ + lcm = backwards_multiple*2u; + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + if(0 != (needs_backwards_lcmed & (Alignment-1))) + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + needs_backwards_lcmed += backwards_multiple; + assert((needs_backwards_lcmed % lcm) == 0); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the half of the alignmment + else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){ + std::size_t remainder; + lcm = backwards_multiple*4u; + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + //needs_backwards_lcmed += backwards_multiple; + if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){ + if(backwards_multiple & Alignment/2u){ + needs_backwards_lcmed += (remainder)*backwards_multiple; + } + else{ + needs_backwards_lcmed += (4-remainder)*backwards_multiple; + } + } + assert((needs_backwards_lcmed % lcm) == 0); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + else{ + lcm = detail::lcm(max, min); + } + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = detail::get_truncated_size(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + assert((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = detail::get_rounded_size(needs_backwards, lcm); + lcm_out = lcm; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + static multiallocation_iterator allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes @@ -309,13 +406,13 @@ class memory_algorithm_common if(nbytes > UsableByPreviousChunk) nbytes -= UsableByPreviousChunk; - //We can find a aligned portion if we allocate a chunk that has alignment + //We can find a aligned portion if we allocate a block that has alignment //nbytes + alignment bytes or more. std::size_t minimum_allocation = max_value (nbytes + alignment, std::size_t(MinBlockUnits*Alignment)); - //Since we will split that chunk, we must request a bit more memory + //Since we will split that block, we must request a bit more memory //if the alignment is near the beginning of the buffer, because otherwise, - //there is no space for a new chunk before the alignment. + //there is no space for a new block before the alignment. // // ____ Aligned here // | @@ -390,7 +487,7 @@ class memory_algorithm_common // | MBU +more | ACB | (3) | BCU | // ----------------------------------------------------- //This size will be the minimum size to be able to create a - //new chunk in the end. + //new block in the end. const std::size_t second_min_units = max_value(std::size_t(MinBlockUnits), ceil_units(nbytes) + AllocatedCtrlUnits ); diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp new file mode 100644 index 0000000..4f5751a --- /dev/null +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp @@ -0,0 +1,61 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP +#define BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +/*!\file + Describes sequential fit algorithm used to allocate objects in shared memory. +*/ + +namespace boost { + +namespace interprocess { + +/*!This class implements the simple sequential fit algorithm with a simply + linked list of free buffers.*/ +template +class multi_simple_seq_fit + : public detail::simple_seq_fit_impl +{ + typedef detail::simple_seq_fit_impl base_t; + public: + /*!Constructor. "size" is the total size of the managed memory segment, + "extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(multi_simple_seq_fit) + offset that the allocator should not use at all.*/ + multi_simple_seq_fit (std::size_t size, std::size_t extra_hdr_bytes) + : base_t(size, extra_hdr_bytes){} + + /*!Allocates bytes from existing segments. If there is no memory, it uses + the growing functor associated with the group to allocate a new segment. + If this fails, returns 0.*/ + void* allocate (std::size_t nbytes) + { return base_t::multi_allocate(nbytes); } +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP + diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp new file mode 100644 index 0000000..2393d1e --- /dev/null +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp @@ -0,0 +1,973 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP +#define BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*!\file + Describes sequential fit algorithm used to allocate objects in shared memory. + This class is intended as a base class for single segment and multi-segment + implementations. +*/ + +namespace boost { + +namespace interprocess { + +namespace detail { + +/*!This class implements the simple sequential fit algorithm with a simply + linked list of free buffers. + This class is intended as a base class for single segment and multi-segment + implementations.*/ +template +class simple_seq_fit_impl +{ + //Non-copyable + simple_seq_fit_impl(); + simple_seq_fit_impl(const simple_seq_fit_impl &); + simple_seq_fit_impl &operator=(const simple_seq_fit_impl &); + + public: + /*!Shared interprocess_mutex family used for the rest of the Interprocess framework*/ + typedef MutexFamily mutex_family; + /*!Pointer type to be used with the rest of the Interprocess framework*/ + typedef VoidPointer void_pointer; + + private: + struct block_ctrl; + typedef typename detail:: + pointer_to_other::type block_ctrl_ptr; + + /*!Block control structure*/ + struct block_ctrl + { + /*!Offset pointer to the next block.*/ + block_ctrl_ptr m_next; + /*!This block's memory size (including block_ctrl + header) in BasicSize units*/ + std::size_t m_size; + + std::size_t get_user_bytes() const + { return this->m_size*Alignment - BlockCtrlBytes; } + + std::size_t get_total_bytes() const + { return this->m_size*Alignment; } + + static block_ctrl *get_block_from_addr(void *addr) + { + return reinterpret_cast + (detail::char_ptr_cast(addr) - BlockCtrlBytes); + } + + void *get_addr() const + { + return reinterpret_cast + (detail::char_ptr_cast(this) + BlockCtrlBytes); + } + + }; + + /*!Shared interprocess_mutex to protect memory allocate/deallocate*/ + typedef typename MutexFamily::mutex_type interprocess_mutex; + + /*!This struct includes needed data and derives from + interprocess_mutex to allow EBO when using null interprocess_mutex*/ + struct header_t : public interprocess_mutex + { + /*!Pointer to the first free block*/ + block_ctrl m_root; + /*!Allocated bytes for internal checking*/ + std::size_t m_allocated; + /*!The size of the memory segment*/ + std::size_t m_size; + } m_header; + + public: + /*!Constructor. "size" is the total size of the managed memory segment, + "extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit_impl) + offset that the allocator should not use at all.*/ + simple_seq_fit_impl (std::size_t size, std::size_t extra_hdr_bytes); + /*!Destructor.*/ + ~simple_seq_fit_impl(); + /*!Obtains the minimum size needed by the algorithm*/ + static std::size_t get_min_size (std::size_t extra_hdr_bytes); + + //Functions for single segment management + + /*!Allocates bytes, returns 0 if there is not more memory*/ + void* allocate (std::size_t nbytes); + + /*!Deallocates previously allocated bytes*/ + void deallocate (void *addr); + + /*!Returns the size of the memory segment*/ + std::size_t get_size() const; + + /*!Increases managed memory in extra_size bytes more*/ + void grow(std::size_t extra_size); + + /*!Returns true if all allocated memory has been deallocated*/ + bool all_memory_deallocated(); + + /*!Makes an internal sanity check and returns true if success*/ + bool check_sanity(); + + //!Initializes to zero all the memory that's not in use. + //!This function is normally used for security reasons. + void clear_free_memory(); + + std::pair + allocation_command (allocation_type command, std::size_t limit_size, + std::size_t preferred_size,std::size_t &received_size, + void *reuse_ptr = 0, std::size_t backwards_multiple = 1); + + /*!Returns the size of the buffer previously allocated pointed by ptr*/ + std::size_t size(void *ptr) const; + + /*!Allocates aligned bytes, returns 0 if there is not more memory. + Alignment must be power of 2*/ + void* allocate_aligned (std::size_t nbytes, std::size_t alignment); + + /*!Allocates bytes, if there is no more memory, it executes functor + f(std::size_t) to allocate a new segment to manage. The functor returns + std::pair indicating the base address and size of + the new segment. If the new segment can't be allocated, allocate + it will return 0.*/ + void* multi_allocate(std::size_t nbytes); + + private: + /*!Real allocation algorithm with min allocation option*/ + std::pair priv_allocate(allocation_type command + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr = 0); + /*!Returns next block if it's free. + Returns 0 if next block is not free.*/ + block_ctrl *priv_next_block_if_free(block_ctrl *ptr); + + /*!Returns previous block's if it's free. + Returns 0 if previous block is not free.*/ + std::pairpriv_prev_block_if_free(block_ctrl *ptr); + + /*!Real expand function implementation*/ + bool priv_expand(void *ptr + ,std::size_t min_size, std::size_t preferred_size + ,std::size_t &received_size); + + /*!Real expand to both sides implementation*/ + void* priv_expand_both_sides(allocation_type command + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr + ,bool only_preferred_backwards); + + /*!Real shrink function implementation*/ + bool priv_shrink(void *ptr + ,std::size_t max_size, std::size_t preferred_size + ,std::size_t &received_size); + + //!Real private aligned allocation function + void* priv_allocate_aligned (std::size_t nbytes, std::size_t alignment); + + /*!Checks if block has enough memory and splits/unlinks the block + returning the address to the users*/ + void* priv_check_and_allocate(std::size_t units + ,block_ctrl* prev + ,block_ctrl* block + ,std::size_t &received_size); + /*!Real deallocation algorithm*/ + void priv_deallocate(void *addr); + + /*!Makes a new memory portion available for allocation*/ + void priv_add_segment(void *addr, std::size_t size); + + enum { Alignment = boost::alignment_of::value }; + enum { BlockCtrlBytes = detail::ct_rounded_size::value }; + enum { BlockCtrlSize = BlockCtrlBytes/Alignment }; + enum { MinBlockSize = BlockCtrlSize + Alignment }; + + public: + enum { PayloadPerAllocation = BlockCtrlBytes }; +}; + +template +inline simple_seq_fit_impl:: + simple_seq_fit_impl(std::size_t size, std::size_t extra_hdr_bytes) +{ + //Initialize sizes and counters + m_header.m_allocated = 0; + m_header.m_size = size; + + //Initialize pointers + std::size_t block1_off = detail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment); + m_header.m_root.m_next = reinterpret_cast + (detail::char_ptr_cast(this) + block1_off); + m_header.m_root.m_next->m_size = (size - block1_off)/Alignment; + m_header.m_root.m_next->m_next = &m_header.m_root; +} + +template +inline simple_seq_fit_impl::~simple_seq_fit_impl() +{ + //There is a memory leak! +// assert(m_header.m_allocated == 0); +// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root)); +} + +template +inline void simple_seq_fit_impl::grow(std::size_t extra_size) +{ + //Old highest address block's end offset + std::size_t old_end = m_header.m_size/Alignment*Alignment; + + //Update managed buffer's size + m_header.m_size += extra_size; + + //We need at least MinBlockSize blocks to create a new block + if((m_header.m_size - old_end) < MinBlockSize){ + return; + } + + //We'll create a new free block with extra_size bytes + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(this) + old_end); + + new_block->m_next = 0; + new_block->m_size = (m_header.m_size - old_end)/Alignment; + m_header.m_allocated += new_block->m_size*Alignment; + this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes); +} + +template +inline void simple_seq_fit_impl::priv_add_segment(void *addr, std::size_t size) +{ + //Check size + assert(!(size < MinBlockSize)); + if(size < MinBlockSize) + return; + //Construct big block using the new segment + block_ctrl *new_block = static_cast(addr); + new_block->m_size = size/Alignment; + new_block->m_next = 0; + //Simulate this block was previously allocated + m_header.m_allocated += new_block->m_size*Alignment; + //Return block and insert it in the free block list + this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes); +} + +template +inline std::size_t simple_seq_fit_impl::get_size() const + { return m_header.m_size; } + +template +inline std::size_t simple_seq_fit_impl:: + get_min_size (std::size_t extra_hdr_bytes) +{ + return detail::get_rounded_size(sizeof(simple_seq_fit_impl)+extra_hdr_bytes + ,Alignment) + + MinBlockSize; +} + +template +inline bool simple_seq_fit_impl:: + all_memory_deallocated() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return m_header.m_allocated == 0 && + detail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root; +} + +template +inline void simple_seq_fit_impl::clear_free_memory() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + block_ctrl *block = detail::get_pointer(m_header.m_root.m_next); + + //Iterate through all free portions + do{ + //Just clear user the memory part reserved for the user + std::memset( detail::char_ptr_cast(block) + BlockCtrlBytes + , 0 + , block->m_size*Alignment - BlockCtrlBytes); + block = detail::get_pointer(block->m_next); + } + while(block != &m_header.m_root); +} + +template +inline bool simple_seq_fit_impl:: + check_sanity() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + block_ctrl *block = detail::get_pointer(m_header.m_root.m_next); + + std::size_t free_memory = 0; + + //Iterate through all blocks obtaining their size + do{ + //Free blocks's next must be always valid + block_ctrl *next = detail::get_pointer(block->m_next); + if(!next){ + return false; + } + free_memory += block->m_size*Alignment; + block = next; + } + while(block != &m_header.m_root); + + //Check allocated bytes are less than size + if(m_header.m_allocated > m_header.m_size){ + return false; + } + + //Check free bytes are less than size + if(free_memory > m_header.m_size){ + return false; + } + return true; +} + +template +inline void* simple_seq_fit_impl:: + allocate(std::size_t nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + std::size_t ignore; + return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; +} + +template +inline void* simple_seq_fit_impl:: + allocate_aligned(std::size_t nbytes, std::size_t alignment) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return priv_allocate_aligned(nbytes, alignment); +} + +template +inline std::pair simple_seq_fit_impl:: + allocation_command (allocation_type command, std::size_t min_size, + std::size_t preferred_size,std::size_t &received_size, + void *reuse_ptr, std::size_t backwards_multiple) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + (void)backwards_multiple; + command &= ~expand_bwd; + if(!command) + return std::pair(0, false); + return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr); +} + +template +inline std::size_t simple_seq_fit_impl:: + size(void *ptr) const +{ + //We need no synchronization since this block is not going + //to be modified + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + return block->m_size*Alignment - BlockCtrlBytes; +} + +template +inline void* simple_seq_fit_impl:: + multi_allocate(std::size_t nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + //Multisegment pointer. Let's try first the normal allocation + //since it's faster. + std::size_t ignore; + void *addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + if(!addr){ + //If this fails we will try the allocation through the segment + //creator. + std::size_t group, id; + //Obtain the segment group of this segment + void_pointer::get_group_and_id(this, group, id); + if(group == 0){ + //Ooops, group 0 is not valid. + return 0; + } + //Now obtain the polymorphic functor that creates + //new segments and try to allocate again. + boost::interprocess::multi_segment_services *p_services = + static_cast + (void_pointer::find_group_data(group)); + assert(p_services); + std::pair ret = + p_services->create_new_segment(MinBlockSize > nbytes ? MinBlockSize : nbytes); + if(ret.first){ + priv_add_segment(ret.first, ret.second); + addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + } + } + return addr; +} + +template +void* simple_seq_fit_impl:: + priv_expand_both_sides(allocation_type command + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr + ,bool only_preferred_backwards) +{ + typedef std::pair prev_block_t; + block_ctrl *reuse = block_ctrl::get_block_from_addr(reuse_ptr); + received_size = 0; + + if(this->size(reuse_ptr) > min_size){ + received_size = this->size(reuse_ptr); + return reuse_ptr; + } + + if(command & expand_fwd){ + if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) + return reuse_ptr; + } + else{ + received_size = this->size(reuse_ptr); + } + if(command & expand_bwd){ + std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes; + prev_block_t prev_pair = priv_prev_block_if_free(reuse); + block_ctrl *prev = prev_pair.second; + if(!prev){ + return 0; + } + + std::size_t needs_backwards = + detail::get_rounded_size(preferred_size - extra_forward, Alignment); + + if(!only_preferred_backwards){ + needs_backwards = + max_value(detail::get_rounded_size(min_size - extra_forward, Alignment) + ,min_value(prev->get_user_bytes(), needs_backwards)); + } + + //Check if previous block has enough size + if((prev->get_user_bytes()) >= needs_backwards){ + //Now take all next space. This will succeed + if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){ + assert(0); + } + + //We need a minimum size to split the previous one + if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){ + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(reuse) - needs_backwards - BlockCtrlBytes); + new_block->m_next = 0; + new_block->m_size = + BlockCtrlSize + (needs_backwards + extra_forward)/Alignment; + prev->m_size = + (prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlSize; + received_size = needs_backwards + extra_forward; + m_header.m_allocated += needs_backwards + BlockCtrlBytes; + return new_block->get_addr(); + } + else{ + //Just merge the whole previous block + block_ctrl *prev_2_block = prev_pair.first; + //Update received size and allocation + received_size = extra_forward + prev->get_user_bytes(); + m_header.m_allocated += prev->get_total_bytes(); + //Now unlink it from previous block + prev_2_block->m_next = prev->m_next; + prev->m_size = reuse->m_size + prev->m_size; + prev->m_next = 0; + return prev->get_addr(); + } + } + } + return 0; +} + +template +std::pair simple_seq_fit_impl:: + priv_allocate(allocation_type command + ,std::size_t limit_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr) +{ + if(command & shrink_in_place){ + bool success = + this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size); + return std::pair ((success ? reuse_ptr : 0), true); + } + typedef std::pair return_type; + received_size = 0; + + if(limit_size > preferred_size) + return return_type(0, false); + + //Number of units to request (including block_ctrl header) + std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlSize; + + //Get the root and the first memory block + block_ctrl *prev = &m_header.m_root; + block_ctrl *block = detail::get_pointer(prev->m_next); + block_ctrl *root = &m_header.m_root; + block_ctrl *biggest_block = 0; + block_ctrl *prev_biggest_block = 0; + std::size_t biggest_size = limit_size; + + //Expand in place + //reuse_ptr, limit_size, preferred_size, received_size + // + if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + void *ret = priv_expand_both_sides + (command, limit_size, preferred_size, received_size, reuse_ptr, true); + if(ret) + return return_type(ret, true); + } + + if(command & allocate_new){ + received_size = 0; + while(block != root){ + //Update biggest block pointers + if(block->m_size > biggest_size){ + prev_biggest_block = prev; + biggest_size = block->m_size; + biggest_block = block; + } + void *addr = this->priv_check_and_allocate(nunits, prev, block, received_size); + if(addr) return return_type(addr, false); + //Bad luck, let's check next block + prev = block; + block = detail::get_pointer(block->m_next); + } + + //Bad luck finding preferred_size, now if we have any biggest_block + //try with this block + if(biggest_block){ + received_size = biggest_block->m_size*Alignment - BlockCtrlSize; + nunits = detail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlSize; + void *ret = this->priv_check_and_allocate + (nunits, prev_biggest_block, biggest_block, received_size); + if(ret) + return return_type(ret, false); + } + } + //Now try to expand both sides with min size + if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + return return_type(priv_expand_both_sides + (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); + } + return return_type(0, false); +} + +template +inline typename simple_seq_fit_impl::block_ctrl * + simple_seq_fit_impl:: + priv_next_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + //Take the address where the next block should go + block_ctrl *next_block = reinterpret_cast + (detail::char_ptr_cast(ptr) + ptr->m_size*Alignment); + + //Check if the adjacent block is in the managed segment + std::size_t distance = (detail::char_ptr_cast(next_block) - detail::char_ptr_cast(this))/Alignment; + if(distance >= (m_header.m_size/Alignment)){ + //"next_block" does not exist so we can't expand "block" + return 0; + } + + if(!next_block->m_next) + return 0; + + return next_block; +} + +template +inline + std::pair::block_ctrl * + ,typename simple_seq_fit_impl::block_ctrl *> + simple_seq_fit_impl:: + priv_prev_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + typedef std::pair prev_pair_t; + //Take the address where the previous block should go + block_ctrl *root = &m_header.m_root; + block_ctrl *prev_2_block = root; + block_ctrl *prev_block = detail::get_pointer(root->m_next); + while((detail::char_ptr_cast(prev_block) + prev_block->m_size*Alignment) + != (detail::char_ptr_cast(ptr)) + && prev_block != root){ + prev_2_block = prev_block; + prev_block = detail::get_pointer(prev_block->m_next); + } + + if(prev_block == root || !prev_block->m_next) + return prev_pair_t(0, 0); + + //Check if the previous block is in the managed segment + std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment; + if(distance >= (m_header.m_size/Alignment)){ + //"previous_block" does not exist so we can't expand "block" + return prev_pair_t(0, 0); + } + return prev_pair_t(prev_2_block, prev_block); +} + + +template +inline bool simple_seq_fit_impl:: + priv_expand (void *ptr + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size) +{ + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + std::size_t old_block_size = block->m_size; + + //All used blocks' next is marked with 0 so check it + assert(block->m_next == 0); + + //Put this to a safe value + received_size = old_block_size*Alignment - BlockCtrlBytes; + + //Now translate it to Alignment units + min_size = detail::get_rounded_size(min_size, Alignment)/Alignment; + preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment; + + //Some parameter checks + if(min_size > preferred_size) + return false; + + std::size_t data_size = old_block_size - BlockCtrlSize; + + if(data_size >= min_size) + return true; + + block_ctrl *next_block = priv_next_block_if_free(block); + if(!next_block){ + return false; + } + + //Is "block" + "next_block" big enough? + std::size_t merged_size = old_block_size + next_block->m_size; + + //Now we can expand this block further than before + received_size = merged_size*Alignment - BlockCtrlBytes; + + if(merged_size < (min_size + BlockCtrlSize)){ + return false; + } + + //We can fill expand. Merge both blocks, + block->m_next = next_block->m_next; + block->m_size = merged_size; + + //Find the previous free block of next_block + block_ctrl *prev = &m_header.m_root; + while(detail::get_pointer(prev->m_next) != next_block){ + prev = detail::get_pointer(prev->m_next); + } + + //Now insert merged block in the free list + //This allows reusing allocation logic in this function + m_header.m_allocated -= old_block_size*Alignment; + prev->m_next = block; + + //Now use check and allocate to do the allocation logic + preferred_size += BlockCtrlSize; + std::size_t nunits = preferred_size < merged_size ? preferred_size : merged_size; + + //This must success since nunits is less than merged_size! + if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){ + //Something very ugly is happening here. This is a bug + //or there is memory corruption + assert(0); + return false; + } + return true; +} + +template +inline bool simple_seq_fit_impl:: + priv_shrink (void *ptr + ,std::size_t max_size + ,std::size_t preferred_size + ,std::size_t &received_size) +{ + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + std::size_t block_size = block->m_size; + + //All used blocks' next is marked with 0 so check it + assert(block->m_next == 0); + + //Put this to a safe value + received_size = block_size*Alignment - BlockCtrlBytes; + + //Now translate it to Alignment units + max_size = max_size/Alignment; + preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment; + + //Some parameter checks + if(max_size < preferred_size) + return false; + + std::size_t data_size = block_size - BlockCtrlSize; + + if(data_size < preferred_size) + return false; + + if(data_size == preferred_size) + return true; + + //We must be able to create at least a new empty block + if((data_size - preferred_size) < BlockCtrlSize){ + return false; + } + + //Now we can just rewrite the size of the old buffer + block->m_size = preferred_size + BlockCtrlSize; + + //Update new size + received_size = preferred_size*Alignment; + + //We create the new block + block = reinterpret_cast + (detail::char_ptr_cast(block) + block->m_size*Alignment); + + //Write control data to simulate this new block was previously allocated + block->m_next = 0; + block->m_size = data_size - preferred_size; + + //Now deallocate the new block to insert it in the free list + this->priv_deallocate(detail::char_ptr_cast(block)+BlockCtrlBytes); + return true; +} + +template +inline void* simple_seq_fit_impl:: + priv_allocate_aligned(std::size_t nbytes, std::size_t alignment) +{ + //Ensure power of 2 + if ((alignment & (alignment - std::size_t(1u))) != 0){ + //Alignment is not power of two + assert((alignment & (alignment - std::size_t(1u))) != 0); + return 0; + } + + std::size_t ignore; + if(alignment <= Alignment){ + return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + } + + std::size_t request = + nbytes + alignment + MinBlockSize*Alignment - BlockCtrlBytes; + void *buffer = priv_allocate(allocate_new, request, request, ignore).first; + if(!buffer) + return 0; + else if ((((std::size_t)(buffer)) % alignment) == 0) + return buffer; + + char *aligned_portion = (char*) + ((std::size_t)((char*)buffer + alignment - 1) & -alignment); + + char *pos = ((aligned_portion - (char*)buffer) >= (MinBlockSize*Alignment)) ? + aligned_portion : (aligned_portion + alignment); + + + block_ctrl *first = reinterpret_cast + (detail::char_ptr_cast(buffer) - BlockCtrlBytes); + + block_ctrl *second = reinterpret_cast + (detail::char_ptr_cast(pos) - BlockCtrlBytes); + + std::size_t old_size = first->m_size; + + first->m_size = ((char*)second - (char*)first)/Alignment; + second->m_size = old_size - first->m_size; + + //Write control data to simulate this new block was previously allocated + second->m_next = 0; + + //Now deallocate the new block to insert it in the free list + this->priv_deallocate(detail::char_ptr_cast(first) + BlockCtrlBytes); + return detail::char_ptr_cast(second) + BlockCtrlBytes; +} + +template inline +void* simple_seq_fit_impl::priv_check_and_allocate + (std::size_t nunits + ,typename simple_seq_fit_impl::block_ctrl* prev + ,typename simple_seq_fit_impl::block_ctrl* block + ,std::size_t &received_size) +{ + std::size_t upper_nunits = nunits + BlockCtrlSize; + bool found = false; + + if (block->m_size > upper_nunits){ + //This block is bigger than needed, split it in + //two blocks, the first's size will be (block->m_size-units) + //the second's size (units) + std::size_t total_size = block->m_size; + block->m_size = nunits; + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(block) + Alignment*nunits); + new_block->m_size = total_size - nunits; + new_block->m_next = block->m_next; + prev->m_next = new_block; + found = true; + } + else if (block->m_size >= nunits){ + //This block has exactly the right size with an extra + //unusable extra bytes. + prev->m_next = block->m_next; + found = true; + } + + if(found){ + //We need block_ctrl for deallocation stuff, so + //return memory user can overwrite + m_header.m_allocated += block->m_size*Alignment; + received_size = block->m_size*Alignment - BlockCtrlBytes; + //Mark the block as allocated + block->m_next = 0; + //Check alignment + assert(((detail::char_ptr_cast(block) - detail::char_ptr_cast(this)) + % Alignment) == 0 ); + return detail::char_ptr_cast(block)+BlockCtrlBytes; + } + return 0; +} + +template +void simple_seq_fit_impl::deallocate(void* addr) +{ + if(!addr) return; + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return this->priv_deallocate(addr); +} + +template +void simple_seq_fit_impl::priv_deallocate(void* addr) +{ + if(!addr) return; + + //Let's get free block list. List is always sorted + //by memory address to allow block merging. + //Pointer next always points to the first + //(lower address) block + block_ctrl_ptr prev = &m_header.m_root; + block_ctrl_ptr pos = m_header.m_root.m_next; + block_ctrl_ptr block = reinterpret_cast + (detail::char_ptr_cast(addr) - BlockCtrlBytes); + + //All used blocks' next is marked with 0 so check it + assert(block->m_next == 0); + + //Check if alignment and block size are right + assert((detail::char_ptr_cast(addr) - detail::char_ptr_cast(this)) + % Alignment == 0 ); + + std::size_t total_size = Alignment*block->m_size; + assert(m_header.m_allocated >= total_size); + + //Update used memory count + m_header.m_allocated -= total_size; + + //Let's find the previous and the next block of the block to deallocate + //This ordering comparison must be done with original pointers + //types since their mapping to raw pointers can be different + //in each process + while((detail::get_pointer(pos) != &m_header.m_root) && (block > pos)){ + prev = pos; + pos = pos->m_next; + } + + //Try to combine with upper block + if ((detail::char_ptr_cast(detail::get_pointer(block)) + + Alignment*block->m_size) == + detail::char_ptr_cast(detail::get_pointer(pos))){ + + block->m_size += pos->m_size; + block->m_next = pos->m_next; + } + else{ + block->m_next = pos; + } + + //Try to combine with lower block + if ((detail::char_ptr_cast(detail::get_pointer(prev)) + + Alignment*prev->m_size) == + detail::char_ptr_cast(detail::get_pointer(block))){ + prev->m_size += block->m_size; + prev->m_next = block->m_next; + } + else{ + prev->m_next = block; + } +} + +} //namespace detail { + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP + diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index 88394ff..3898d5f 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -564,7 +564,7 @@ inline std::pair simple_seq_fit_impl:: T *reuse_ptr) { std::pair ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); @@ -577,7 +577,7 @@ inline std::pair simple_seq_fit_impl:: void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) - return std::pair(0, 0); + return std::pair((void*)0, 0); if(command & try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object @@ -596,7 +596,7 @@ inline std::pair simple_seq_fit_impl:: void *reuse_ptr, std::size_t sizeof_object) { command &= ~expand_bwd; - if(!command) return std::pair(0, false); + if(!command) return std::pair((void*)0, false); std::pair ret; std::size_t max_count = m_header.m_size/sizeof_object; @@ -769,7 +769,7 @@ std::pair simple_seq_fit_impl:: received_size = 0; if(limit_size > preferred_size) - return return_type(0, false); + return return_type((void*)0, false); //Number of units to request (including block_ctrl header) std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlUnits; @@ -819,7 +819,7 @@ std::pair simple_seq_fit_impl:: if(biggest_block){ std::size_t limit_units = detail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlUnits; if(biggest_block->m_size < limit_units) - return return_type(0, false); + return return_type((void*)0, false); received_size = biggest_block->m_size*Alignment - BlockCtrlUnits; void *ret = this->priv_check_and_allocate @@ -836,7 +836,7 @@ std::pair simple_seq_fit_impl:: algo_impl_t::assert_alignment(ret.first); return ret; } - return return_type(0, false); + return return_type((void*)0, false); } template inline @@ -888,13 +888,13 @@ inline } if(prev_block == root || !prev_block->m_next) - return prev_pair_t(0, 0); + return prev_pair_t((block_ctrl*)0, (block_ctrl*)0); //Check if the previous block is in the managed segment std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment; if(distance >= (m_header.m_size/Alignment)){ //"previous_block" does not exist so we can't expand "block" - return prev_pair_t(0, 0); + return prev_pair_t((block_ctrl*)0, (block_ctrl*)0); } return prev_pair_t(prev_2_block, prev_block); } diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index f675f1d..9634116 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -352,6 +352,8 @@ class rbtree_best_fit static const std::size_t PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk; }; +/// @cond + template inline std::size_t rbtree_best_fit ::priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes) @@ -651,7 +653,7 @@ inline std::pair rbtree_best_fit ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); @@ -664,7 +666,7 @@ inline std::pair rbtree_best_fit(0, 0); + return std::pair((void *)0, 0); if(command & try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object @@ -776,26 +778,16 @@ void* rbtree_best_fit:: assert(prev_block->m_size == reuse->m_prev_size); algo_impl_t::assert_alignment(prev_block); - //Let's calculate the number of extra bytes of data before the current - //block's begin. The value is a multiple of backwards_multiple - std::size_t needs_backwards = preferred_size - - detail::get_truncated_size(received_size, backwards_multiple); - - const std::size_t lcm = detail::lcm(max_value(backwards_multiple, (std::size_t)Alignment) - ,min_value(backwards_multiple, (std::size_t)Alignment)); - - //If we want to use min_size data to get a buffer between preferred_size - //and min_size if preferred_size can't be achieved, calculate the - //biggest of all possibilities - if(!only_preferred_backwards){ - needs_backwards = min_size - detail::get_truncated_size(received_size, backwards_multiple); + std::size_t needs_backwards_aligned; + std::size_t lcm; + if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed + ( backwards_multiple + , received_size + , only_preferred_backwards ? preferred_size : min_size + , lcm, needs_backwards_aligned)){ + return 0; } - assert((needs_backwards % backwards_multiple) == 0); - - const std::size_t needs_backwards_aligned = - detail::get_rounded_size(needs_backwards, lcm); - //Check if previous block has enough size if(std::size_t(prev_block->m_size*Alignment) >= needs_backwards_aligned){ //Now take all next space. This will succeed @@ -822,7 +814,7 @@ void* rbtree_best_fit:: assert(prev_block->m_size >= BlockCtrlUnits); priv_mark_as_free_block(prev_block); - //Update the old previous block in the free chunks tree + //Update the old previous block in the free blocks tree //If the new size fulfills tree invariants do nothing, //otherwise erase() + insert() { @@ -857,10 +849,8 @@ void* rbtree_best_fit:: m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); //Just merge the whole previous block - needs_backwards = detail::get_truncated_size - (prev_block->m_size*Alignment, backwards_multiple); - //received_size = received_size/backwards_multiple*backwards_multiple + needs_backwards; - received_size = received_size + needs_backwards; + //prev_block->m_size*Alignment is multiple of lcm (and backwards_multiple) + received_size = received_size + prev_block->m_size*Alignment; m_header.m_allocated += prev_block->m_size*Alignment; //Now update sizes @@ -942,7 +932,7 @@ std::pair rbtree_best_fit: received_size = 0; if(limit_size > preferred_size) - return return_type(0, false); + return return_type((void*)0, false); //Number of units to request (including block_ctrl header) std::size_t preferred_units = priv_get_total_units(preferred_size); @@ -981,7 +971,7 @@ std::pair rbtree_best_fit: (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); } - return return_type(0, false); + return return_type((void*)0, false); } template @@ -1070,12 +1060,12 @@ bool rbtree_best_fit:: assert(next_block->m_size == priv_next_block(next_block)->m_prev_size); const std::size_t rem_units = merged_units - intended_units; - //Check if we we need to update the old next block in the free chunks tree + //Check if we we need to update the old next block in the free blocks tree //If the new size fulfills tree invariants, we just need to replace the node //(the block start has been displaced), otherwise erase() + insert(). // - //This fixup must be done in two parts, because the new next chunk might - //overwrite the tree hook of the old next chunk. So we first erase the + //This fixup must be done in two parts, because the new next block might + //overwrite the tree hook of the old next block. So we first erase the //old if needed and we'll insert the new one after creating the new next imultiset_iterator old_next_block_it(Imultiset::s_iterator_to(*next_block)); const bool size_invariants_broken = @@ -1304,7 +1294,7 @@ void rbtree_best_fit::priv_deallocate(vo bool merge_with_prev = !priv_is_prev_allocated(block); bool merge_with_next = !priv_is_allocated_block(next_block); - //Merge logic. First just update block sizes, then fix free chunks tree + //Merge logic. First just update block sizes, then fix free blocks tree if(merge_with_prev || merge_with_next){ //Merge if the previous is free if(merge_with_prev){ @@ -1344,10 +1334,11 @@ void rbtree_best_fit::priv_deallocate(vo priv_mark_as_free_block(block_to_insert); } +/// @endcond + } //namespace interprocess { } //namespace boost { #include #endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP - diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index c3853a1..627c440 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -53,9 +53,6 @@ class offset_ptr { /// @cond typedef offset_ptr self_t; - typedef const PointedType * const_pointer_t; - typedef typename detail::add_reference - ::type const_reference_t; void unspecified_bool_type_func() const {} typedef void (self_t::*unspecified_bool_type)() const; @@ -64,6 +61,9 @@ class offset_ptr __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0 #endif void set_offset(const volatile void *ptr) + { set_offset((const void*)ptr); } + + void set_offset(const void *ptr) { const char *p = static_cast(const_cast(ptr)); //offset == 1 && ptr != 0 is not legal for this pointer @@ -402,68 +402,44 @@ namespace intrusive { //Predeclaration to avoid including header template -struct has_pointer_plus_bit; +struct max_pointer_plus_bits; -template -struct has_pointer_plus_bit, N> +template +struct max_pointer_plus_bits, Alignment> { - static const bool value = (N % 4u == 0); + //The offset ptr can embed one bit less than the alignment since it + //uses offset == 1 to store the null pointer. + static const std::size_t value = ::boost::interprocess::detail::ls_zeros::value - 1; }; //Predeclaration -template -struct pointer_plus_bit; +template +struct pointer_plus_bits; -//Specialization -template -struct pointer_plus_bit > +template +struct pointer_plus_bits, NumBits> { typedef boost::interprocess::offset_ptr pointer; + //Bits are stored in the lower bits of the pointer except the LSB, + //because this bit is used to represent the null pointer. + static const std::size_t Mask = ((std::size_t(1) << NumBits)-1)<<1u; static pointer get_pointer(const pointer &n) - { return (T*)(std::size_t(n.get()) & ~std::size_t(2u)); } + { return (T*)(std::size_t(n.get()) & ~std::size_t(Mask)); } static void set_pointer(pointer &n, pointer p) - { n = (T*)(std::size_t(p.get()) | (std::size_t(n.get()) & std::size_t(2u))); } - - static bool get_bit(const pointer &n) - { return 0 != (std::size_t(n.get()) & std::size_t(2u)); } - - static void set_bit(pointer &n, bool c) - { n = (T*)(std::size_t(get_pointer(n).get()) | (std::size_t(c) << 1u)); } -}; - -//Predeclaration to avoid including header -template -struct has_pointer_plus_2_bits; - -template -struct has_pointer_plus_2_bits, N> -{ - static const bool value = (N % 8u == 0); -}; - -//Predeclaration -template -struct pointer_plus_2_bits; - -template -struct pointer_plus_2_bits > -{ - typedef boost::interprocess::offset_ptr pointer; - - static pointer get_pointer(const pointer &n) - { return (T*)(std::size_t(n.get()) & ~std::size_t(6u)); } - - static void set_pointer(pointer &n, pointer p) - { n = (T*)(std::size_t(p.get()) | (std::size_t(n.get()) & std::size_t(6u))); } + { + std::size_t pint = std::size_t(p.get()); + assert(0 == (std::size_t(pint) & Mask)); + n = (T*)(pint | (std::size_t(n.get()) & std::size_t(Mask))); + } static std::size_t get_bits(const pointer &n) - { return(std::size_t(n.get()) & std::size_t(6u)) >> 1u; } + { return(std::size_t(n.get()) & std::size_t(Mask)) >> 1u; } static void set_bits(pointer &n, std::size_t b) { - assert(b < 4); + assert(b < (std::size_t(1) << NumBits)); n = (T*)(std::size_t(get_pointer(n).get()) | (b << 1u)); } }; diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index c8ee79e..545cf5d 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include //std::size_t #include //char_traits #include //std::nothrow @@ -292,7 +294,7 @@ class segment_manager_base block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment); //------------------------------- - //boost::interprocess::scoped_lock guard(m_header); + //scoped_lock guard(m_header); //------------------------------- if(ctrl_data->allocation_type() != anonymous_type){ @@ -423,10 +425,10 @@ class segment_manager void *ret; if(name == reinterpret_cast(-1)){ - ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t()); + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), true); } else{ - ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t()); + ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), true); } return std::pair(static_cast(ret), size); } @@ -439,7 +441,7 @@ class segment_manager { detail::placement_destroy table; std::size_t size; - void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t()); + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), true); return std::pair(static_cast(ret), size); } @@ -502,7 +504,7 @@ class segment_manager //!executing the object function call*/ template void atomic_func(Func &f) - { boost::interprocess::scoped_lock guard(m_header); f(); } + { scoped_lock guard(m_header); f(); } //!Destroys a previously created unique instance. //!Returns false if the object was not present. @@ -559,7 +561,7 @@ class segment_manager void reserve_named_objects(std::size_t num) { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- m_header.m_named_index.reserve(num); } @@ -570,7 +572,7 @@ class segment_manager void reserve_unique_objects(std::size_t num) { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- m_header.m_unique_index.reserve(num); } @@ -580,7 +582,7 @@ class segment_manager void shrink_to_fit_indexes() { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- m_header.m_named_index.shrink_to_fit(); m_header.m_unique_index.shrink_to_fit(); @@ -591,7 +593,7 @@ class segment_manager std::size_t get_num_named_objects() { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- return m_header.m_named_index.size(); } @@ -601,7 +603,7 @@ class segment_manager std::size_t get_num_unique_objects() { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- return m_header.m_unique_index.size(); } @@ -688,6 +690,39 @@ class segment_manager (priv_generic_construct(name, num, try2find, dothrow, table)); } + //!Tries to find a previous named allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair find_no_lock (const CharType* name) + { + //The name can't be null, no anonymous object can be found by name + assert(name != 0); + detail::placement_destroy table; + std::size_t size; + void *ret; + + if(name == reinterpret_cast(-1)){ + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), false); + } + else{ + ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), false); + } + return std::pair(static_cast(ret), size); + } + + //!Tries to find a previous unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair find_no_lock (const detail::unique_instance_t* name) + { + detail::placement_destroy table; + std::size_t size; + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), false); + return std::pair(static_cast(ret), size); + } + private: void *priv_generic_construct(const CharType *name, std::size_t num, @@ -790,7 +825,8 @@ class segment_manager IndexType > &index, detail::in_place_interface &table, std::size_t &length, - detail::true_ is_intrusive) + detail::true_ is_intrusive, + bool use_lock) { (void)is_intrusive; typedef IndexType > index_type; @@ -798,7 +834,7 @@ class segment_manager typedef typename index_type::iterator index_it; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(priv_get_lock(use_lock)); //------------------------------- //Find name in index detail::intrusive_compare_key key @@ -829,7 +865,8 @@ class segment_manager IndexType > &index, detail::in_place_interface &table, std::size_t &length, - detail::false_ is_intrusive) + detail::false_ is_intrusive, + bool use_lock) { (void)is_intrusive; typedef IndexType > index_type; @@ -837,7 +874,7 @@ class segment_manager typedef typename index_type::iterator index_it; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(priv_get_lock(use_lock)); //------------------------------- //Find name in index index_it it = index.find(key_type(name, std::char_traits::length(name))); @@ -900,7 +937,7 @@ class segment_manager typedef typename index_type::value_type intrusive_value_type; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Find name in index detail::intrusive_compare_key key @@ -950,7 +987,7 @@ class segment_manager typedef typename index_type::key_type key_type; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Try to find the name in the index index_it it = index.find(key_type (name, @@ -1038,7 +1075,7 @@ class segment_manager typedef std::pair index_ib; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Insert the node. This can throw. //First, we want to know if the key is already present before @@ -1118,7 +1155,7 @@ class segment_manager //Initialize the node value_eraser to erase inserted node //if something goes wrong - detail::value_eraser value_eraser(index, it); + value_eraser v_eraser(index, it); //Avoid constructions if constructor is trivial //Build scoped ptr to avoid leaks with constructor exception @@ -1130,8 +1167,8 @@ class segment_manager //All constructors successful, we don't want to release memory mem.release(); - //Release node value_eraser since construction was successful - value_eraser.release(); + //Release node v_eraser since construction was successful + v_eraser.release(); return ptr; } @@ -1164,7 +1201,7 @@ class segment_manager typedef std::pair index_ib; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Insert the node. This can throw. //First, we want to know if the key is already present before @@ -1204,7 +1241,7 @@ class segment_manager } //Initialize the node value_eraser to erase inserted node //if something goes wrong - detail::value_eraser value_eraser(index, it); + value_eraser v_eraser(index, it); //Allocates buffer for name + data, this can throw (it hurts) void *buffer_ptr; @@ -1260,8 +1297,8 @@ class segment_manager //All constructors successful, we don't want to release memory mem.release(); - //Release node value_eraser since construction was successful - value_eraser.release(); + //Release node v_eraser since construction was successful + v_eraser.release(); return ptr; } @@ -1272,6 +1309,20 @@ class segment_manager typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + scoped_lock + #else + detail::move_return > + #endif + priv_get_lock(bool use_lock) + { + scoped_lock local(m_header, defer_lock); + if(use_lock){ + local.lock(); + } + return local; + } + //!This struct includes needed data and derives from //!rmutex to allow EBO when using null interprocess_mutex struct header_t diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index 9d2eda3..c07c79f 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -76,10 +76,12 @@ class shared_memory_object //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE shared_memory_object - (detail::moved_object &moved) + (const detail::moved_object moved) + : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved.get()); } #else shared_memory_object(shared_memory_object &&moved) + : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } #endif @@ -88,7 +90,7 @@ class shared_memory_object //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE shared_memory_object &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { shared_memory_object tmp(moved); this->swap(tmp); @@ -97,7 +99,7 @@ class shared_memory_object #else shared_memory_object &operator=(shared_memory_object &&moved) { - shared_memory_object tmp(move(moved)); + shared_memory_object tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -150,6 +152,8 @@ class shared_memory_object /// @endcond }; +/// @cond + inline shared_memory_object::shared_memory_object() : m_handle(file_handle_t(detail::invalid_file())) {} @@ -341,6 +345,32 @@ inline void shared_memory_object::priv_close() #endif +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; + +///@endcond + +//!A class that stores the name of a shared memory +//!and calls shared_memory_object::remove(name) in its destructor +//!Useful to remove temporary shared memory objects in the presence +//!of exceptions +class remove_shared_memory_on_destroy +{ + const char * m_name; + public: + remove_shared_memory_on_destroy(const char *name) + : m_name(name) + {} + + ~remove_shared_memory_on_destroy() + { shared_memory_object::remove(m_name); } +}; + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 3c48eda..8e4db51 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -72,6 +72,11 @@ class shared_count : m_px(0), m_pi(0) // nothrow {} + template + shared_count(const shared_count &other_shared_count, const Ptr &p) + : m_px(p), m_pi(other_shared_count.m_pi) + {} + template shared_count(const Ptr &p, const VoidAllocator &a, Deleter d) : m_px(p), m_pi(0) diff --git a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp index 6863bbd..5d1c98e 100644 --- a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp +++ b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp @@ -27,6 +27,10 @@ namespace boost{ namespace interprocess{ +//!This class is used as a base class that allows a shared_ptr to the current +//!object to be obtained from within a member function. +//!enable_shared_from_this defines two member functions called shared_from_this +//!that return a shared_ptr and shared_ptr, depending on constness, to this. template class enable_shared_from_this { @@ -60,7 +64,6 @@ class enable_shared_from_this return p; } - private: /// @cond typedef T element_type; mutable weak_ptr _internal_weak_this; diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index 9566224..fa272aa 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -47,19 +48,21 @@ namespace detail{ template inline void sp_enable_shared_from_this - (shared_count const & pn, - const typename pointer_to_other ::pointer, - enable_shared_from_this >::type &pe, - const typename shared_count::pointer &px) + (shared_count const & pn + ,enable_shared_from_this *pe + ,T *ptr) + { - if(pe != 0) + (void)ptr; + if(pe != 0){ pe->_internal_weak_this._internal_assign(pn); + } } -/* + template inline void sp_enable_shared_from_this(shared_count const &, ...) {} -*/ + } // namespace detail //!shared_ptr stores a pointer to a dynamically allocated object. @@ -122,9 +125,17 @@ class shared_ptr typedef typename detail::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); - //detail::sp_enable_shared_from_this( m_pn, p, p ); + detail::sp_enable_shared_from_this( m_pn, detail::get_pointer(p), detail::get_pointer(p) ); } + + //!Constructs a shared_ptr that shares ownership with r and stores p. + //!Postconditions: get() == p && use_count() == r.use_count(). + //!Throws: nothing. + shared_ptr(const shared_ptr &other, const pointer &p) + : m_pn(other.m_pn, p) + {} + //!If r is empty, constructs an empty shared_ptr. Otherwise, constructs //!a shared_ptr that shares ownership with r. Never throws. template @@ -139,6 +150,19 @@ class shared_ptr : m_pn(r.m_pn) // may throw {} + //!Move-Constructs a shared_ptr that takes ownership of other resource and + //!other is put in default-constructed state. + //!Throws: nothing. + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + explicit shared_ptr(detail::moved_object other) + : m_pn() + { this->swap(other.get()); } + #else + explicit shared_ptr(shared_ptr &&other) + : m_pn() + { this->swap(other); } + #endif + /// @cond template shared_ptr(shared_ptr const & r, detail::static_cast_tag) @@ -172,6 +196,22 @@ class shared_ptr return *this; } + //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). + //!Never throws + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + shared_ptr & operator=(detail::moved_object other) // never throws + { + this_type(other).swap(*this); + return *this; + } + #else + shared_ptr & operator=(shared_ptr &&other) // never throws + { + this_type(other).swap(*this); + return *this; + } + #endif + //!This is equivalent to: //!this_type().swap(*this); void reset() @@ -192,6 +232,12 @@ class shared_ptr this_type(p, a, d).swap(*this); } + template + void reset(shared_ptr const & r, const pointer &p) + { + this_type(r, p).swap(*this); + } + //!Returns a reference to the //!pointed type reference operator* () const // never throws @@ -333,6 +379,18 @@ typename detail::pointer_to_other, Deleter get_deleter(shared_ptr const & p) { return static_cast(p._internal_get_deleter(typeid(Deleter))); } */ + +/// @cond + +//!This class has move constructor +template +struct is_movable > +{ + enum { value = true }; +}; + +/// @endcond + } // namespace interprocess /// @cond diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index 0cade7b..ca5f1bd 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -138,11 +138,11 @@ class unique_ptr //! //!Effects: Constructs a unique_ptr which owns the pointer which u owns //!(if any). If the deleter is not a reference type, it is move constructed - //!from u’s deleter, otherwise the reference is copy constructed from u’s deleter. + //!from u's deleter, otherwise the reference is copy constructed from u's deleter. //! //!After the construction, u no longer owns a pointer. //![ Note: The deleter constructor can be implemented with - //!std::forward. —end note ] + //!std::detail::forward_impl. -end note ] //! //!Postconditions: get() == value u.get() had before the construction. //!get_deleter() returns a reference to the internally stored deleter which @@ -152,11 +152,11 @@ class unique_ptr //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE unique_ptr(detail::moved_object u) - : ptr_(u.get().release(), move(u.get().get_deleter())) + : ptr_(u.get().release(), detail::move_impl(u.get().get_deleter())) {} #else unique_ptr(unique_ptr &&u) - : ptr_(u.release(), forward(u.get_deleter())) + : ptr_(u.release(), detail::forward_impl(u.get_deleter())) {} #endif @@ -168,8 +168,8 @@ class unique_ptr //! //!Effects: Constructs a unique_ptr which owns the pointer which u owns //!(if any). If the deleter is not a reference - //!type, it is move constructed from u’s deleter, otherwise the reference - //!is copy constructed from u’s deleter. + //!type, it is move constructed from u's deleter, otherwise the reference + //!is copy constructed from u's deleter. //! //!After the construction, u no longer owns a pointer. //! @@ -181,7 +181,7 @@ class unique_ptr //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - unique_ptr(const detail::moved_object >& u, + unique_ptr(detail::moved_object > u, typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && @@ -192,12 +192,12 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u.get()).release(), move(u.get().get_deleter())) + : ptr_(const_cast&>(u.get()).release(), detail::move_impl(u.get().get_deleter())) {} #else template unique_ptr(unique_ptr && u, - typename boost::enable_if_c< + typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && ( @@ -207,7 +207,7 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u).release(), forward(u.get_deleter())) + : ptr_(const_cast&>(u).release(), detail::forward_impl(u.get_deleter())) {} #endif @@ -221,7 +221,7 @@ class unique_ptr //!Requires: Assignment of the deleter D from an rvalue D must not throw an exception. //! - //!Effects: reset(u.release()) followed by a move assignment from u’s deleter to + //!Effects: reset(u.release()) followed by a move assignment from u's deleter to //!this deleter. //! //!Postconditions: This unique_ptr now owns the pointer which u owned, and u no @@ -231,17 +231,17 @@ class unique_ptr //! //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - unique_ptr& operator=(const detail::moved_object& u) + unique_ptr& operator=(detail::moved_object u) { reset(u.get().release()); - ptr_.second() = move(u.get().get_deleter()); + ptr_.second() = detail::move_impl(u.get().get_deleter()); return *this; } #else - unique_ptr(unique_ptr && u) + unique_ptr& operator=(unique_ptr && u) { reset(u.release()); - ptr_.second() = move(u.get_deleter()); + ptr_.second() = detail::move_impl(u.get_deleter()); return *this; } #endif @@ -250,7 +250,7 @@ class unique_ptr //!throw an exception. U* must be implicitly convertible to T*. //! //!Effects: reset(u.release()) followed by a move assignment from - //!u’s deleter to this deleter. If either D or E is + //!u's deleter to this deleter. If either D or E is //!a reference type, then the referenced lvalue deleter participates //!in the move assignment. //! @@ -262,17 +262,17 @@ class unique_ptr //!Throws: nothing. template #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - unique_ptr& operator=(const detail::moved_object >& mu) + unique_ptr& operator=(detail::moved_object > mu) { reset(mu.get().release()); - ptr_.second() = move(mu.get().get_deleter()); + ptr_.second() = detail::move_impl(mu.get().get_deleter()); return *this; } #else - unique_ptr(unique_ptr && u) + unique_ptr& operator=(unique_ptr && u) { reset(u.release()); - ptr_.second() = move(u.get_deleter()); + ptr_.second() = detail::move_impl(u.get_deleter()); return *this; } #endif @@ -356,8 +356,8 @@ class unique_ptr //!Requires: The deleter D is Swappable and will not throw an exception under swap. //! - //!Effects: The stored pointers of this and u are exchanged. The stored deleters are swap’d (unqualified). - //! + //!Effects: The stored pointers of this and u are exchanged. + //! The stored deleters are swapped (unqualified). //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void swap(unique_ptr& u) @@ -597,9 +597,13 @@ struct managed_unique_ptr //!with boost::interproces::deleter from a pointer //!of type T that has been allocated in the passed managed segment template +#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE inline typename detail::return_type ::type >::type +#else +typename managed_unique_ptr::type +#endif make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory) { typename managed_unique_ptr::type to_return diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index 7e48cd7..e43c519 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -200,7 +200,10 @@ class weak_ptr template void _internal_assign(const detail::shared_count & pn2) - { m_pn = pn2; } + { + + m_pn = pn2; + } private: diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index d967809..05f6ff2 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -9,7 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// #include - +#include namespace boost { namespace interprocess { @@ -86,11 +86,23 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, if(now >= abs_time) return false; } + typedef boost::interprocess::scoped_lock InternalLock; //The enter interprocess_mutex guarantees that while executing a notification, //no other thread can execute the do_timed_wait method. { //--------------------------------------------------------------- - boost::interprocess::scoped_lock lock(m_enter_mut); + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_enter_mut, abs_time); + lock = detail::move_impl(dummy); + } + else{ + InternalLock dummy(m_enter_mut); + lock = detail::move_impl(dummy); + } + + if(!lock) + return false; //--------------------------------------------------------------- //We increment the waiting thread count protected so that it will be //always constant when another thread enters the notification logic. @@ -146,7 +158,18 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, //Notification occurred, we will lock the checking interprocess_mutex so that //if a notify_one notification occurs, only one thread can exit //--------------------------------------------------------------- - boost::interprocess::scoped_lock lock(m_check_mut); + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_check_mut, abs_time); + lock = detail::move_impl(dummy); + } + else{ + InternalLock dummy(m_check_mut); + lock = detail::move_impl(dummy); + } + + if(!lock) + return false; //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 ((boost::uint32_t*)&m_command, SLEEP, NOTIFY_ONE); diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index d9ef89f..d3f7e0b 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include //!\file @@ -31,6 +32,8 @@ namespace interprocess { //!A file lock, is a mutual exclusion utility similar to a mutex using a //!file. A file lock has sharable and exclusive locking capabilities and //!can be used with scoped_lock and sharable_lock classes. +//!A file lock can't guarantee synchronization between threads of the same +//!process so just use file locks to synchronize threads from different processes. class file_lock { /// @cond @@ -106,62 +109,6 @@ class file_lock private: file_handle_t m_file_hnd; - bool timed_acquire_file_lock - (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) - { - //Obtain current count and target time - boost::posix_time::ptime now = microsec_clock::universal_time(); - using namespace boost::detail; - - if(now >= abs_time) return false; - - do{ - if(!try_acquire_file_lock(hnd, acquired)) - return false; - - if(acquired) - return true; - else{ - now = microsec_clock::universal_time(); - - if(now >= abs_time){ - acquired = false; - return true; - } - // relinquish current time slice - winapi::sched_yield(); - } - }while (true); - } - - bool timed_acquire_file_lock_sharable - (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) - { - //Obtain current count and target time - boost::posix_time::ptime now = microsec_clock::universal_time(); - using namespace boost::detail; - - if(now >= abs_time) return false; - - do{ - if(!try_acquire_file_lock_sharable(hnd, acquired)) - return false; - - if(acquired) - return true; - else{ - now = microsec_clock::universal_time(); - - if(now >= abs_time){ - acquired = false; - return true; - } - // relinquish current time slice - winapi::sched_yield(); - } - }while (true); - } - bool timed_acquire_file_lock (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) { @@ -172,7 +119,7 @@ class file_lock if(now >= abs_time) return false; do{ - if(!try_acquire_file_lock(hnd, acquired)) + if(!detail::try_acquire_file_lock(hnd, acquired)) return false; if(acquired) @@ -185,7 +132,7 @@ class file_lock return true; } // relinquish current time slice - sleep(0); + detail::thread_yield(); } }while (true); } @@ -200,7 +147,7 @@ class file_lock if(now >= abs_time) return false; do{ - if(!try_acquire_file_lock_sharable(hnd, acquired)) + if(!detail::try_acquire_file_lock_sharable(hnd, acquired)) return false; if(acquired) @@ -213,7 +160,7 @@ class file_lock return true; } // relinquish current time slice - ::sleep(0); + detail::thread_yield(); } }while (true); } @@ -259,7 +206,7 @@ inline bool file_lock::try_lock() inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time) { bool result; - if(!detail::timed_acquire_file_lock(m_file_hnd, result, abs_time)){ + if(!this->timed_acquire_file_lock(m_file_hnd, result, abs_time)){ error_info err(system_error_code()); throw interprocess_exception(err); } @@ -295,7 +242,7 @@ inline bool file_lock::try_lock_sharable() inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time) { bool result; - if(!detail::timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){ + if(!this->timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){ error_info err(system_error_code()); throw interprocess_exception(err); } diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 1ec3f74..59ebbdb 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -50,6 +50,8 @@ namespace interprocess { class named_condition; +//!This class is a condition variable that can be placed in shared memory or +//!memory mapped files. class interprocess_condition { /// @cond diff --git a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp index c600e4c..80c975d 100644 --- a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -266,6 +266,8 @@ class interprocess_upgradable_mutex /// @endcond }; +/// @cond + template const unsigned interprocess_upgradable_mutex::base_constants_t::max_readers; @@ -633,8 +635,9 @@ inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradab return true; } -} //namespace interprocess { +/// @endcond +} //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/sync/math_functions.hpp b/include/boost/interprocess/sync/math_functions.hpp new file mode 100644 index 0000000..54d4126 --- /dev/null +++ b/include/boost/interprocess/sync/math_functions.hpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Stephen Cleary 2000. +// (C) Copyright Ion Gaztanaga 2007-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +// This file is a slightly modified file from Boost.Pool +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP + +#include //BOOST_STATIC_ASSERT +#include //CHAR_BIT + +namespace boost { +namespace interprocess { +namespace detail { + +// Greatest common divisor and least common multiple + +// +// gcd is an algorithm that calculates the greatest common divisor of two +// integers, using Euclid's algorithm. +// +// Pre: A > 0 && B > 0 +// Recommended: A > B +template +inline Integer gcd(Integer A, Integer B) +{ + do + { + const Integer tmp(B); + B = A % B; + A = tmp; + } while (B != 0); + + return A; +} + +// +// lcm is an algorithm that calculates the least common multiple of two +// integers. +// +// Pre: A > 0 && B > 0 +// Recommended: A > B +template +inline Integer lcm(const Integer & A, const Integer & B) +{ + Integer ret = A; + ret /= gcd(A, B); + ret *= B; + return ret; +} + +template +inline Integer log2_ceil(const Integer & A) +{ + Integer i = 0; + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + ++i; + } + return i; +} + +template +inline Integer upper_power_of_2(const Integer & A) +{ + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + } + return power_of_2; +} + +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(Size_t_Bits_Power_2); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + +} // namespace detail +} // namespace interprocess +} // namespace boost + +#endif diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index cfdbe13..cc3b758 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -40,6 +40,9 @@ namespace interprocess { namespace detail{ class interprocess_tester; } /// @endcond +//! A global condition variable that can be created by name. +//! This condition variable is designed to work with named_mutex and +//! can't be placed in shared memory or memory mapped files. class named_condition { /// @cond @@ -146,21 +149,30 @@ class named_condition template void do_wait(Lock& lock) { - lock_inverter inverted_lock(lock); - //unlock internal first to avoid deadlock with near simultaneous waits - scoped_lock > external_unlock(inverted_lock); + //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex()); - this->condition()->wait(internal_lock); + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + + //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock internal_unlock; + internal_lock.swap(internal_unlock); + this->condition()->wait(internal_unlock); } template bool do_timed_wait(Lock& lock, const boost::posix_time::ptime &abs_time) { - //unlock internal first to avoid deadlock with near simultaneous waits - lock_inverter inverted_lock(lock); - scoped_lock > external_unlock(inverted_lock); - scoped_lock internal_lock(*this->mutex()); - return this->condition()->timed_wait(internal_lock, abs_time); + //lock internal before unlocking external to avoid race with a notifier + scoped_lock internal_lock(*this->mutex(), abs_time); + if(!internal_lock) return false; + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + + //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock internal_unlock; + internal_lock.swap(internal_unlock); + return this->condition()->timed_wait(internal_unlock, abs_time); } #endif @@ -174,6 +186,8 @@ class named_condition /// @endcond }; +/// @cond + inline named_condition::~named_condition() {} @@ -320,6 +334,8 @@ inline bool named_condition::timed_wait inline bool named_condition::remove(const char *name) { return shared_memory_object::remove(name); } +/// @endcond + } //namespace interprocess } //namespace boost diff --git a/include/boost/interprocess/sync/named_recursive_mutex.hpp b/include/boost/interprocess/sync/named_recursive_mutex.hpp index 3d62284..9f8b8f3 100644 --- a/include/boost/interprocess/sync/named_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/named_recursive_mutex.hpp @@ -108,6 +108,8 @@ class named_recursive_mutex /// @endcond }; +/// @cond + inline named_recursive_mutex::~named_recursive_mutex() {} @@ -159,6 +161,8 @@ inline bool named_recursive_mutex::timed_lock(const boost::posix_time::ptime &ab inline bool named_recursive_mutex::remove(const char *name) { return shared_memory_object::remove(name); } +/// @endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/sync/named_upgradable_mutex.hpp b/include/boost/interprocess/sync/named_upgradable_mutex.hpp index 853ced4..79c624f 100644 --- a/include/boost/interprocess/sync/named_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -233,6 +233,8 @@ class named_upgradable_mutex /// @endcond }; +/// @cond + inline named_upgradable_mutex::~named_upgradable_mutex() {} @@ -339,8 +341,9 @@ inline bool named_upgradable_mutex::try_unlock_sharable_and_lock_upgradable() inline bool named_upgradable_mutex::remove(const char *name) { return shared_memory_object::remove(name); } -} //namespace interprocess { +/// @endcond +} //namespace interprocess { } //namespace boost { #include diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index 2e4442c..f9e155e 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -122,15 +122,16 @@ class scoped_lock //! to thisscoped_lock with no blocking. If the scop scoped_lock does not //! own the mutex, then neither will this scoped_lock. Only a moved //! scoped_lock's will match this signature. An non-moved scoped_lock - //! can be moved with the expression: "move(lock);". This + //! can be moved with the expression: "detail::move_impl(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit scoped_lock(detail::moved_object > scop) + scoped_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(scop.get().owns()) { mp_mutex = scop.get().release(); } #else - explicit scoped_lock(scoped_lock &&scop) + + scoped_lock(scoped_lock &&scop) : mp_mutex(0), m_locked(scop.owns()) { mp_mutex = scop.release(); } #endif @@ -144,11 +145,11 @@ class scoped_lock //! unlocking upgr. If upgr is unlocked, then this scoped_lock will be //! unlocked as well. Only a moved upgradable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with - //! the expression: "move(lock);" This constructor may block if + //! the expression: "detail::move_impl(lock);" This constructor may block if //! other threads hold a sharable_lock on this mutex (sharable_lock's can //! share ownership with an upgradable_lock). #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit scoped_lock(detail::moved_object > upgr) + scoped_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr.get(); @@ -159,7 +160,7 @@ class scoped_lock mp_mutex = u_lock.release(); } #else - explicit scoped_lock(upgradable_lock &&upgr) + scoped_lock(upgradable_lock &&upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -326,7 +327,7 @@ class scoped_lock //! mutex after the assignment (and scop will not), but the mutex's lock //! count will be decremented by one. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_lock &operator=(detail::moved_object > scop) + scoped_lock &operator=(detail::moved_object scop) { if(this->owns()) this->unlock(); @@ -335,7 +336,7 @@ class scoped_lock return *this; } #else - scoped_lock &operator=(scoped_lock &&scop) + scoped_lock &operator=(scoped_lock &&scop) { if(this->owns()) this->unlock(); diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index 1fbe7d1..705f863 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -127,14 +127,14 @@ class sharable_lock //! sharable_lock with no blocking. If the upgr sharable_lock does not own the mutex, then //! neither will this sharable_lock. Only a moved sharable_lock's will match this //! signature. An non-moved sharable_lock can be moved with the expression: - //! "move(lock);". This constructor does not alter the state of the mutex, + //! "detail::move_impl(lock);". This constructor does not alter the state of the mutex, //! only potentially who owns it. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit sharable_lock(detail::moved_object > upgr) + sharable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(upgr.get().owns()) { mp_mutex = upgr.get().release(); } #else - explicit sharable_lock(sharable_lock &&upgr) + sharable_lock(sharable_lock &&upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } #endif @@ -147,9 +147,9 @@ class sharable_lock //!Notes: If upgr is locked, this constructor will lock this sharable_lock while //! unlocking upgr. Only a moved sharable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with the expression: - //! "move(lock);".*/ + //! "detail::move_impl(lock);".*/ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit sharable_lock(detail::moved_object > upgr) + sharable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr.get(); @@ -160,7 +160,7 @@ class sharable_lock mp_mutex = u_lock.release(); } #else - explicit sharable_lock(upgradable_lock &&upgr) + sharable_lock(upgradable_lock &&upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -181,9 +181,9 @@ class sharable_lock //! to a sharable-ownership of this sharable_lock. //! Only a moved scoped_lock's will match this //! signature. An non-moved scoped_lock can be moved with the expression: - //! "move(lock);".*/ + //! "detail::move_impl(lock);".*/ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit sharable_lock(detail::moved_object > scop) + sharable_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop.get(); @@ -194,7 +194,7 @@ class sharable_lock mp_mutex = e_lock.release(); } #else - explicit sharable_lock(scoped_lock &&scop) + sharable_lock(scoped_lock &&scop) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop; diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 6399400..6b1340d 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -121,14 +121,14 @@ class upgradable_lock //! while unlocking upgr. If upgr is unlocked, then this upgradable_lock will //! be unlocked as well. Only a moved upgradable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with the - //! expression: "move(lock);". This constructor does not alter the + //! expression: "detail::move_impl(lock);". This constructor does not alter the //! state of the mutex, only potentially who owns it. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit upgradable_lock(detail::moved_object > upgr) + upgradable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(upgr.get().owns()) { mp_mutex = upgr.get().release(); } #else - explicit upgradable_lock(upgradable_lock &&upgr) + upgradable_lock(upgradable_lock &&upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } #endif @@ -141,9 +141,9 @@ class upgradable_lock //! to an upgradable-ownership of this upgradable_lock. //! Only a moved sharable_lock's will match this //! signature. An non-moved sharable_lock can be moved with the - //! expression: "move(lock);". + //! expression: "detail::move_impl(lock);". #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit upgradable_lock(detail::moved_object > scop) + upgradable_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop.get(); @@ -154,7 +154,7 @@ class upgradable_lock mp_mutex = u_lock.release(); } #else - explicit upgradable_lock(scoped_lock &&scop) + upgradable_lock(scoped_lock &&scop) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop; diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index c8b3c1a..88165be 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -83,7 +83,7 @@ class windows_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE windows_shared_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else windows_shared_memory(windows_shared_memory &&moved) @@ -95,7 +95,7 @@ class windows_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE windows_shared_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { windows_shared_memory tmp(moved); this->swap(tmp); @@ -104,7 +104,7 @@ class windows_shared_memory #else windows_shared_memory &operator=(windows_shared_memory &&moved) { - windows_shared_memory tmp(move(moved)); + windows_shared_memory tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -143,6 +143,8 @@ class windows_shared_memory /// @endcond }; +/// @cond + inline windows_shared_memory::windows_shared_memory() : m_handle(0) {} @@ -169,7 +171,7 @@ inline mode_t windows_shared_memory::get_mode() const inline bool windows_shared_memory::priv_open_or_create (detail::create_enum_t type, const char *filename, mode_t mode, std::size_t size) { - m_name = filename; + m_name = filename ? filename : ""; unsigned long file_map_access = 0; unsigned long map_access = 0; @@ -235,6 +237,16 @@ inline void windows_shared_memory::priv_close() } } +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/proj/conceptgcc/MakeAll b/proj/conceptgcc/MakeAll index c941303..1770e5e 100644 --- a/proj/conceptgcc/MakeAll +++ b/proj/conceptgcc/MakeAll @@ -1,35 +1,35 @@ - -#ifndef CC -CC=i686-pc-cygwin-conceptg++.exe -#endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/conceptgcc/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSDOC_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSDOC_OUT := $(patsubst ../../example/%.cpp, ../../bin/conceptgcc/ex_%.out, $(INTERPROCESSDOC_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSDOC_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/conceptgcc - -../../bin/conceptgcc/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -../../bin/conceptgcc/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -clean: - rm -f *.o - rm -f ../../bin/conceptgcc/* + +#ifndef CC +CC=i686-pc-cygwin-conceptg++.exe +#endif + +BOOST_ROOT=../../../.. + +INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) +INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/conceptgcc/test_%.out, $(INTERPROCESSTEST_CPP)) + +INTERPROCESSDOC_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSDOC_OUT := $(patsubst ../../example/%.cpp, ../../bin/conceptgcc/ex_%.out, $(INTERPROCESSDOC_CPP)) + +LIBDIR:= ../../../../stage/lib + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSDOC_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/conceptgcc + +../../bin/conceptgcc/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +../../bin/conceptgcc/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +clean: + rm -f *.o + rm -f ../../bin/conceptgcc/* diff --git a/proj/cygwin/MakeAll b/proj/cygwin/MakeAll index 4073873..72e7b80 100644 --- a/proj/cygwin/MakeAll +++ b/proj/cygwin/MakeAll @@ -1,33 +1,33 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/cygwin/test_%.out, $(INTERPROCESSTEST_CPP)) - -#INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -#INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/cygwin/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSEXAMPLE_OUT) $(INTERPROCESSTEST_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/cygwin - -../../bin/cygwin/test_%.out: ../../test/%.cpp - $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -#../../bin/cygwin/ex_%.out: ../../example/%.cpp -# $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - - -clean: - rm -f *.o - rm -f ../../bin/cygwin/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/cygwin/test_%.out, $(INTERPROCESSTEST_CPP)) + +#INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +#INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/cygwin/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +LIBDIR:= ../../../../stage/lib + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSEXAMPLE_OUT) $(INTERPROCESSTEST_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/cygwin + +../../bin/cygwin/test_%.out: ../../test/%.cpp + $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +#../../bin/cygwin/ex_%.out: ../../example/%.cpp +# $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + + +clean: + rm -f *.o + rm -f ../../bin/cygwin/* diff --git a/proj/linux/MakeAll b/proj/linux/MakeAll index f0c361b..9f0962f 100644 --- a/proj/linux/MakeAll +++ b/proj/linux/MakeAll @@ -1,32 +1,32 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. -BOOST_LIBS=/usr/local/lib - - -INTERPROCESS_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESS_OUT := $(patsubst ../../test/%.cpp, ../../bin/linux/test_%.out, $(INTERPROCESS_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/linux/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -.PHONY: createdir clean - -all: createdir $(INTERPROCESS_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/linux - -../../bin/linux/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ - -../../bin/linux/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ - -clean: - rm -f *.o - rm -f ../../bin/linux/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. +BOOST_LIBS=/usr/local/lib + + +INTERPROCESS_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESS_OUT := $(patsubst ../../test/%.cpp, ../../bin/linux/test_%.out, $(INTERPROCESS_CPP)) + +INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/linux/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +.PHONY: createdir clean + +all: createdir $(INTERPROCESS_OUT) $(INTERPROCESSEXAMPLE_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/linux + +../../bin/linux/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ + +../../bin/linux/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ + +clean: + rm -f *.o + rm -f ../../bin/linux/* diff --git a/proj/mingw/MakeAll b/proj/mingw/MakeAll index 1903c1b..0b23825 100644 --- a/proj/mingw/MakeAll +++ b/proj/mingw/MakeAll @@ -1,35 +1,35 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/mingw/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/mingw/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/mingw - -../../bin/mingw/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -../../bin/mingw/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -clean: - rm -f *.o - rm -f ../../bin/mingw/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. + +INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) +INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/mingw/test_%.out, $(INTERPROCESSTEST_CPP)) + +INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/mingw/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +LIBDIR:= ../../../../stage/lib + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/mingw + +../../bin/mingw/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +../../bin/mingw/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +clean: + rm -f *.o + rm -f ../../bin/mingw/* diff --git a/proj/qnx/MakeAll b/proj/qnx/MakeAll index d941efd..b98dc49 100644 --- a/proj/qnx/MakeAll +++ b/proj/qnx/MakeAll @@ -1,33 +1,33 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/qnx/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/qnx/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/qnx - -../../bin/qnx/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ - -../../bin/qnx/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ - -clean: - rm -f *.o - rm -f ../../bin/qnx/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. + +INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) +INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/qnx/test_%.out, $(INTERPROCESSTEST_CPP)) + +INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/qnx/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/qnx + +../../bin/qnx/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ + +../../bin/qnx/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ + +clean: + rm -f *.o + rm -f ../../bin/qnx/* diff --git a/proj/to-do.txt b/proj/to-do.txt new file mode 100644 index 0000000..785bafa --- /dev/null +++ b/proj/to-do.txt @@ -0,0 +1,46 @@ +-> Implement zero_memory flag for allocation_command + +-> The general allocation funtion can be improved with some fixed size allocation bins. + +-> Adapt error reporting to TR1 system exceptions + +-> Improve exception messages + +-> Movability of containers should depend on the no-throw guarantee of allocators copy constructor + +-> Check self-assignment for vectors + +-> Update writing a new memory allocator explaining new functions (like alignment) + +-> private node allocators could take the number of nodes as a runtime parameter. + +-> Explain how to build intrusive indexes. + +-> Add intrusive index types as available indexes. + +-> Add maximum alignment allocation limit in PageSize bytes. Otherwise, we can't + guarantee alignment for process-shared allocations. + +-> Add default algorithm and index types. The user does not need to know how are + they implemented. + +-> Pass max size check in allocation to node pools + +-> Use in-place expansion capabilities to shrink_to_fit and reserve functions + from iunordered_index. + +-> Keep an eye on container iterator constness issue to bring Interprocess containers up-to-date. + +-> change unique_ptr to avoid using compressed_pair + +-> Improve unique_ptr test to test move assignment and other goodies like assigment from null + +-> barrier_test fails on MacOS X on PowerPC. + +-> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ + +-> add contiguous_elements option to burst allocation + +-> Completely erase is_movable in code and tests for compilers with rvalue reference + +-> named_xxx classes and file lock should be movable \ No newline at end of file diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index 4758668..7f00fbe 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -1,847 +1,935 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_mapping_test", "shared_memory_mappable_test.vcproj", "{5CE18C83-6025-36FE-A4F7-BA09176D3A11}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_test", "shared_memory_test.vcproj", "{5E2838CC-0916-8F4E-A4F7-93506BA0D310}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_ptr_test", "shared_ptr_test.vcproj", "{5371C383-6092-1238-A877-BAEB37867609}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_test", "string_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D4A792607}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upgradable_mutex_test", "upgradable_mutex.vcproj", "{4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_buffer_test", "user_buffer_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792603}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vectorstream_test", "vectorstream_test.vcproj", "{58CCE183-6032-12FE-A4F7-BA893A767601}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_test", "vector_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_condition_test", "named_condition_test.vcproj", "{58CC2563-6092-48FE-FAF7-BA046A792658}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexA", "doc_anonymous_mutexA.vcproj", "{58C1B183-9026-4E63-12F2-005412200054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexB", "doc_anonymous_mutexB.vcproj", "{58C1B183-9026-4E63-12F2-005202441254}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_mutex", "doc_named_mutex.vcproj", "{58C181B3-9516-463E-2F12-122155400054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionA", "doc_anonymous_conditionA.vcproj", "{5C1B8183-0296-4F83-1F22-001005220544}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionB", "doc_anonymous_conditionB.vcproj", "{58C1FE83-2906-E643-2F12-024410052254}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionA", "doc_named_conditionA.vcproj", "{58EB1CB3-1354-364E-12F2-154356612054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionB", "doc_named_conditionB.vcproj", "{58181CB3-5134-634E-12F2-155435622054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreA", "doc_anonymous_semaphoreA.vcproj", "{5CB81183-29FB-F843-24FF-022050100544}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreB", "doc_anonymous_semaphoreB.vcproj", "{58FBE8C3-9026-FAB2-E643-000522441254}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_upgradable_mutex_test", "named_upgradable_mutex.vcproj", "{48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexA", "doc_anonymous_upgradable_mutexA.vcproj", "{5C18831B-F162-FA96-E6C3-FA5122040054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexB", "doc_anonymous_upgradable_mutexB.vcproj", "{5C1B1043-1EFF-2793-4E63-245241283054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueA", "doc_message_queueA.vcproj", "{51B189C3-4E63-9026-12F2-12200AF54054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueB", "doc_message_queueB.vcproj", "{5C1B1813-12C2-0296-4E63-244549126520}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cont", "doc_cont.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792653}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contA", "doc_contA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contB", "doc_contB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792651}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory", "doc_shared_memory.vcproj", "{58CCE183-6032-12FE-4FC7-83A79F760B61}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_test", "unique_ptr_test.vcproj", "{571C3383-6092-A877-1238-B3786BAE7605}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_containers", "doc_move_containers.vcproj", "{58C1B183-0296-EA42-EF04-005120054104}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_index_allocation_test", "map_index_allocation_test.vcproj", "{588CCD13-2962-83FE-F4B7-92230DB73629}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_map_index_allocation_test", "flat_map_index_allocation_test.vcproj", "{51D8E9C3-2D65-48FE-3AA7-7922C0E36329}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iset_index_allocation_test", "iset_index_allocation_test.vcproj", "{58BD1CC3-6972-F3F7-84BE-0DB736035922}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iunordered_set_index_allocation_test", "iunordered_set_index_allocation_test.vcproj", "{5BD1C7C3-3F7F-6972-84BE-B731D9236035}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory2", "doc_shared_memory2.vcproj", "{58CE1D83-F31E-4FD7-6132-8A79F6307B61}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping2", "doc_file_mapping2.vcproj", "{5CE19883-F413-7EFD-6342-B79639F7B611}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping", "doc_file_mapping.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_map", "doc_map.vcproj", "{59CEC183-8192-8F6D-4FB7-BA260A79D352}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_test", "windows_shared_memory_test.vcproj", "{E385C28C-0691-4FA7-F48E-935BA0D06310}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_mapping_test", "windows_shared_memory_mapping_test.vcproj", "{518CE8C3-6512-FA75-46EF-B917A3A116D1}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_windows_shared_memory_test", "managed_windows_shared_memory.vcproj", "{5D18CE83-1926-7AE4-FE94-B606D9B23131}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_pool_test", "adaptive_pool_test.vcproj", "{58CE1D84-1962-4FE9-BA0D-A4F7973A4652}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_adaptive_pool_test", "cached_adaptive_pool_test.vcproj", "{5188E3CE-2964-F43E-FB87-B037AC692D59}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_adaptive_pool_test", "private_adaptive_pool_test.vcproj", "{5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_allocator", "doc_allocator.vcproj", "{581B1C83-4E12-9526-020F-012482540054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_node_allocator", "doc_node_allocator.vcproj", "{51B17C83-E172-5396-0FA2-825472008554}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_node_allocator", "doc_private_node_allocator.vcproj", "{2B75C833-17D2-4956-A23F-820854254175}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_node_allocator", "doc_cached_node_allocator.vcproj", "{283AD375-7D12-5866-23BF-854308651275}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_adaptive_pool", "doc_adaptive_pool.vcproj", "{57C832B1-17D2-9537-FA12-827220448554}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_adaptive_pool", "doc_cached_adaptive_pool.vcproj", "{536C8251-7E12-9537-A1E2-822073258554}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_adaptive_pool", "doc_private_adaptive_pool.vcproj", "{83258CB1-127E-9375-F872-8324A1054454}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_raw_allocation", "doc_managed_raw_allocation.vcproj", "{5198EFC3-2731-F34E-4FD8-1859AC94F761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_aligned_allocation", "doc_managed_aligned_allocation.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_interprocesslib", "interprocesslib.vcproj", "{FFAA56F1-32EC-4B22-B6BD-95A311A67C35}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory", "doc_windows_shared_memory.vcproj", "{5E17C9C3-1362-2E1E-C84F-8A76B6739F21}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory2", "doc_windows_shared_memory2.vcproj", "{5E1D6C83-31DE-4F6F-6132-87A9FB663041}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_node_pool_test", "adaptive_node_pool_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_pool_test", "node_pool_test.vcproj", "{8A519DC3-6092-A4FE-F748-BA91328D6522}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deque_test", "deque_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792655}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "barrier_test", "barrier_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792661}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bufferstream_test", "bufferstream_test.vcproj", "{58C183CE-6203-FE12-A237-BA8976695960}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_node_allocator_test", "cached_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792659}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_node_allocator_test", "private_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792620}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_allocator_test", "node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792622}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_mutex_test", "named_mutex_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792625}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_recursive_mutex_test", "named_recursive_mutex_test.vcproj", "{5C83CE18-4F48-A7FE-6092-B7920AD3A624}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_semaphore_test", "named_semaphore_test.vcproj", "{58CCE283-1609-48FE-A4F7-BA0D3A793523}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_heap_memory", "doc_managed_heap_memory.vcproj", "{58CCE183-6092-48FE-A4FC-BA0D3A792647}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "allocexcept_test", "allocexcept_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792662}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "condition_test", "condition_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792658}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_test", "data_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792657}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_bufferstream", "doc_bufferstream.vcproj", "{58C1B183-9026-4E12-00F2-001200540054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_intrusive", "doc_intrusive.vcproj", "{5E18CC83-6092-48FE-A677-B832A0D3A650}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageA", "doc_ipc_messageA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageB", "doc_ipc_messageB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792648}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_mapped_file", "doc_managed_mapped_file.vcproj", "{58CCE183-5091-48FE-A4FC-BA0D3A792446}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocA", "doc_named_allocA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocB", "doc_named_allocB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792644}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_offset_ptr", "doc_offset_ptr.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792643}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_scoped_ptr", "doc_scoped_ptr.vcproj", "{58CC8E13-0962-8F4E-77A6-BD3A6832A042}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_vectorstream", "doc_vectorstream.vcproj", "{58C1B183-9260-4E8F-F200-000000000041}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_where_allocate", "doc_where_allocate.vcproj", "{58CCE183-6092-48FE-A677-BA0D3A832640}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_mapping_test", "file_mapping_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792638}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792637}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intrusive_ptr_test", "intrusive_ptr_test.vcproj", "{5821C383-6092-12FE-A877-BA0D33467633}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_ex.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_mapped_file_test", "managed_mapped_file_test.vcproj", "{5CCE1883-0926-F7A4-8FE4-BA0606D92331}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapped_file_test", "mapped_file_test.vcproj", "{5C6D9CE1-2609-F7A4-8FE4-BA0883602330}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_algorithm_test", "memory_algorithm_test.vcproj", "{58E18CC3-6092-8F4E-A3E7-A792230D3629}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_queue_test", "message_queue.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792628}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mutex_test", "mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A27}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "null_index_test", "null_index_test.vcproj", "{0000058C-0000-0000-0000-000000000021}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recursive_mutex_test", "recursive_mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A14}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "semaphore_test", "semaphore_test.vcproj", "{5CE28C83-48FE-1676-4FA7-B50D3A76A013}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_multiple_allocation", "doc_managed_multiple_allocation.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_allocation_command", "doc_managed_allocation_command.vcproj", "{5189DEA3-3261-F33E-47ED-83BC69F66061}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_construction_info", "doc_managed_construction_info.vcproj", "{5C82D1D3-3861-3AF1-03EF-89AED4716761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr_explicit", "doc_shared_ptr_explicit.vcproj", "{4E887AC3-F8EA-6923-A744-C264A398C913}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unique_ptr", "doc_unique_ptr.vcproj", "{589C2EB3-8A57-1862-F4EA-A6B14C7329A3}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr", "doc_shared_ptr.vcproj", "{51CE89A3-6092-F4EA-48A7-B4B9AC326093}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_shared_memory_test", "managed_shared_memory.vcproj", "{58DF28E3-0926-F47A-E28A-B03A4D619631}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_grow", "doc_managed_grow.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "offset_ptr_test", "offset_ptr_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.ActiveCfg = Debug|Win32 - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.Build.0 = Debug|Win32 - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.ActiveCfg = Release|Win32 - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.Build.0 = Release|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.ActiveCfg = Debug|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.Build.0 = Debug|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.ActiveCfg = Release|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.Build.0 = Release|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Debug.ActiveCfg = Debug|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Debug.Build.0 = Debug|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Release.ActiveCfg = Release|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.ActiveCfg = Debug|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.Build.0 = Debug|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.ActiveCfg = Release|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.Build.0 = Release|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.Build.0 = Debug|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.ActiveCfg = Release|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.Build.0 = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.ActiveCfg = Debug|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.Build.0 = Debug|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.ActiveCfg = Release|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.Build.0 = Release|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Debug.Build.0 = Debug|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Release.ActiveCfg = Release|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Release.Build.0 = Release|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Debug.Build.0 = Debug|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Release.ActiveCfg = Release|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Release.Build.0 = Release|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Debug.ActiveCfg = Debug|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Debug.Build.0 = Debug|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Release.ActiveCfg = Release|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Release.Build.0 = Release|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Debug.ActiveCfg = Debug|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Debug.Build.0 = Debug|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Release.ActiveCfg = Release|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Release.Build.0 = Release|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Debug.ActiveCfg = Debug|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Debug.Build.0 = Debug|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Release.ActiveCfg = Release|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Release.Build.0 = Release|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Debug.ActiveCfg = Debug|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Debug.Build.0 = Debug|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Release.ActiveCfg = Release|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Release.Build.0 = Release|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Debug.ActiveCfg = Debug|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Debug.Build.0 = Debug|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Release.ActiveCfg = Release|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Release.Build.0 = Release|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Debug.ActiveCfg = Debug|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Debug.Build.0 = Debug|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Release.ActiveCfg = Release|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Release.Build.0 = Release|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.ActiveCfg = Debug|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.Build.0 = Debug|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Release.ActiveCfg = Release|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Release.Build.0 = Release|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.ActiveCfg = Debug|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.Build.0 = Debug|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.ActiveCfg = Release|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.Build.0 = Release|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.ActiveCfg = Debug|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.Build.0 = Debug|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.ActiveCfg = Release|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.Build.0 = Release|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.ActiveCfg = Debug|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.Build.0 = Debug|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Release.ActiveCfg = Release|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Release.Build.0 = Release|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.ActiveCfg = Debug|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.Build.0 = Debug|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Release.ActiveCfg = Release|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Release.Build.0 = Release|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Debug.ActiveCfg = Debug|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Debug.Build.0 = Debug|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Release.ActiveCfg = Release|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.Build.0 = Release|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.Build.0 = Debug|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.ActiveCfg = Release|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.Build.0 = Release|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Debug.ActiveCfg = Debug|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Debug.Build.0 = Debug|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Release.ActiveCfg = Release|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Release.Build.0 = Release|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Debug.Build.0 = Debug|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Release.ActiveCfg = Release|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Release.Build.0 = Release|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.ActiveCfg = Debug|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.Build.0 = Debug|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.ActiveCfg = Release|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.Build.0 = Release|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.ActiveCfg = Debug|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.Build.0 = Debug|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.ActiveCfg = Release|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.Build.0 = Release|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.ActiveCfg = Debug|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.Build.0 = Debug|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.ActiveCfg = Release|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.Build.0 = Release|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.ActiveCfg = Debug|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.Build.0 = Debug|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.ActiveCfg = Release|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.Build.0 = Release|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.ActiveCfg = Debug|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.Build.0 = Debug|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.ActiveCfg = Release|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.Build.0 = Release|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.ActiveCfg = Debug|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.Build.0 = Debug|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.ActiveCfg = Release|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.Build.0 = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.ActiveCfg = Debug|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.Build.0 = Debug|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.ActiveCfg = Release|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.Build.0 = Release|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.ActiveCfg = Debug|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.Build.0 = Debug|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.ActiveCfg = Release|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.Build.0 = Release|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.ActiveCfg = Debug|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.Build.0 = Debug|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.ActiveCfg = Release|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.Build.0 = Release|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.ActiveCfg = Debug|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.Build.0 = Debug|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.ActiveCfg = Release|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.Build.0 = Release|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.ActiveCfg = Debug|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.Build.0 = Debug|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.ActiveCfg = Release|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.Build.0 = Release|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.ActiveCfg = Debug|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.Build.0 = Debug|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.ActiveCfg = Release|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.Build.0 = Release|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.ActiveCfg = Debug|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.Build.0 = Debug|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.ActiveCfg = Release|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.Build.0 = Release|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Debug.ActiveCfg = Debug|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Debug.Build.0 = Debug|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Release.ActiveCfg = Release|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Release.Build.0 = Release|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Debug.ActiveCfg = Debug|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Debug.Build.0 = Debug|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Release.ActiveCfg = Release|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Release.Build.0 = Release|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Debug.ActiveCfg = Debug|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Debug.Build.0 = Debug|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Release.ActiveCfg = Release|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Release.Build.0 = Release|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Debug.ActiveCfg = Debug|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Debug.Build.0 = Debug|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Release.ActiveCfg = Release|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Release.Build.0 = Release|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Debug.ActiveCfg = Debug|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Debug.Build.0 = Debug|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Release.ActiveCfg = Release|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Release.Build.0 = Release|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Debug.ActiveCfg = Debug|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Debug.Build.0 = Debug|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Release.ActiveCfg = Release|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Release.Build.0 = Release|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Debug.ActiveCfg = Debug|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Debug.Build.0 = Debug|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Release.ActiveCfg = Release|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Release.Build.0 = Release|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.ActiveCfg = Debug|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.Build.0 = Debug|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.ActiveCfg = Release|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.Build.0 = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.ActiveCfg = Debug|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.Build.0 = Debug|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.ActiveCfg = Release|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.Build.0 = Release|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.ActiveCfg = Debug|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.Build.0 = Debug|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.ActiveCfg = Release|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.Build.0 = Release|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.ActiveCfg = Debug|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.Build.0 = Debug|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.ActiveCfg = Release|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.Build.0 = Release|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.ActiveCfg = Debug|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.Build.0 = Debug|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.ActiveCfg = Release|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.Build.0 = Release|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Debug.ActiveCfg = Debug|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Debug.Build.0 = Debug|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Release.ActiveCfg = Release|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.Build.0 = Release|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.ActiveCfg = Debug|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.Build.0 = Debug|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.ActiveCfg = Release|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.Build.0 = Release|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.ActiveCfg = Debug|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.Build.0 = Debug|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.ActiveCfg = Release|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.Build.0 = Release|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Debug.Build.0 = Debug|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Release.ActiveCfg = Release|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Release.Build.0 = Release|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.ActiveCfg = Debug|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.Build.0 = Debug|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.ActiveCfg = Release|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.Build.0 = Release|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.Build.0 = Debug|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.ActiveCfg = Release|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.Build.0 = Release|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.ActiveCfg = Debug|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.Build.0 = Debug|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.ActiveCfg = Release|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.Build.0 = Release|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Debug.Build.0 = Debug|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Release.ActiveCfg = Release|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Debug.ActiveCfg = Debug|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Debug.Build.0 = Debug|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Release.ActiveCfg = Release|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.ActiveCfg = Debug|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.Build.0 = Debug|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.ActiveCfg = Release|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.Build.0 = Release|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.ActiveCfg = Debug|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.Build.0 = Debug|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.ActiveCfg = Release|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.Build.0 = Release|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.ActiveCfg = Debug|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.Build.0 = Debug|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.ActiveCfg = Release|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.Build.0 = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.ActiveCfg = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.Build.0 = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.ActiveCfg = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.Build.0 = Release|Win32 - {0000058C-0000-0000-0000-000000000021}.Debug.ActiveCfg = Debug|Win32 - {0000058C-0000-0000-0000-000000000021}.Debug.Build.0 = Debug|Win32 - {0000058C-0000-0000-0000-000000000021}.Release.ActiveCfg = Release|Win32 - {0000058C-0000-0000-0000-000000000021}.Release.Build.0 = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.ActiveCfg = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.Build.0 = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.ActiveCfg = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.Build.0 = Release|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.ActiveCfg = Debug|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.Build.0 = Debug|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.ActiveCfg = Release|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.Build.0 = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.ActiveCfg = Debug|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.Build.0 = Debug|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.ActiveCfg = Release|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.Build.0 = Release|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.ActiveCfg = Debug|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.Build.0 = Debug|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.ActiveCfg = Release|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.Build.0 = Release|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.ActiveCfg = Debug|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.Build.0 = Debug|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.ActiveCfg = Release|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.Build.0 = Release|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.ActiveCfg = Debug|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.Build.0 = Debug|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.ActiveCfg = Release|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.Build.0 = Release|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.ActiveCfg = Debug|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.Build.0 = Debug|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.ActiveCfg = Release|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.Build.0 = Release|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.ActiveCfg = Debug|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.Build.0 = Debug|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.ActiveCfg = Release|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.Build.0 = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_mapping_test", "shared_memory_mappable_test.vcproj", "{5CE18C83-6025-36FE-A4F7-BA09176D3A11}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_test", "shared_memory_test.vcproj", "{5E2838CC-0916-8F4E-A4F7-93506BA0D310}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_ptr_test", "shared_ptr_test.vcproj", "{5371C383-6092-1238-A877-BAEB37867609}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_test", "string_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D4A792607}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upgradable_mutex_test", "upgradable_mutex.vcproj", "{4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_buffer_test", "user_buffer_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792603}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vectorstream_test", "vectorstream_test.vcproj", "{58CCE183-6032-12FE-A4F7-BA893A767601}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_test", "vector_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_condition_test", "named_condition_test.vcproj", "{58CC2563-6092-48FE-FAF7-BA046A792658}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexA", "doc_anonymous_mutexA.vcproj", "{58C1B183-9026-4E63-12F2-005412200054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexB", "doc_anonymous_mutexB.vcproj", "{58C1B183-9026-4E63-12F2-005202441254}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_mutex", "doc_named_mutex.vcproj", "{58C181B3-9516-463E-2F12-122155400054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionA", "doc_anonymous_conditionA.vcproj", "{5C1B8183-0296-4F83-1F22-001005220544}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionB", "doc_anonymous_conditionB.vcproj", "{58C1FE83-2906-E643-2F12-024410052254}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionA", "doc_named_conditionA.vcproj", "{58EB1CB3-1354-364E-12F2-154356612054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionB", "doc_named_conditionB.vcproj", "{58181CB3-5134-634E-12F2-155435622054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreA", "doc_anonymous_semaphoreA.vcproj", "{5CB81183-29FB-F843-24FF-022050100544}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreB", "doc_anonymous_semaphoreB.vcproj", "{58FBE8C3-9026-FAB2-E643-000522441254}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_upgradable_mutex_test", "named_upgradable_mutex.vcproj", "{48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexA", "doc_anonymous_upgradable_mutexA.vcproj", "{5C18831B-F162-FA96-E6C3-FA5122040054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexB", "doc_anonymous_upgradable_mutexB.vcproj", "{5C1B1043-1EFF-2793-4E63-245241283054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueA", "doc_message_queueA.vcproj", "{51B189C3-4E63-9026-12F2-12200AF54054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueB", "doc_message_queueB.vcproj", "{5C1B1813-12C2-0296-4E63-244549126520}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cont", "doc_cont.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792653}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contA", "doc_contA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contB", "doc_contB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792651}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory", "doc_shared_memory.vcproj", "{58CCE183-6032-12FE-4FC7-83A79F760B61}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_test", "unique_ptr_test.vcproj", "{571C3383-6092-A877-1238-B3786BAE7605}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_containers", "doc_move_containers.vcproj", "{58C1B183-0296-EA42-EF04-005120054104}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_index_allocation_test", "map_index_allocation_test.vcproj", "{588CCD13-2962-83FE-F4B7-92230DB73629}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_map_index_allocation_test", "flat_map_index_allocation_test.vcproj", "{51D8E9C3-2D65-48FE-3AA7-7922C0E36329}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iset_index_allocation_test", "iset_index_allocation_test.vcproj", "{58BD1CC3-6972-F3F7-84BE-0DB736035922}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iunordered_set_index_allocation_test", "iunordered_set_index_allocation_test.vcproj", "{5BD1C7C3-3F7F-6972-84BE-B731D9236035}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory2", "doc_shared_memory2.vcproj", "{58CE1D83-F31E-4FD7-6132-8A79F6307B61}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping2", "doc_file_mapping2.vcproj", "{5CE19883-F413-7EFD-6342-B79639F7B611}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping", "doc_file_mapping.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_map", "doc_map.vcproj", "{59CEC183-8192-8F6D-4FB7-BA260A79D352}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_test", "windows_shared_memory_test.vcproj", "{E385C28C-0691-4FA7-F48E-935BA0D06310}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_mapping_test", "windows_shared_memory_mapping_test.vcproj", "{518CE8C3-6512-FA75-46EF-B917A3A116D1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_windows_shared_memory_test", "managed_windows_shared_memory.vcproj", "{5D18CE83-1926-7AE4-FE94-B606D9B23131}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_pool_test", "adaptive_pool_test.vcproj", "{58CE1D84-1962-4FE9-BA0D-A4F7973A4652}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_adaptive_pool_test", "cached_adaptive_pool_test.vcproj", "{5188E3CE-2964-F43E-FB87-B037AC692D59}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_adaptive_pool_test", "private_adaptive_pool_test.vcproj", "{5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_allocator", "doc_allocator.vcproj", "{581B1C83-4E12-9526-020F-012482540054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_node_allocator", "doc_node_allocator.vcproj", "{51B17C83-E172-5396-0FA2-825472008554}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_node_allocator", "doc_private_node_allocator.vcproj", "{2B75C833-17D2-4956-A23F-820854254175}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_node_allocator", "doc_cached_node_allocator.vcproj", "{283AD375-7D12-5866-23BF-854308651275}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_adaptive_pool", "doc_adaptive_pool.vcproj", "{57C832B1-17D2-9537-FA12-827220448554}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_adaptive_pool", "doc_cached_adaptive_pool.vcproj", "{536C8251-7E12-9537-A1E2-822073258554}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_adaptive_pool", "doc_private_adaptive_pool.vcproj", "{83258CB1-127E-9375-F872-8324A1054454}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_raw_allocation", "doc_managed_raw_allocation.vcproj", "{5198EFC3-2731-F34E-4FD8-1859AC94F761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_aligned_allocation", "doc_managed_aligned_allocation.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_interprocesslib", "interprocesslib.vcproj", "{FFAA56F1-32EC-4B22-B6BD-95A311A67C35}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory", "doc_windows_shared_memory.vcproj", "{5E17C9C3-1362-2E1E-C84F-8A76B6739F21}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory2", "doc_windows_shared_memory2.vcproj", "{5E1D6C83-31DE-4F6F-6132-87A9FB663041}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_node_pool_test", "adaptive_node_pool_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_pool_test", "node_pool_test.vcproj", "{8A519DC3-6092-A4FE-F748-BA91328D6522}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deque_test", "deque_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792655}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "barrier_test", "barrier_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792661}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bufferstream_test", "bufferstream_test.vcproj", "{58C183CE-6203-FE12-A237-BA8976695960}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_node_allocator_test", "cached_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792659}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_node_allocator_test", "private_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792620}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_allocator_test", "node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792622}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_mutex_test", "named_mutex_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792625}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_recursive_mutex_test", "named_recursive_mutex_test.vcproj", "{5C83CE18-4F48-A7FE-6092-B7920AD3A624}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_semaphore_test", "named_semaphore_test.vcproj", "{58CCE283-1609-48FE-A4F7-BA0D3A793523}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_heap_memory", "doc_managed_heap_memory.vcproj", "{58CCE183-6092-48FE-A4FC-BA0D3A792647}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "allocexcept_test", "allocexcept_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792662}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "condition_test", "condition_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792658}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_test", "data_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792657}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_bufferstream", "doc_bufferstream.vcproj", "{58C1B183-9026-4E12-00F2-001200540054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_intrusive", "doc_intrusive.vcproj", "{5E18CC83-6092-48FE-A677-B832A0D3A650}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageA", "doc_ipc_messageA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageB", "doc_ipc_messageB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792648}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_mapped_file", "doc_managed_mapped_file.vcproj", "{58CCE183-5091-48FE-A4FC-BA0D3A792446}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocA", "doc_named_allocA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocB", "doc_named_allocB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792644}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_offset_ptr", "doc_offset_ptr.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792643}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_scoped_ptr", "doc_scoped_ptr.vcproj", "{58CC8E13-0962-8F4E-77A6-BD3A6832A042}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_vectorstream", "doc_vectorstream.vcproj", "{58C1B183-9260-4E8F-F200-000000000041}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_where_allocate", "doc_where_allocate.vcproj", "{58CCE183-6092-48FE-A677-BA0D3A832640}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_mapping_test", "file_mapping_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792638}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792637}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intrusive_ptr_test", "intrusive_ptr_test.vcproj", "{5821C383-6092-12FE-A877-BA0D33467633}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_ex.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_mapped_file_test", "managed_mapped_file_test.vcproj", "{5CCE1883-0926-F7A4-8FE4-BA0606D92331}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapped_file_test", "mapped_file_test.vcproj", "{5C6D9CE1-2609-F7A4-8FE4-BA0883602330}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_algorithm_test", "memory_algorithm_test.vcproj", "{58E18CC3-6092-8F4E-A3E7-A792230D3629}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_queue_test", "message_queue.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792628}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mutex_test", "mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A27}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "null_index_test", "null_index_test.vcproj", "{0000058C-0000-0000-0000-000000000021}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recursive_mutex_test", "recursive_mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A14}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "semaphore_test", "semaphore_test.vcproj", "{5CE28C83-48FE-1676-4FA7-B50D3A76A013}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_multiple_allocation", "doc_managed_multiple_allocation.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_allocation_command", "doc_managed_allocation_command.vcproj", "{5189DEA3-3261-F33E-47ED-83BC69F66061}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_construction_info", "doc_managed_construction_info.vcproj", "{5C82D1D3-3861-3AF1-03EF-89AED4716761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr_explicit", "doc_shared_ptr_explicit.vcproj", "{4E887AC3-F8EA-6923-A744-C264A398C913}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unique_ptr", "doc_unique_ptr.vcproj", "{589C2EB3-8A57-1862-F4EA-A6B14C7329A3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr", "doc_shared_ptr.vcproj", "{51CE89A3-6092-F4EA-48A7-B4B9AC326093}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_shared_memory_test", "managed_shared_memory.vcproj", "{58DF28E3-0926-F47A-E28A-B03A4D619631}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_grow", "doc_managed_grow.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "offset_ptr_test", "offset_ptr_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_shared_memory", "doc_anonymous_shared_memory.vcproj", "{6DE178C3-12FE-6032-4FC7-879B63B9F651}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anonymous_shared_memory_test", "anonymous_shared_memory_test.vcproj", "{58DE8A13-4FA7-6252-36FE-B3A0A6D92812}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unordered_map", "doc_unordered_map.vcproj", "{9C185DF3-B75F-1928-8F6D-735108AABE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_multi_index", "doc_multi_index.vcproj", "{918C5DF3-1928-B73F-F626-7358518CBE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_test", "unordered_test.vcproj", "{C3CE1183-09F2-A46A-4FE6-D06BA7923A02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_index_test", "multi_index_test.vcproj", "{9285DFD3-1928-F662-CB73-73518CB53A62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_lock_test", "file_lock_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792639}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intersegment_ptr_test", "intersegment_ptr_test.vcproj", "{5E81CD01-4FA2-2A96-84FE-DA631CA20962}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_copy_on_write", "doc_managed_copy_on_write.vcproj", "{8E0C437E-3613-FD46-F3AE-876A0731CA85}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "enable_shared_from_this_test", "enable_shared_from_this_test.vcproj", "{571C3483-87C7-6921-1238-B086B3E766C9}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_complex_map", "doc_complex_map.vcproj", "{5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.ActiveCfg = Debug|Win32 + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.Build.0 = Debug|Win32 + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.ActiveCfg = Release|Win32 + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.Build.0 = Release|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.ActiveCfg = Debug|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.Build.0 = Debug|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.ActiveCfg = Release|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.Build.0 = Release|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Debug.ActiveCfg = Debug|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Debug.Build.0 = Debug|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Release.ActiveCfg = Release|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.ActiveCfg = Debug|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.Build.0 = Debug|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.ActiveCfg = Release|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.Build.0 = Release|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.Build.0 = Debug|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.ActiveCfg = Release|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.ActiveCfg = Debug|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.Build.0 = Debug|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.ActiveCfg = Release|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.Build.0 = Release|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Debug.Build.0 = Debug|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Release.ActiveCfg = Release|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Release.Build.0 = Release|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Debug.Build.0 = Debug|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Release.ActiveCfg = Release|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Release.Build.0 = Release|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Debug.ActiveCfg = Debug|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Debug.Build.0 = Debug|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Release.ActiveCfg = Release|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Release.Build.0 = Release|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Debug.ActiveCfg = Debug|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Debug.Build.0 = Debug|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Release.ActiveCfg = Release|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Release.Build.0 = Release|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Debug.ActiveCfg = Debug|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Debug.Build.0 = Debug|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Release.ActiveCfg = Release|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Release.Build.0 = Release|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Debug.ActiveCfg = Debug|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Debug.Build.0 = Debug|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Release.ActiveCfg = Release|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Release.Build.0 = Release|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Debug.ActiveCfg = Debug|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Debug.Build.0 = Debug|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Release.ActiveCfg = Release|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Release.Build.0 = Release|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Debug.ActiveCfg = Debug|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Debug.Build.0 = Debug|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Release.ActiveCfg = Release|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Release.Build.0 = Release|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.ActiveCfg = Debug|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.Build.0 = Debug|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Release.ActiveCfg = Release|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Release.Build.0 = Release|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.ActiveCfg = Debug|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.Build.0 = Debug|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.ActiveCfg = Release|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.Build.0 = Release|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.ActiveCfg = Debug|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.Build.0 = Debug|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.ActiveCfg = Release|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.Build.0 = Release|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.ActiveCfg = Debug|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.Build.0 = Debug|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Release.ActiveCfg = Release|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Release.Build.0 = Release|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.ActiveCfg = Debug|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.Build.0 = Debug|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Release.ActiveCfg = Release|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Release.Build.0 = Release|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Debug.ActiveCfg = Debug|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Debug.Build.0 = Debug|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Release.ActiveCfg = Release|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.Build.0 = Release|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.Build.0 = Debug|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.ActiveCfg = Release|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.Build.0 = Release|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Debug.ActiveCfg = Debug|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Debug.Build.0 = Debug|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Release.ActiveCfg = Release|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Release.Build.0 = Release|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Debug.Build.0 = Debug|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Release.ActiveCfg = Release|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Release.Build.0 = Release|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.ActiveCfg = Debug|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.Build.0 = Debug|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.ActiveCfg = Release|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.Build.0 = Release|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.ActiveCfg = Debug|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.Build.0 = Debug|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.ActiveCfg = Release|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.Build.0 = Release|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.ActiveCfg = Debug|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.Build.0 = Debug|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.ActiveCfg = Release|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.Build.0 = Release|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.ActiveCfg = Debug|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.Build.0 = Debug|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.ActiveCfg = Release|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.Build.0 = Release|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.ActiveCfg = Debug|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.Build.0 = Debug|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.ActiveCfg = Release|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.Build.0 = Release|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.ActiveCfg = Debug|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.Build.0 = Debug|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.ActiveCfg = Release|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.Build.0 = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.ActiveCfg = Debug|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.Build.0 = Debug|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.ActiveCfg = Release|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.Build.0 = Release|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.ActiveCfg = Debug|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.Build.0 = Debug|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.ActiveCfg = Release|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.Build.0 = Release|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.ActiveCfg = Debug|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.Build.0 = Debug|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.ActiveCfg = Release|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.Build.0 = Release|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.ActiveCfg = Debug|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.Build.0 = Debug|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.ActiveCfg = Release|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.Build.0 = Release|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.ActiveCfg = Debug|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.Build.0 = Debug|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.ActiveCfg = Release|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.Build.0 = Release|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.ActiveCfg = Debug|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.Build.0 = Debug|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.ActiveCfg = Release|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.Build.0 = Release|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.ActiveCfg = Debug|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.Build.0 = Debug|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.ActiveCfg = Release|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.Build.0 = Release|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Debug.ActiveCfg = Debug|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Debug.Build.0 = Debug|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Release.ActiveCfg = Release|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Release.Build.0 = Release|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Debug.ActiveCfg = Debug|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Debug.Build.0 = Debug|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Release.ActiveCfg = Release|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Release.Build.0 = Release|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Debug.ActiveCfg = Debug|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Debug.Build.0 = Debug|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Release.ActiveCfg = Release|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Release.Build.0 = Release|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Debug.ActiveCfg = Debug|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Debug.Build.0 = Debug|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Release.ActiveCfg = Release|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Release.Build.0 = Release|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Debug.ActiveCfg = Debug|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Debug.Build.0 = Debug|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Release.ActiveCfg = Release|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Release.Build.0 = Release|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Debug.ActiveCfg = Debug|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Debug.Build.0 = Debug|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Release.ActiveCfg = Release|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Release.Build.0 = Release|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Debug.ActiveCfg = Debug|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Debug.Build.0 = Debug|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Release.ActiveCfg = Release|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Release.Build.0 = Release|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.ActiveCfg = Debug|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.Build.0 = Debug|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.ActiveCfg = Release|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.Build.0 = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.ActiveCfg = Debug|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.Build.0 = Debug|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.ActiveCfg = Release|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.Build.0 = Release|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.ActiveCfg = Debug|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.Build.0 = Debug|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.ActiveCfg = Release|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.Build.0 = Release|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.ActiveCfg = Debug|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.Build.0 = Debug|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.ActiveCfg = Release|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.ActiveCfg = Debug|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.Build.0 = Debug|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.ActiveCfg = Release|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.Build.0 = Release|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Debug.ActiveCfg = Debug|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Debug.Build.0 = Debug|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Release.ActiveCfg = Release|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.Build.0 = Release|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.ActiveCfg = Debug|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.Build.0 = Debug|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.ActiveCfg = Release|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.Build.0 = Release|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.ActiveCfg = Debug|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.Build.0 = Debug|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.ActiveCfg = Release|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.Build.0 = Release|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Debug.Build.0 = Debug|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Release.ActiveCfg = Release|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Release.Build.0 = Release|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.ActiveCfg = Debug|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.Build.0 = Debug|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.ActiveCfg = Release|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.Build.0 = Release|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.Build.0 = Debug|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.ActiveCfg = Release|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.Build.0 = Release|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.ActiveCfg = Debug|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.Build.0 = Debug|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.ActiveCfg = Release|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.Build.0 = Release|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Debug.Build.0 = Debug|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Release.ActiveCfg = Release|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Debug.ActiveCfg = Debug|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Debug.Build.0 = Debug|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Release.ActiveCfg = Release|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.ActiveCfg = Debug|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.Build.0 = Debug|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.ActiveCfg = Release|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.Build.0 = Release|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.ActiveCfg = Debug|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.Build.0 = Debug|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.ActiveCfg = Release|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.Build.0 = Release|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.ActiveCfg = Debug|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.Build.0 = Debug|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.ActiveCfg = Release|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.Build.0 = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.ActiveCfg = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.Build.0 = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.ActiveCfg = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.Build.0 = Release|Win32 + {0000058C-0000-0000-0000-000000000021}.Debug.ActiveCfg = Debug|Win32 + {0000058C-0000-0000-0000-000000000021}.Debug.Build.0 = Debug|Win32 + {0000058C-0000-0000-0000-000000000021}.Release.ActiveCfg = Release|Win32 + {0000058C-0000-0000-0000-000000000021}.Release.Build.0 = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.ActiveCfg = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.Build.0 = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.ActiveCfg = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.Build.0 = Release|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.ActiveCfg = Debug|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.Build.0 = Debug|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.ActiveCfg = Release|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.Build.0 = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.ActiveCfg = Debug|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.Build.0 = Debug|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.ActiveCfg = Release|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.Build.0 = Release|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.ActiveCfg = Debug|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.Build.0 = Debug|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.ActiveCfg = Release|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.Build.0 = Release|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.ActiveCfg = Debug|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.Build.0 = Debug|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.ActiveCfg = Release|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.Build.0 = Release|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.ActiveCfg = Debug|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.Build.0 = Debug|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.ActiveCfg = Release|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.Build.0 = Release|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.ActiveCfg = Debug|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.Build.0 = Debug|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.ActiveCfg = Release|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.Build.0 = Release|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.ActiveCfg = Debug|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.Build.0 = Debug|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.ActiveCfg = Release|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.Build.0 = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.ActiveCfg = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.Build.0 = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.ActiveCfg = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.Build.0 = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.ActiveCfg = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.Build.0 = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.ActiveCfg = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.Build.0 = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.ActiveCfg = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.Build.0 = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.ActiveCfg = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.Build.0 = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.ActiveCfg = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.Build.0 = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.ActiveCfg = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.Build.0 = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.ActiveCfg = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.Build.0 = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.ActiveCfg = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.Build.0 = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.ActiveCfg = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.Build.0 = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.ActiveCfg = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.Build.0 = Release|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.ActiveCfg = Debug|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.Build.0 = Debug|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.ActiveCfg = Release|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.Build.0 = Release|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.ActiveCfg = Debug|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.Build.0 = Debug|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.ActiveCfg = Release|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.Build.0 = Release|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Debug.ActiveCfg = Debug|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Debug.Build.0 = Debug|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Release.ActiveCfg = Release|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Release.Build.0 = Release|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Debug.ActiveCfg = Debug|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Debug.Build.0 = Debug|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Release.ActiveCfg = Release|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/proj/vc7ide/anonymous_shared_memory_test.vcproj b/proj/vc7ide/anonymous_shared_memory_test.vcproj new file mode 100644 index 0000000..4b81afc --- /dev/null +++ b/proj/vc7ide/anonymous_shared_memory_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_anonymous_shared_memory.vcproj b/proj/vc7ide/doc_anonymous_shared_memory.vcproj new file mode 100644 index 0000000..cd5d7a4 --- /dev/null +++ b/proj/vc7ide/doc_anonymous_shared_memory.vcproj @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_complex_map.vcproj b/proj/vc7ide/doc_complex_map.vcproj new file mode 100644 index 0000000..855420e --- /dev/null +++ b/proj/vc7ide/doc_complex_map.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_managed_copy_on_write.vcproj b/proj/vc7ide/doc_managed_copy_on_write.vcproj new file mode 100644 index 0000000..0264fbe --- /dev/null +++ b/proj/vc7ide/doc_managed_copy_on_write.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_multi_index.vcproj b/proj/vc7ide/doc_multi_index.vcproj new file mode 100644 index 0000000..5a29cee --- /dev/null +++ b/proj/vc7ide/doc_multi_index.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_unordered_map.vcproj b/proj/vc7ide/doc_unordered_map.vcproj new file mode 100644 index 0000000..a08a8ea --- /dev/null +++ b/proj/vc7ide/doc_unordered_map.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/enable_shared_from_this_test.vcproj b/proj/vc7ide/enable_shared_from_this_test.vcproj new file mode 100644 index 0000000..e6ff1fe --- /dev/null +++ b/proj/vc7ide/enable_shared_from_this_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/file_lock_test.vcproj b/proj/vc7ide/file_lock_test.vcproj new file mode 100644 index 0000000..3e311dc --- /dev/null +++ b/proj/vc7ide/file_lock_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 5ccbb82..0f79970 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -315,6 +315,9 @@ Name="Managed Memory Classes" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + + diff --git a/proj/vc7ide/intersegment_ptr_test.vcproj b/proj/vc7ide/intersegment_ptr_test.vcproj new file mode 100644 index 0000000..e01e3bb --- /dev/null +++ b/proj/vc7ide/intersegment_ptr_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/multi_index_test.vcproj b/proj/vc7ide/multi_index_test.vcproj new file mode 100644 index 0000000..5d2a807 --- /dev/null +++ b/proj/vc7ide/multi_index_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unordered_test.vcproj b/proj/vc7ide/unordered_test.vcproj new file mode 100644 index 0000000..6c91a73 --- /dev/null +++ b/proj/vc7ide/unordered_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8b3e8ec..a070a7e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost Interprocess Library Test Jamfile -# (C) Copyright Ion Gaztañaga 2006. +# (C) Copyright Ion Gaztanaga 2006. # Use, modification and distribution are subject to the # Boost Software License, Version 1.0. (See accompanying file # LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/test/adaptive_node_pool_test.cpp b/test/adaptive_node_pool_test.cpp index 866b8f3..4ecdafb 100644 --- a/test/adaptive_node_pool_test.cpp +++ b/test/adaptive_node_pool_test.cpp @@ -10,14 +10,18 @@ #include #include "node_pool_test.hpp" #include +#include + +using namespace boost::interprocess; +typedef managed_shared_memory::segment_manager segment_manager_t; + +//Explicit specialization to catch compilation errors +template class detail::private_adaptive_node_pool_impl; int main () { - using namespace boost::interprocess; - typedef managed_shared_memory::segment_manager segment_manager; - typedef detail::private_adaptive_node_pool - node_pool_t; + node_pool_t; if(!test::test_all_node_pool()) return 1; diff --git a/test/adaptive_pool_test.cpp b/test/adaptive_pool_test.cpp index 7b36131..ebc3043 100644 --- a/test/adaptive_pool_test.cpp +++ b/test/adaptive_pool_test.cpp @@ -32,6 +32,8 @@ typedef detail::adaptive_pool_v1 //Explicit instantiations to catch compilation errors template class adaptive_pool; template class detail::adaptive_pool_v1; +template class adaptive_pool; +template class detail::adaptive_pool_v1; //Alias list types typedef list MyShmList; @@ -41,7 +43,6 @@ typedef list MyShmListV1; typedef vector MyShmVector; typedef vector MyShmVectorV1; - int main () { if(test::list_test()) diff --git a/test/allocator_v1.hpp b/test/allocator_v1.hpp index 6504df9..b46c3c4 100644 --- a/test/allocator_v1.hpp +++ b/test/allocator_v1.hpp @@ -114,17 +114,17 @@ class allocator_v1 //!Deallocates memory previously allocated. Never throws void deallocate(const pointer &ptr, size_type) - { mp_mngr->deallocate(detail::get_pointer(ptr)); } -/* + { mp_mngr->deallocate((void*)detail::get_pointer(ptr)); } + //!Construct object, calling constructor. //!Throws if T(const T&) throws void construct(const pointer &ptr, const_reference value) - { new(detail::get_pointer(ptr)) value_type(value); } + { new((void*)detail::get_pointer(ptr)) value_type(value); } //!Destroys object. Throws if object's destructor throws void destroy(const pointer &ptr) { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } -*/ + //!Returns the number of elements that could be allocated. Never throws size_type max_size() const { return mp_mngr->get_size(); } diff --git a/test/anonymous_shared_memory_test.cpp b/test/anonymous_shared_memory_test.cpp new file mode 100644 index 0000000..43ac48b --- /dev/null +++ b/test/anonymous_shared_memory_test.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +using namespace boost::interprocess; + +int main () +{ + try{ + const std::size_t MemSize = 99999*2; + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(MemSize)); + + //Write pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + *pattern = static_cast(i); + } + + //Check pattern + pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } + } + } + } + catch(std::exception &exc){ + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + return 0; +} + +#include diff --git a/test/cached_adaptive_pool_test.cpp b/test/cached_adaptive_pool_test.cpp index 0a0574e..0f5a09a 100644 --- a/test/cached_adaptive_pool_test.cpp +++ b/test/cached_adaptive_pool_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" @@ -33,7 +34,8 @@ typedef detail::cached_adaptive_pool_v1 //Explicit instantiations to catch compilation errors template class cached_adaptive_pool; template class detail::cached_adaptive_pool_v1; - +template class cached_adaptive_pool; +template class detail::cached_adaptive_pool_v1; //Alias list types typedef list MyShmList; diff --git a/test/cached_node_allocator_test.cpp b/test/cached_node_allocator_test.cpp index 597c90d..c29e639 100644 --- a/test/cached_node_allocator_test.cpp +++ b/test/cached_node_allocator_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" @@ -31,6 +32,8 @@ typedef detail::cached_node_allocator_v1 //Explicit instantiations to catch compilation errors template class cached_node_allocator; template class detail::cached_node_allocator_v1; +template class cached_node_allocator; +template class detail::cached_node_allocator_v1; //Alias list types typedef list MyShmList; diff --git a/test/deque_test.cpp b/test/deque_test.cpp index c9a6934..483f8da 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -65,12 +65,12 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) { IntType move_me(1); stddeque->insert(stddeque->begin()+size/2, 50, 1); - shmdeque->insert(shmdeque->begin()+size/2, 50, move(move_me)); + shmdeque->insert(shmdeque->begin()+size/2, 50, detail::move_impl(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { IntType move_me(2); - shmdeque->assign(shmdeque->size()/2, move(move_me)); + shmdeque->assign(shmdeque->size()/2, detail::move_impl(move_me)); stddeque->assign(stddeque->size()/2, 2); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } @@ -120,7 +120,7 @@ bool do_test() int i; for(i = 0; i < max; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->end(), move(move_me)); + shmdeque->insert(shmdeque->end(), detail::move_impl(move_me)); stddeque->insert(stddeque->end(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; @@ -141,7 +141,7 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me (-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -164,7 +164,7 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -189,7 +189,7 @@ bool do_test() for(i = 0; i < max; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->begin(), move(move_me)); + shmdeque->insert(shmdeque->begin(), detail::move_impl(move_me)); stddeque->insert(stddeque->begin(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index af691f9..e8466f0 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -82,26 +82,26 @@ class dummy_test_allocator template dummy_test_allocator(const dummy_test_allocator &) {} -/* + pointer address(reference value) { return pointer(addressof(value)); } const_pointer address(const_reference value) const { return const_pointer(addressof(value)); } -*/ + pointer allocate(size_type, cvoid_ptr = 0) { return 0; } void deallocate(const pointer &, size_type) { } -/* + template void construct(pointer, const Convertible &) {} void destroy(pointer) {} -*/ + size_type max_size() const { return 0; } @@ -115,7 +115,7 @@ class dummy_test_allocator size_type, size_type, size_type &, const pointer & = 0) - { return std::pair(0, true); } + { return std::pair(pointer(0), true); } //!Returns maximum the number of objects the previously allocated memory //!pointed by p can hold. diff --git a/test/enable_shared_from_this_test.cpp b/test/enable_shared_from_this_test.cpp new file mode 100644 index 0000000..6cc7a78 --- /dev/null +++ b/test/enable_shared_from_this_test.cpp @@ -0,0 +1,97 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, 2003 Peter Dimov +// +// This file is the adaptation of shared_from_this_test.cpp from smart_ptr library +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include +#include +#include "get_process_id_name.hpp" + +// + +using namespace boost::interprocess; + +typedef allocator + v_allocator_t; + +struct X; + +typedef deleter x_deleter_t; + +struct X : + public enable_shared_from_this +{ +}; + +typedef shared_ptr v_shared_ptr; + + +template +void test_enable_shared_this(ManagedMemory &managed_mem) +{ + v_shared_ptr p(make_managed_shared_ptr + (managed_mem.template construct(anonymous_instance)(), managed_mem)); + + v_shared_ptr q = p->shared_from_this(); + BOOST_TEST(p == q); + BOOST_TEST(!(p < q) && !(q < p)); + + X v2(*p); + + try + { + //This should throw bad_weak_ptr + v_shared_ptr r = v2.shared_from_this(); + BOOST_ERROR("v2.shared_from_this() failed to throw"); + } + catch(boost::interprocess::bad_weak_ptr const &) + { + //This is the expected path + } + catch(...){ + BOOST_ERROR("v2.shared_from_this() threw an unexpected exception"); + } + + try + { + //This should not throw bad_weak_ptr + *p = X(); + v_shared_ptr r = p->shared_from_this(); + BOOST_TEST(p == r); + BOOST_TEST(!(p < r) && !(r < p)); + } + catch(boost::interprocess::bad_weak_ptr const &) + { + BOOST_ERROR("p->shared_from_this() threw bad_weak_ptr after *p = X()"); + } + catch(...) + { + BOOST_ERROR("p->shared_from_this() threw an unexpected exception after *p = X()"); + } +} + + +int main() +{ + std::string process_name; + test::get_process_id_name(process_name); + shared_memory_object::remove(process_name.c_str()); + managed_shared_memory shmem(create_only, process_name.c_str(), 65536); + test_enable_shared_this(shmem); + shared_memory_object::remove(process_name.c_str()); + return boost::report_errors(); +} + +#include diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 840a45e..0a62b33 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -85,26 +85,26 @@ class expand_bwd_test_allocator expand_bwd_test_allocator(const expand_bwd_test_allocator &other) : mp_buffer(other.mp_buffer), m_size(other.m_size) , m_offset(other.m_offset), m_allocations(0){ } -/* + pointer address(reference value) { return pointer(addressof(value)); } const_pointer address(const_reference value) const { return const_pointer(addressof(value)); } -*/ + pointer allocate(size_type , cvoid_ptr hint = 0) { (void)hint; return 0; } void deallocate(const pointer &, size_type) {} -/* + template void construct(pointer ptr, const Convertible &value) { new((void*)ptr) value_type(value); } void destroy(pointer ptr) { (*ptr).~value_type(); } -*/ + size_type max_size() const { return m_size; } diff --git a/test/expand_bwd_test_template.hpp b/test/expand_bwd_test_template.hpp index 4ccf0ca..4a61d92 100644 --- a/test/expand_bwd_test_template.hpp +++ b/test/expand_bwd_test_template.hpp @@ -15,6 +15,7 @@ #include #include "expand_bwd_test_allocator.hpp" #include +#include namespace boost { namespace interprocess { namespace test { @@ -107,7 +108,8 @@ template bool test_insert_with_expand_bwd() { typedef typename VectorWithExpandBwdAllocator::value_type value_type; - typedef std::vector Vect; + typedef typename boost::remove_volatile::type non_volatile_value_type; + typedef std::vector Vect; const int MemorySize = 1000; //Distance old and new buffer @@ -131,37 +133,42 @@ bool test_insert_with_expand_bwd() for(int iteration = 0; iteration < Iterations; ++iteration) { - Vect memory; - memory.resize(MemorySize); + value_type *memory = new value_type[MemorySize]; + try { + std::vector initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } - Vect initial_data; - initial_data.resize(InitialSize[iteration]); - for(int i = 0; i < InitialSize[iteration]; ++i){ - initial_data[i] = value_type(i); - } + Vect data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } - Vect data_to_insert; - data_to_insert.resize(InsertSize[iteration]); - for(int i = 0; i < InsertSize[iteration]; ++i){ - data_to_insert[i] = value_type(-i); + expand_bwd_test_allocator alloc + ((value_type*)&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + vector.insert( vector.begin() + Position[iteration] + , data_to_insert.begin(), data_to_insert.end()); + initial_data.insert(initial_data.begin() + Position[iteration] + , data_to_insert.begin(), data_to_insert.end()); + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } } - - expand_bwd_test_allocator alloc - (&memory[0], memory.size(), Offset[iteration]); - VectorWithExpandBwdAllocator vector(alloc); - vector.insert( vector.begin() - , initial_data.begin(), initial_data.end()); - vector.insert( vector.begin() + Position[iteration] - , data_to_insert.begin(), data_to_insert.end()); - initial_data.insert(initial_data.begin() + Position[iteration] - , data_to_insert.begin(), data_to_insert.end()); - //Now check that values are equal - if(!CheckEqualVector(vector, initial_data)){ - std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl - << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl - << " Iteration: " << iteration << std::endl; - return false; + catch(...){ + delete []((non_volatile_value_type*)memory); + throw; } + delete []((non_volatile_value_type*)memory); } return true; @@ -173,7 +180,8 @@ template bool test_assign_with_expand_bwd() { typedef typename VectorWithExpandBwdAllocator::value_type value_type; - typedef std::vector Vect; + typedef typename boost::remove_volatile::type non_volatile_value_type; + typedef std::vector Vect; const int MemorySize = 200; const int Offset[] = { 50, 50, 50}; @@ -183,41 +191,46 @@ bool test_assign_with_expand_bwd() for(int iteration = 0; iteration initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } - //Create initial data - Vect initial_data; - initial_data.resize(InitialSize[iteration]); - for(int i = 0; i < InitialSize[iteration]; ++i){ - initial_data[i] = i; + //Create data to assign + std::vector data_to_assign; + data_to_assign.resize(AssignSize[iteration]); + for(int i = 0; i < AssignSize[iteration]; ++i){ + data_to_assign[i] = -i; + } + + //Insert initial data to the vector to test + expand_bwd_test_allocator alloc + (&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + + //Assign data + vector.assign(data_to_assign.begin(), data_to_assign.end()); + initial_data.assign(data_to_assign.begin(), data_to_assign.end()); + + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } } - - //Create data to assign - Vect data_to_assign; - data_to_assign.resize(AssignSize[iteration]); - for(int i = 0; i < AssignSize[iteration]; ++i){ - data_to_assign[i] = -i; - } - - //Insert initial data to the vector to test - expand_bwd_test_allocator alloc - (&memory[0], memory.size(), Offset[iteration]); - VectorWithExpandBwdAllocator vector(alloc); - vector.insert( vector.begin() - , initial_data.begin(), initial_data.end()); - - //Assign data - vector.assign(data_to_assign.begin(), data_to_assign.end()); - initial_data.assign(data_to_assign.begin(), data_to_assign.end()); - - //Now check that values are equal - if(!CheckEqualVector(vector, initial_data)){ - std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl - << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl - << " Iteration: " << iteration << std::endl; - return false; + catch(...){ + delete []((typename boost::remove_volatile::type*)memory); + throw; } + delete []((typename boost::remove_volatile::type*)memory); } return true; diff --git a/test/file_lock_test.cpp b/test/file_lock_test.cpp new file mode 100644 index 0000000..be0311c --- /dev/null +++ b/test/file_lock_test.cpp @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include "get_process_id_name.hpp" +#include +#include + +using namespace boost::interprocess; +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class file_lock_lock_test_wrapper + : public boost::interprocess::file_lock +{ + public: + file_lock_lock_test_wrapper() + : boost::interprocess::file_lock(test::get_process_id_name()) + {} +}; + +int main () +{ + //Destroy and create file + { + std::remove(test::get_process_id_name()); + std::ofstream file(test::get_process_id_name()); + if(!file){ + return 1; + } + file_lock flock(test::get_process_id_name()); + { + scoped_lock sl(flock); + } + { + scoped_lock sl(flock, try_to_lock); + } + { + scoped_lock sl(flock, test::delay(1)); + } + } + + //test::test_all_lock(); + //test::test_all_mutex(); + //test::test_all_sharable_mutex(); + std::remove(test::get_process_id_name()); + + return 0; +} + +#include diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 1b6a014..743c917 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -12,7 +12,6 @@ #include //std::streamoff #include //std::ofstream, std::ifstream #include -#include #include #include #include //std::auto_ptr @@ -123,6 +122,13 @@ int main () } } } + { + //Now test move semantics + file_mapping mapping(test::get_process_id_name(), read_only); + file_mapping move_ctor(detail::move_impl(mapping)); + file_mapping move_assign; + move_assign = detail::move_impl(move_ctor); + } } catch(std::exception &exc){ std::remove(test::get_process_id_name()); diff --git a/test/intersegment_ptr_test.cpp b/test/intersegment_ptr_test.cpp new file mode 100644 index 0000000..1f2d98a --- /dev/null +++ b/test/intersegment_ptr_test.cpp @@ -0,0 +1,404 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include //mapped_region +#include //anonymous_shared_memory +#include //managed_multi_shared_memory +#include //std::size_t + + +using namespace boost::interprocess; + +bool test_types_and_convertions() +{ + typedef intersegment_ptr pint_t; + typedef intersegment_ptr pcint_t; + typedef intersegment_ptr pvint_t; + typedef intersegment_ptr pcvint_t; + + if(!detail::is_same::value) + return false; + if(!detail::is_same::value) + return false; + if(!detail::is_same::value) + return false; + if(!detail::is_same::value) + return false; + int dummy_int = 9; + + { pint_t pint(&dummy_int); pcint_t pcint(pint); + if(pcint.get() != &dummy_int) return false; } + { pint_t pint(&dummy_int); pvint_t pvint(pint); + if(pvint.get() != &dummy_int) return false; } + { pint_t pint(&dummy_int); pcvint_t pcvint(pint); + if(pcvint.get() != &dummy_int) return false; } + { pcint_t pcint(&dummy_int); pcvint_t pcvint(pcint); + if(pcvint.get() != &dummy_int) return false; } + { pvint_t pvint(&dummy_int); pcvint_t pcvint(pvint); + if(pcvint.get() != &dummy_int) return false; } + + pint_t pint(0); + pcint_t pcint(0); + pvint_t pvint(0); + pcvint_t pcvint(0); + + pint = &dummy_int; + pcint = &dummy_int; + pvint = &dummy_int; + pcvint = &dummy_int; + + { pcint = pint; if(pcint.get() != &dummy_int) return false; } + { pvint = pint; if(pvint.get() != &dummy_int) return false; } + { pcvint = pint; if(pcvint.get() != &dummy_int) return false; } + { pcvint = pcint; if(pcvint.get() != &dummy_int) return false; } + { pcvint = pvint; if(pcvint.get() != &dummy_int) return false; } + + if(!pint) + return false; + + pint = 0; + if(pint) + return false; + + return true; +} + +bool test_arithmetic() +{ + typedef intersegment_ptr pint_t; + const int NumValues = 5; + int values[NumValues]; + + //Initialize p + pint_t p = values; + if(p.get() != values) + return false; + + //Initialize p + NumValues + pint_t pe = &values[NumValues]; + if(pe == p) + return false; + if(pe.get() != &values[NumValues]) + return false; + + //ptr - ptr + if((pe - p) != NumValues) + return false; + //ptr - integer + if((pe - NumValues) != p) + return false; + //ptr + integer + if((p + NumValues) != pe) + return false; + //integer + ptr + if((NumValues + p) != pe) + return false; + //indexing + if(pint_t(&p[NumValues]) != pe) + return false; + if(pint_t(&pe[-NumValues]) != p) + return false; + + //ptr -= integer + pint_t p0 = pe; + p0-= NumValues; + if(p != p0) + return false; + //ptr += integer + pint_t penew = p0; + penew += NumValues; + if(penew != pe) + return false; + + //++ptr + penew = p0; + for(int j = 0; j != NumValues; ++j, ++penew); + if(penew != pe) + return false; + //--ptr + p0 = pe; + for(int j = 0; j != NumValues; ++j, --p0); + if(p != p0) + return false; + //ptr++ + penew = p0; + for(int j = 0; j != NumValues; ++j){ + pint_t p = penew; + if(p != penew++) + return false; + } + //ptr-- + p0 = pe; + for(int j = 0; j != NumValues; ++j){ + pint_t p = p0; + if(p != p0--) + return false; + } + + return true; +} + +bool test_comparison() +{ + typedef intersegment_ptr pint_t; + const int NumValues = 5; + int values[NumValues]; + + //Initialize p + pint_t p = values; + if(p.get() != values) + return false; + + //Initialize p + NumValues + pint_t pe = &values[NumValues]; + if(pe == p) + return false; + if(pe.get() != &values[NumValues]) + return false; + + //operators + if(p == pe) + return false; + if(p != p) + return false; + if(!(p < pe)) + return false; + if(!(p <= pe)) + return false; + if(!(pe > p)) + return false; + if(!(pe >= p)) + return false; + + return true; +} + +struct segment_data +{ + int int0; + int int1; + intersegment_ptr ptr0; + int int2; + int int3; +}; + +bool test_basic_comparisons() +{ + //Create aligned sections + const std::size_t PageSize = mapped_region::get_page_size(); + mapped_region reg_0_0(anonymous_shared_memory(PageSize)); + mapped_region reg_0_1(anonymous_shared_memory(PageSize)); + mapped_region reg_1_0(anonymous_shared_memory(PageSize)); + mapped_region reg_1_1(anonymous_shared_memory(PageSize)); + + if(sizeof(segment_data) > mapped_region::get_page_size()) + return false; + + segment_data &seg_0_0 = *((segment_data *)reg_0_0.get_address()); + segment_data &seg_0_1 = *((segment_data *)reg_0_1.get_address()); + segment_data &seg_1_0 = *((segment_data *)reg_1_0.get_address()); + segment_data &seg_1_1 = *((segment_data *)reg_1_1.get_address()); + + //Some dummy multi_segment_services + multi_segment_services *services0 = (multi_segment_services *)0; + multi_segment_services *services1 = (multi_segment_services *)1; + + const intersegment_ptr::segment_group_id group_0_id = + intersegment_ptr::new_segment_group(services0); + const intersegment_ptr::segment_group_id group_1_id = + intersegment_ptr::new_segment_group(services1); + + { + + //Now register the segments in the segment data-base + intersegment_ptr::insert_mapping(group_0_id, &seg_0_0, PageSize); + intersegment_ptr::insert_mapping(group_0_id, &seg_0_1, PageSize); + intersegment_ptr::insert_mapping(group_1_id, &seg_1_0, PageSize); + intersegment_ptr::insert_mapping(group_1_id, &seg_1_1, PageSize); + } + + //Now do some testing... + { + //Same segment + seg_0_0.ptr0 = &seg_0_0.int0; + seg_0_1.ptr0 = &seg_0_1.int0; + + if(seg_0_0.ptr0.get() != &seg_0_0.int0) + return false; + if(seg_0_1.ptr0.get() != &seg_0_1.int0) + return false; + + //Try it again to make use of the already established relative addressing + seg_0_0.ptr0 = &seg_0_0.int1; + seg_0_1.ptr0 = &seg_0_1.int1; + + if(seg_0_0.ptr0.get() != &seg_0_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_1.int1) + return false; + + //Set to null and try again + seg_0_0.ptr0 = 0; + seg_0_1.ptr0 = 0; + + seg_0_0.ptr0 = &seg_0_0.int1; + seg_0_1.ptr0 = &seg_0_1.int1; + + if(seg_0_0.ptr0.get() != &seg_0_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_1.int1) + return false; + + //Set to null and try again + int stack_int; + seg_0_0.ptr0 = &stack_int; + seg_0_1.ptr0 = &stack_int; + + if(seg_0_0.ptr0.get() != &stack_int) + return false; + if(seg_0_1.ptr0.get() != &stack_int) + return false; + } + + { + //Now use stack variables + intersegment_ptr stack_0 = &seg_0_0.int2; + intersegment_ptr stack_1 = &seg_1_1.int2; + + if(stack_0.get() != &seg_0_0.int2) + return false; + if(stack_1.get() != &seg_1_1.int2) + return false; + + //Now reuse stack variables knowing that there are on stack + stack_0 = &seg_0_0.int3; + stack_1 = &seg_1_1.int3; + + if(stack_0.get() != &seg_0_0.int3) + return false; + if(stack_1.get() != &seg_1_1.int3) + return false; + + //Now set to null and try it again + stack_0 = 0; + stack_1 = 0; + + stack_0 = &seg_0_0.int3; + stack_1 = &seg_1_1.int3; + + if(stack_0.get() != &seg_0_0.int3) + return false; + if(stack_1.get() != &seg_1_1.int3) + return false; + } + { + //Different segments in the same group + seg_0_0.ptr0 = &seg_0_1.int0; + seg_0_1.ptr0 = &seg_0_0.int0; + + if(seg_0_0.ptr0.get() != &seg_0_1.int0) + return false; + if(seg_0_1.ptr0.get() != &seg_0_0.int0) + return false; + + //Try it again to make use of the already established segmented addressing + seg_0_0.ptr0 = &seg_0_1.int1; + seg_0_1.ptr0 = &seg_0_0.int1; + + if(seg_0_0.ptr0.get() != &seg_0_1.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_0.int1) + return false; + + //Set to null and try it again + seg_0_0.ptr0 = 0; + seg_0_1.ptr0 = 0; + + seg_0_0.ptr0 = &seg_0_1.int1; + seg_0_1.ptr0 = &seg_0_0.int1; + + if(seg_0_0.ptr0.get() != &seg_0_1.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_0.int1) + return false; + } + + { + //Different groups + seg_0_0.ptr0 = &seg_1_0.int0; + seg_0_1.ptr0 = &seg_1_1.int0; + + if(seg_0_0.ptr0.get() != &seg_1_0.int0) + return false; + if(seg_0_1.ptr0.get() != &seg_1_1.int0) + return false; + + //Try it again + seg_0_0.ptr0 = &seg_1_0.int1; + seg_0_1.ptr0 = &seg_1_1.int1; + + if(seg_0_0.ptr0.get() != &seg_1_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_1_1.int1) + return false; + + //Set null and try it again + seg_0_0.ptr0 = 0; + seg_0_1.ptr0 = 0; + + seg_0_0.ptr0 = &seg_1_0.int1; + seg_0_1.ptr0 = &seg_1_1.int1; + + if(seg_0_0.ptr0.get() != &seg_1_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_1_1.int1) + return false; + } + + { + //Erase mappings + intersegment_ptr::delete_group(group_0_id); + intersegment_ptr::delete_group(group_1_id); + } + return true; +} + +bool test_multi_segment_shared_memory() +{ + { + shared_memory_object::remove("kk0"); + managed_multi_shared_memory mshm(create_only, "kk", 4096); + } + + shared_memory_object::remove("kk0"); + return true; +} + +int main() +{ + if(!test_types_and_convertions()) + return 1; + if(!test_arithmetic()) + return 1; + if(!test_comparison()) + return 1; + if(!test_basic_comparisons()) + return 1; + + if(!test_multi_segment_shared_memory()) + return 1; + return 0; +} + +#include diff --git a/test/iset_index_allocation_test.cpp b/test/iset_index_allocation_test.cpp index a5bae3f..9e25313 100644 --- a/test/iset_index_allocation_test.cpp +++ b/test/iset_index_allocation_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include "named_allocation_test_template.hpp" diff --git a/test/list_test.cpp b/test/list_test.cpp index a083d91..e2073fe 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -26,6 +26,9 @@ template class boost::interprocess::list ShmemAllocator; typedef list MyList; +typedef allocator ShmemVolatileAllocator; +typedef list MyVolatileList; + typedef allocator ShmemMoveAllocator; typedef list MyMoveList; @@ -37,6 +40,9 @@ int main () if(test::list_test()) return 1; + if(test::list_test()) + return 1; + if(test::list_test()) return 1; diff --git a/test/list_test.hpp b/test/list_test.hpp index a8982f6..deaa277 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -36,7 +36,7 @@ struct push_data_function typedef typename MyShmList::value_type IntType; for(int i = 0; i < max; ++i){ IntType move_me(i); - shmlist->push_back(move(move_me)); + shmlist->push_back(detail::move_impl(move_me)); stdlist->push_back(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -54,7 +54,7 @@ struct push_data_function typedef typename MyShmList::value_type IntType; for(int i = 0; i < max; ++i){ IntType move_me(i); - shmlist->push_front(move(move_me)); + shmlist->push_front(detail::move_impl(move_me)); stdlist->push_front(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -136,7 +136,7 @@ int list_test (bool copied_allocators_equal = true) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -166,7 +166,7 @@ int list_test (bool copied_allocators_equal = true) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index c33b97e..0d00edb 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -88,6 +88,44 @@ int main () return -1; } + { + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_copy_on_write, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find("MyVector").first; + if(!mfile_vect) + return -1; + + //Erase vector + mfile.destroy_ptr(mfile_vect); + + //Make sure vector is erased + mfile_vect = mfile.find("MyVector").first; + if(mfile_vect) + return -1; + } + //Now check vector is still in the file + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_copy_on_write, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find("MyVector").first; + if(!mfile_vect) + return -1; + } + } + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_read_only, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find("MyVector").first; + if(!mfile_vect) + return -1; + } { std::size_t old_free_memory; { @@ -162,6 +200,13 @@ int main () if(next_file_size <= final_file_size) return -1; } + { + //Now test move semantics + managed_mapped_file original(open_only, FileName); + managed_mapped_file move_ctor(detail::move_impl(original)); + managed_mapped_file move_assign; + move_assign = detail::move_impl(move_ctor); + } } std::remove(FileName); diff --git a/test/managed_shared_memory_test.cpp b/test/managed_shared_memory_test.cpp index 9d7d94c..2004af8 100644 --- a/test/managed_shared_memory_test.cpp +++ b/test/managed_shared_memory_test.cpp @@ -84,7 +84,44 @@ int main () if(!shmem_vect) return -1; } + { + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_copy_on_write, ShmemName); + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + + //Erase vector + shmem.destroy_ptr(shmem_vect); + + //Make sure vector is erased + shmem_vect = shmem.find("MyVector").first; + if(shmem_vect) + return -1; + } + //Now check vector is still in the shmem + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_copy_on_write, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } + } + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_read_only, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } { std::size_t old_free_memory; { @@ -159,6 +196,13 @@ int main () if(next_shmem_size <= final_shmem_size) return -1; } + { + //Now test move semantics + managed_shared_memory original(open_only, ShmemName); + managed_shared_memory move_ctor(detail::move_impl(original)); + managed_shared_memory move_assign; + move_assign = detail::move_impl(move_ctor); + } } shared_memory_object::remove(ShmemName); diff --git a/test/managed_windows_shared_memory_test.cpp b/test/managed_windows_shared_memory_test.cpp index 52b4497..f02868f 100644 --- a/test/managed_windows_shared_memory_test.cpp +++ b/test/managed_windows_shared_memory_test.cpp @@ -72,20 +72,68 @@ int main () //Construct a vector in the shared memory w_shm_vect = w_shm.construct ("MyVector") (myallocator); - //Map preexisting segment again in memory - managed_windows_shared_memory w_shm_new(open_only, MemName); + { + //Map preexisting segment again in memory + managed_windows_shared_memory w_shm_new(open_only, MemName); - //Check vector is still there - w_shm_vect = w_shm_new.find("MyVector").first; - if(!w_shm_vect) - return -1; + //Check vector is still there + w_shm_vect = w_shm_new.find("MyVector").first; + if(!w_shm_vect) + return -1; - if(w_shm_new.get_size() != w_shm.get_size()) - return 1; - //Destroy and check it is not present - w_shm_new.destroy_ptr(w_shm_vect); - if(0 != w_shm_new.find("MyVector").first) - return 1; + if(w_shm_new.get_size() != w_shm.get_size()) + return 1; + + { + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_copy_on_write, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + + //Erase vector + shmem.destroy_ptr(shmem_vect); + + //Make sure vector is erased + shmem_vect = shmem.find("MyVector").first; + if(shmem_vect) + return -1; + } + //Now check vector is still in the s + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_copy_on_write, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } + } + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_read_only, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } + + //Destroy and check it is not present + w_shm_new.destroy_ptr(w_shm_vect); + if(0 != w_shm_new.find("MyVector").first) + return 1; + + //Now test move semantics + managed_windows_shared_memory original(open_only, MemName); + managed_windows_shared_memory move_ctor(detail::move_impl(original)); + managed_windows_shared_memory move_assign; + move_assign = detail::move_impl(move_ctor); + } } return 0; diff --git a/test/map_test.hpp b/test/map_test.hpp index 4d9902f..13363bf 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -115,9 +115,9 @@ int map_test () int i, j; for(i = 0; i < max; ++i){ - shmmap->insert(move(IntPairType (move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType (detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(StdPairType(i, i)); } @@ -232,9 +232,9 @@ int map_test () } for(i = 0; i < max; ++i){ - shmmap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(StdPairType(i, i)); } @@ -242,10 +242,10 @@ int map_test () if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; for(i = 0; i < max; ++i){ - shmmap->insert(shmmap->begin(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->begin(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->begin(), StdPairType(i, i)); //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->begin(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->begin(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->begin(), StdPairType(i, i)); //PrintContainers(shmmultimap, stdmultimap); if(!CheckEqualPairContainers(shmmap, stdmap)) @@ -253,29 +253,29 @@ int map_test () if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - shmmap->insert(shmmap->end(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->end(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->end(), StdPairType(i, i)); - shmmultimap->insert(shmmultimap->end(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->end(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->end(), StdPairType(i, i)); if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - shmmap->insert(shmmap->lower_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->lower_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->lower_bound(i), StdPairType(i, i)); //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->lower_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->lower_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->lower_bound(i), StdPairType(i, i)); //PrintContainers(shmmultimap, stdmultimap); if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - shmmap->insert(shmmap->upper_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->upper_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->upper_bound(i), StdPairType(i, i)); //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->upper_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->upper_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->upper_bound(i), StdPairType(i, i)); //PrintContainers(shmmultimap, stdmultimap); if(!CheckEqualPairContainers(shmmap, stdmap)) @@ -303,8 +303,8 @@ int map_test () for(j = 0; j < 3; ++j) for(i = 0; i < 100; ++i){ - shmmap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); if(shmmap->count(IntType(i)) != typename MyShmMultiMap::size_type(1)) return 1; if(shmmultimap->count(IntType(i)) != typename MyShmMultiMap::size_type(j+1)) @@ -367,9 +367,9 @@ int map_test_copyable () int i; for(i = 0; i < max; ++i){ - shmmap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(StdPairType(i, i)); } if(!CheckEqualContainers(shmmap, stdmap)) return 1; diff --git a/test/mapped_file_test.cpp b/test/mapped_file_test.cpp index 233e907..75bb9eb 100644 --- a/test/mapped_file_test.cpp +++ b/test/mapped_file_test.cpp @@ -74,6 +74,11 @@ int main () //Overwrite all memory std::memset(file1.get_user_address(), 0, file1.get_user_size()); + + //Now test move semantics + mapped_file move_ctor(detail::move_impl(file1)); + mapped_file move_assign; + move_assign = detail::move_impl(move_ctor); } std::remove(FileName); return 0; diff --git a/test/multi_index_test.cpp b/test/multi_index_test.cpp new file mode 100644 index 0000000..40ce912 --- /dev/null +++ b/test/multi_index_test.cpp @@ -0,0 +1,149 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2007. 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace boost::interprocess; +namespace bmi = boost::multi_index; + +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator>shm_string; + +//Data to insert in shared memory +struct employee +{ + int id; + int age; + shm_string name; + employee( int id_ + , int age_ + , const char *name_ + , const char_allocator &a) + : id(id_), age(age_), name(name_, a) + {} +}; + +//Tags +struct id{}; +struct age{}; +struct name{}; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + allocator +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + adaptive_pool +>; +/* +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + cached_adaptive_pool +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + private_adaptive_pool +>; +*/ +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + node_allocator +>; +/* +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + cached_node_allocator +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + private_node_allocator +>; +*/ +int main () +{ + return 0; +} + +#include diff --git a/test/node_allocator_test.cpp b/test/node_allocator_test.cpp index dbe7b5d..4c1235f 100644 --- a/test/node_allocator_test.cpp +++ b/test/node_allocator_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" @@ -30,6 +31,8 @@ typedef detail::node_allocator_v1 //Explicit instantiations to catch compilation errors template class node_allocator; template class detail::node_allocator_v1; +template class node_allocator; +template class detail::node_allocator_v1; //Alias list types typedef list MyShmList; diff --git a/test/node_pool_test.cpp b/test/node_pool_test.cpp index 418ce4d..da4dcc2 100644 --- a/test/node_pool_test.cpp +++ b/test/node_pool_test.cpp @@ -11,14 +11,15 @@ #include "node_pool_test.hpp" #include +using namespace boost::interprocess; +typedef managed_shared_memory::segment_manager segment_manager_t; +template class detail::private_node_pool_impl; int main () { - using namespace boost::interprocess; - typedef managed_shared_memory::segment_manager segment_manager; typedef detail::private_node_pool - node_pool_t; + node_pool_t; if(!test::test_all_node_pool()) return 1; diff --git a/test/node_pool_test.hpp b/test/node_pool_test.hpp index 2e2b608..d6b8145 100644 --- a/test/node_pool_test.hpp +++ b/test/node_pool_test.hpp @@ -25,7 +25,7 @@ template struct test_node_pool { static bool allocate_then_deallocate(NodePool &pool); - static bool deallocate_free_chunks(NodePool &pool); + static bool deallocate_free_blocks(NodePool &pool); }; template @@ -60,7 +60,7 @@ bool test_node_pool::allocate_then_deallocate(NodePool &pool) return false; } - pool.deallocate_free_chunks(); + pool.deallocate_free_blocks(); if(0 != pool.num_free_nodes()){ return false; @@ -70,11 +70,11 @@ bool test_node_pool::allocate_then_deallocate(NodePool &pool) } template -bool test_node_pool::deallocate_free_chunks(NodePool &pool) +bool test_node_pool::deallocate_free_blocks(NodePool &pool) { - const std::size_t max_chunks = 10; - const std::size_t max_nodes = max_chunks*pool.get_real_num_node(); - const std::size_t nodes_per_chunk = pool.get_real_num_node(); + const std::size_t max_blocks = 10; + const std::size_t max_nodes = max_blocks*pool.get_real_num_node(); + const std::size_t nodes_per_block = pool.get_real_num_node(); std::vector nodes; @@ -93,25 +93,25 @@ bool test_node_pool::deallocate_free_chunks(NodePool &pool) return false; } - //Now deallocate one of each chunk per iteration - for(std::size_t node_i = 0; node_i < nodes_per_chunk; ++node_i){ - //Deallocate a node per chunk - for(std::size_t i = 0; i < max_chunks; ++i){ - pool.deallocate_node(nodes[i*nodes_per_chunk + node_i]); + //Now deallocate one of each block per iteration + for(std::size_t node_i = 0; node_i < nodes_per_block; ++node_i){ + //Deallocate a node per block + for(std::size_t i = 0; i < max_blocks; ++i){ + pool.deallocate_node(nodes[i*nodes_per_block + node_i]); } //Check that the free count is correct - if(max_chunks*(node_i+1) != pool.num_free_nodes()){ + if(max_blocks*(node_i+1) != pool.num_free_nodes()){ return false; } - //Now try to deallocate free chunks - pool.deallocate_free_chunks(); + //Now try to deallocate free blocks + pool.deallocate_free_blocks(); - //Until we don't deallocate the last node of every chunk + //Until we don't deallocate the last node of every block //no node should be deallocated - if(node_i != (nodes_per_chunk - 1)){ - if(max_chunks*(node_i+1) != pool.num_free_nodes()){ + if(node_i != (nodes_per_block - 1)){ + if(max_blocks*(node_i+1) != pool.num_free_nodes()){ return false; } } @@ -136,7 +136,7 @@ bool test_all_node_pool() typedef boost::interprocess::test::test_node_pool test_node_pool_t; shared_memory_object::remove(test::get_process_id_name()); { - managed_shared_memory shm(create_only, test::get_process_id_name(), 16*1024); + managed_shared_memory shm(create_only, test::get_process_id_name(), 4*1024*sizeof(void*)); typedef deleter deleter_t; typedef unique_ptr unique_ptr_t; @@ -149,7 +149,7 @@ bool test_all_node_pool() //Now call each test if(!test_node_pool_t::allocate_then_deallocate(*p)) return false; - if(!test_node_pool_t::deallocate_free_chunks(*p)) + if(!test_node_pool_t::deallocate_free_blocks(*p)) return false; } shared_memory_object::remove(test::get_process_id_name()); diff --git a/test/private_adaptive_pool_test.cpp b/test/private_adaptive_pool_test.cpp index a914e83..953bdfa 100644 --- a/test/private_adaptive_pool_test.cpp +++ b/test/private_adaptive_pool_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" @@ -30,6 +31,8 @@ typedef detail::private_adaptive_pool_v1 //Explicit instantiations to catch compilation errors template class private_adaptive_pool; template class detail::private_adaptive_pool_v1; +template class private_adaptive_pool; +template class detail::private_adaptive_pool_v1; //Alias list types typedef list MyShmList; diff --git a/test/private_node_allocator_test.cpp b/test/private_node_allocator_test.cpp index 4190c6a..ad3fc5d 100644 --- a/test/private_node_allocator_test.cpp +++ b/test/private_node_allocator_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" @@ -30,6 +31,8 @@ typedef detail::private_node_allocator_v1 //Explicit instantiations to catch compilation errors template class private_node_allocator; template class detail::private_node_allocator_v1; +template class private_node_allocator; +template class detail::private_node_allocator_v1; //Alias list types typedef list MyShmList; diff --git a/test/set_test.hpp b/test/set_test.hpp index f35ccee..db8766f 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -63,7 +63,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -72,7 +72,7 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect3[i] = move(move_me); + aux_vect3[i] = detail::move_impl(move_me); } MyShmSet *shmset2 = @@ -108,20 +108,20 @@ int set_test () int i, j; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(move(move_me)" << std::endl; + std::cout << "Error in shmset->insert(detail::move_impl(move_me)" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(move(move_me)" << std::endl; + std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me)" << std::endl; return 1; } @@ -183,7 +183,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -192,7 +192,7 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = move(move_me); + aux_vect3[i] = detail::move_impl(move_me); } shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); @@ -228,7 +228,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -237,19 +237,19 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = move(move_me); + aux_vect3[i] = detail::move_impl(move_me); } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect4[i] = move(move_me); + aux_vect4[i] = detail::move_impl(move_me); } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect5[i] = move(move_me); + aux_vect5[i] = detail::move_impl(move_me); } shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); @@ -285,88 +285,88 @@ int set_test () for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(move(move_me)) try 2" << std::endl; + std::cout << "Error in shmset->insert(detail::move_impl(move_me)) try 2" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(move(move_me2)) try 2" << std::endl; + std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me2)) try 2" << std::endl; return 1; } for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(shmset->begin(), move(move_me)); + shmset->insert(shmset->begin(), detail::move_impl(move_me)); stdset->insert(stdset->begin(), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->begin(), move(move_me2)); + shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2)); stdmultiset->insert(stdmultiset->begin(), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->begin(), move(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->begin(), detail::move_impl(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), move(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2))" << std::endl; return 1; } IntType move_me3(i); - shmset->insert(shmset->end(), move(move_me3)); + shmset->insert(shmset->end(), detail::move_impl(move_me3)); stdset->insert(stdset->end(), i); IntType move_me4(i); - shmmultiset->insert(shmmultiset->end(), move(move_me4)); + shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4)); stdmultiset->insert(stdmultiset->end(), i); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->end(), move(move_me3))" << std::endl; + std::cout << "Error in shmset->insert(shmset->end(), detail::move_impl(move_me3))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->end(), move(move_me4))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4))" << std::endl; return 1; } { IntType move_me(i); - shmset->insert(shmset->upper_bound(move_me), move(move_me)); + shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me)); stdset->insert(stdset->upper_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->upper_bound(move_me2), move(move_me2)); + shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2)); stdmultiset->insert(stdmultiset->upper_bound(i), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), move(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), move(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2))" << std::endl; return 1; } } { IntType move_me(i); - shmset->insert(shmset->lower_bound(move_me), move(move_me2)); + shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2)); stdset->insert(stdset->lower_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->lower_bound(move_me2), move(move_me2)); + shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2)); stdmultiset->insert(stdmultiset->lower_bound(i), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), move(move_me2))" << std::endl; + std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), move(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2))" << std::endl; return 1; } } @@ -392,9 +392,9 @@ int set_test () for(j = 0; j < 3; ++j) for(i = 0; i < 100; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); IntType count_me(i); if(shmset->count(count_me) != typename MyShmMultiSet::size_type(1)){ std::cout << "Error in shmset->count(count_me)" << std::endl; @@ -461,10 +461,10 @@ int set_test_copyable () int i; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)) return 1; diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 723659c..54fc31d 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "get_process_id_name.hpp" @@ -113,6 +114,35 @@ int main () } } } + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(FileSize)); + + //Write pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + *pattern = static_cast(i); + } + + //Check pattern + pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } + } + } + { + //Now test move semantics + shared_memory_object mapping(open_only, test::get_process_id_name(), read_write); + shared_memory_object move_ctor(detail::move_impl(mapping)); + shared_memory_object move_assign; + move_assign = detail::move_impl(move_ctor); + } } catch(std::exception &exc){ shared_memory_object::remove(test::get_process_id_name()); diff --git a/test/shared_memory_test.cpp b/test/shared_memory_test.cpp index f336409..976a4a2 100644 --- a/test/shared_memory_test.cpp +++ b/test/shared_memory_test.cpp @@ -74,6 +74,11 @@ int main () //Overwrite all memory std::memset(shm1.get_user_address(), 0, shm1.get_user_size()); + + //Now test move semantics + shared_memory move_ctor(detail::move_impl(shm1)); + shared_memory move_assign; + move_assign = detail::move_impl(move_ctor); } } catch(std::exception &ex){ diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index 7371f89..ef7066a 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Peter Dimov 2002-2005. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Peter Dimov 2002-2005, 2007. +// (C) Copyright Ion Gaztanaga 2006-2008. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -168,6 +168,8 @@ int string_shared_ptr_vector_insertion_test() //Now fill a shared memory vector of shared_ptrs to a string string_shared_ptr_vector_t my_sharedptr_vector(string_shared_ptr_allocator); my_sharedptr_vector.insert(my_sharedptr_vector.begin(), NumElements, string_shared_ptr); + //Insert in the middle to test movability + my_sharedptr_vector.insert(my_sharedptr_vector.begin() + my_sharedptr_vector.size()/2, NumElements, string_shared_ptr); //Now check the shared count is the objects contained in the //vector plus string_shared_ptr if(string_shared_ptr.use_count() != static_cast(my_sharedptr_vector.size()+1)){ @@ -536,6 +538,81 @@ int basic_shared_ptr_test() return boost::report_errors(); } +struct alias_tester +{ + int v_; + + explicit alias_tester( int v ): v_( v ) + { + } + + ~alias_tester() + { + v_ = 0; + } +}; + +void test_alias() +{ + typedef allocator + v_allocator_t; + + typedef deleter + alias_tester_deleter_t; + + typedef deleter + int_deleter_t; + + typedef shared_ptr alias_tester_shared_ptr; + + typedef shared_ptr int_shared_ptr; + typedef shared_ptr const_int_shared_ptr; + typedef shared_ptr volatile_int_shared_ptr; + + std::string process_name; + test::get_process_id_name(process_name); + + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory shmem(create_only, process_name.c_str(), 10000); + + { + int m = 0; + int_shared_ptr p; + int_shared_ptr p2( p, &m ); + + BOOST_TEST( detail::get_pointer(p2.get()) == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + p2.reset( p, (int*)0 ); + + BOOST_TEST( p2.get() == 0 ); + + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + + { + int m = 0; + int_shared_ptr p(make_managed_shared_ptr + (shmem.construct(anonymous_instance)(), shmem)); + const_int_shared_ptr p2( p, &m ); + + BOOST_TEST( detail::get_pointer(p2.get()) == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + } + shared_memory_object::remove(process_name.c_str()); +} + int main() { @@ -548,6 +625,8 @@ int main() if(0 != basic_shared_ptr_test()) return 1; + test_alias(); + return 0; } diff --git a/test/string_test.cpp b/test/string_test.cpp index 9009186..62318bb 100644 --- a/test/string_test.cpp +++ b/test/string_test.cpp @@ -127,7 +127,7 @@ int string_test() std::sprintf(buffer, "%i", i); auxShmString += buffer; auxStdString += buffer; - shmStringVect->push_back(move(auxShmString)); + shmStringVect->push_back(detail::move_impl(auxShmString)); stdStringVect->push_back(auxStdString); } @@ -157,7 +157,7 @@ int string_test() std::sprintf(buffer, "%i", i); auxShmString += buffer; auxStdString += buffer; - shmStringVect->insert(shmStringVect->begin(), move(auxShmString)); + shmStringVect->insert(shmStringVect->begin(), detail::move_impl(auxShmString)); stdStringVect->insert(stdStringVect->begin(), auxStdString); } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index eea66a1..2535ec6 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -61,7 +61,7 @@ template class boost::interprocess::multimap //Customize managed_shared_memory class typedef basic_managed_shared_memory , + simple_seq_fit >, map_index > my_managed_shared_memory; diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp index 19830fb..be43789 100644 --- a/test/unique_ptr_test.cpp +++ b/test/unique_ptr_test.cpp @@ -70,14 +70,14 @@ int main() //Test some copy constructors my_unique_ptr_class my_ptr3(0, segment.get_deleter()); - my_unique_ptr_class my_ptr4(move(my_ptr3)); + my_unique_ptr_class my_ptr4(detail::move_impl(my_ptr3)); //Construct a list and fill MyList list(segment.get_segment_manager()); //Insert from my_unique_ptr_class - list.push_front(move(my_ptr)); - list.push_back(move(my_ptr2)); + list.push_front(detail::move_impl(my_ptr)); + list.push_back(detail::move_impl(my_ptr2)); //Check pointers assert(my_ptr.get() == 0); @@ -85,9 +85,9 @@ int main() assert(list.begin()->get() == ptr1); assert(list.rbegin()->get() == ptr2); - //MyList list2(move(list)); - //list2.swap(move(MyList(segment.get_segment_manager()))); - //list.swap(move(MyList(segment.get_segment_manager()))); + //MyList list2(detail::move_impl(list)); + //list2.swap(detail::move_impl(MyList(segment.get_segment_manager()))); + //list.swap(detail::move_impl(MyList(segment.get_segment_manager()))); assert(list.begin()->get() == ptr1); assert(list.rbegin()->get() == ptr2); @@ -97,8 +97,8 @@ int main() MySet set(set_less_t(), segment.get_segment_manager()); //Insert in set from list passing ownership - set.insert(move(*list.begin())); - set.insert(move(*list.rbegin())); + set.insert(detail::move_impl(*list.begin())); + set.insert(detail::move_impl(*list.rbegin())); //Check pointers assert(list.begin()->get() == 0); @@ -120,12 +120,12 @@ int main() //Insert from my_unique_ptr_class if(ptr1 < ptr2){ - vector.insert(vector.begin(), move(*set.begin())); - vector.insert(vector.end(), move(*set.rbegin())); + vector.insert(vector.begin(), detail::move_impl(*set.begin())); + vector.insert(vector.end(), detail::move_impl(*set.rbegin())); } else{ - vector.insert(vector.begin(), move(*set.rbegin())); - vector.insert(vector.end(), move(*set.begin())); + vector.insert(vector.begin(), detail::move_impl(*set.rbegin())); + vector.insert(vector.end(), detail::move_impl(*set.begin())); } //Check pointers @@ -134,14 +134,14 @@ int main() assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); - MyVector vector2(move(vector)); + MyVector vector2(detail::move_impl(vector)); vector2.swap(vector); assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); my_unique_ptr_class a(0, segment.get_deleter()), b(0, segment.get_deleter()); - a = move(b); + a = detail::move_impl(b); } shared_memory_object::remove(process_name.c_str()); return 0; diff --git a/test/unordered_test.cpp b/test/unordered_test.cpp new file mode 100644 index 0000000..9604a32 --- /dev/null +++ b/test/unordered_test.cpp @@ -0,0 +1,94 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "get_process_id_name.hpp" +#include +#include + +#include //std::equal_to +#include //boost::hash + +namespace bip = boost::interprocess; + +typedef bip::allocator ShmemAllocator; +typedef boost::unordered_set, std::equal_to, ShmemAllocator> MyUnorderedSet; +typedef boost::unordered_multiset, std::equal_to, ShmemAllocator> MyUnorderedMultiSet; + +//Explicit instantiation to catch compile-time errors +template class boost::unordered_set, std::equal_to, ShmemAllocator>; +template class boost::unordered_multiset, std::equal_to, ShmemAllocator>; + +int main() +{ + //Remove any other old shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + try { + bip::managed_shared_memory shm(bip::create_only, bip::test::get_process_id_name(), 65536); + + //Elements to be inserted in unordered containers + const int elements[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + const int elements_size = sizeof(elements)/sizeof(elements[0]); + + MyUnorderedSet *myset = + shm.construct(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator()); + MyUnorderedMultiSet *mymset = + shm.construct(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator()); + + //Insert elements and check sizes + myset->insert((&elements[0]), (&elements[elements_size])); + myset->insert((&elements[0]), (&elements[elements_size])); + mymset->insert((&elements[0]), (&elements[elements_size])); + mymset->insert((&elements[0]), (&elements[elements_size])); + + if(myset->size() != (unsigned int)elements_size) + return 1; + if(mymset->size() != (unsigned int)elements_size*2) + return 1; + + //Destroy elements and check sizes + myset->clear(); + mymset->clear(); + + if(!myset->empty()) + return 1; + if(!mymset->empty()) + return 1; + + //Destroy elements and check if memory has been deallocated + shm.destroy_ptr(myset); + shm.destroy_ptr(mymset); + + shm.shrink_to_fit_indexes(); + if(!shm.all_memory_deallocated()) + return 1; + + } + catch(...){ + //Remove shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + throw; + } + //Remove shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + return 0; +} + +#include diff --git a/test/upgradable_mutex_test.cpp b/test/upgradable_mutex_test.cpp index d94bb1b..846743a 100644 --- a/test/upgradable_mutex_test.cpp +++ b/test/upgradable_mutex_test.cpp @@ -35,135 +35,135 @@ int main () //Conversions to scoped_lock { scoped_lock lock(mut); - scoped_lock e_lock(move(lock)); - lock.swap(move(e_lock)); + scoped_lock e_lock(detail::move_impl(lock)); + lock.swap(detail::move_impl(e_lock)); } { scoped_lock lock(mut); scoped_lock e_lock(mut2); - e_lock = move(lock); + e_lock = detail::move_impl(lock); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() - scoped_lock e_lock(move(u_lock)); + scoped_lock e_lock(detail::move_impl(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(u_lock)); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(u_lock)); + e_lock = detail::move_impl(moved); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() - scoped_lock e_lock(move(u_lock), try_to_lock); + scoped_lock e_lock(detail::move_impl(u_lock), try_to_lock); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(u_lock), try_to_lock); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(u_lock), try_to_lock); + e_lock = detail::move_impl(moved); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock u_lock(mut); //This calls timed_unlock_upgradable_and_lock() - scoped_lock e_lock(move(u_lock), t); + scoped_lock e_lock(detail::move_impl(u_lock), t); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock u_lock(mut); //This calls timed_unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(u_lock), t); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(u_lock), t); + e_lock = detail::move_impl(moved); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() - scoped_lock e_lock(move(s_lock), try_to_lock); + scoped_lock e_lock(detail::move_impl(s_lock), try_to_lock); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(s_lock), try_to_lock); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(s_lock), try_to_lock); + e_lock = detail::move_impl(moved); } //Conversions to upgradable_lock { upgradable_lock lock(mut); - upgradable_lock u_lock(move(lock)); - lock.swap(move(u_lock)); + upgradable_lock u_lock(detail::move_impl(lock)); + lock.swap(detail::move_impl(u_lock)); } { upgradable_lock lock(mut); upgradable_lock u_lock(mut2); - upgradable_lock moved(move(lock)); - u_lock = move(moved); + upgradable_lock moved(detail::move_impl(lock)); + u_lock = detail::move_impl(moved); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() - upgradable_lock u_lock(move(s_lock), try_to_lock); + upgradable_lock u_lock(detail::move_impl(s_lock), try_to_lock); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(move(s_lock), try_to_lock); - u_lock = move(moved); + upgradable_lock moved(detail::move_impl(s_lock), try_to_lock); + u_lock = detail::move_impl(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() - upgradable_lock u_lock(move(e_lock)); + upgradable_lock u_lock(detail::move_impl(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(move(e_lock)); - u_lock = move(moved); + upgradable_lock moved(detail::move_impl(e_lock)); + u_lock = detail::move_impl(moved); } //Conversions to sharable_lock { sharable_lock lock(mut); - sharable_lock s_lock(move(lock)); - lock.swap(move(s_lock)); + sharable_lock s_lock(detail::move_impl(lock)); + lock.swap(detail::move_impl(s_lock)); } { sharable_lock lock(mut); sharable_lock s_lock(mut2); - sharable_lock moved(move(lock)); - s_lock = move(moved); + sharable_lock moved(detail::move_impl(lock)); + s_lock = detail::move_impl(moved); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() - sharable_lock s_lock(move(u_lock)); + sharable_lock s_lock(detail::move_impl(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(move(u_lock)); - s_lock = move(moved); + sharable_lock moved(detail::move_impl(u_lock)); + s_lock = detail::move_impl(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() - sharable_lock s_lock(move(e_lock)); + sharable_lock s_lock(detail::move_impl(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(move(e_lock)); - s_lock = move(moved); + sharable_lock moved(detail::move_impl(e_lock)); + s_lock = detail::move_impl(moved); } } diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index 232b253..0835575 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -62,6 +62,18 @@ int main () //Named new capable heap mem allocator wmanaged_heap_memory heap_buffer(memsize); + //Test move semantics + { + wmanaged_external_buffer user_default; + wmanaged_external_buffer temp_external(detail::move_impl(user_buffer)); + user_default = detail::move_impl(temp_external); + user_buffer = detail::move_impl(user_default); + wmanaged_heap_memory heap_default; + wmanaged_heap_memory temp_heap(detail::move_impl(heap_buffer)); + heap_default = detail::move_impl(temp_heap); + heap_buffer = detail::move_impl(heap_default); + } + //Initialize memory user_buffer.reserve_named_objects(100); heap_buffer.reserve_named_objects(100); diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 0e76115..206b0d0 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -44,7 +44,16 @@ int test_expand_bwd() if(!test::test_all_expand_bwd()) return 1; +/* + //First raw volatile ints + typedef test::expand_bwd_test_allocator + volatile_int_allocator_type; + typedef vector + volatile_int_vector; + if(!test::test_all_expand_bwd()) + return 1; +*/ //Now user defined wrapped int typedef test::expand_bwd_test_allocator int_holder_allocator_type; @@ -72,6 +81,9 @@ int main() typedef allocator ShmemAllocator; typedef vector MyVector; + //typedef allocator ShmemVolatileAllocator; + //typedef vector MyVolatileVector; + typedef allocator ShmemMoveAllocator; typedef vector MyMoveVector; @@ -81,6 +93,9 @@ int main() if(test::vector_test()) return 1; + //if(test::vector_test()) + //return 1; + if(test::vector_test()) return 1; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 3d76790..d2f17ac 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -15,9 +15,6 @@ #include #include -#include -#include -#include #include #include #include @@ -25,6 +22,7 @@ #include "check_equal_containers.hpp" #include "movable_int.hpp" #include +#include #include "get_process_id_name.hpp" namespace boost{ @@ -50,18 +48,18 @@ bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) { IntType move_me(1); stdvector->insert(stdvector->begin()+size/2, 50, 1); - shmvector->insert(shmvector->begin()+size/2, 50, move(move_me)); + shmvector->insert(shmvector->begin()+size/2, 50, detail::move_impl(move_me)); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(2); - shmvector->assign(shmvector->size()/2, move(move_me)); + shmvector->assign(shmvector->size()/2, detail::move_impl(move_me)); stdvector->assign(stdvector->size()/2, 2); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(3); - shmvector->assign(shmvector->size()*3-1, move(move_me)); + shmvector->assign(shmvector->size()*3-1, detail::move_impl(move_me)); stdvector->assign(stdvector->size()*3-1, 3); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } @@ -111,7 +109,7 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType new_int(i); - shmvector->insert(shmvector->end(), move(new_int)); + shmvector->insert(shmvector->end(), detail::move_impl(new_int)); stdvector->insert(stdvector->end(), i); } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -133,7 +131,7 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = move(new_int); + aux_vect[i] = detail::move_impl(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -156,7 +154,7 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = move(new_int); + aux_vect[i] = detail::move_impl(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -174,7 +172,7 @@ int vector_test() if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; IntType push_back_this(1); - shmvector->push_back(move(push_back_this)); + shmvector->push_back(detail::move_impl(push_back_this)); stdvector->push_back(int(1)); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -189,7 +187,7 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType insert_this(i); - shmvector->insert(shmvector->begin(), move(insert_this)); + shmvector->insert(shmvector->begin(), detail::move_impl(insert_this)); stdvector->insert(stdvector->begin(), i); } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; diff --git a/test/windows_shared_memory_mapping_test.cpp b/test/windows_shared_memory_mapping_test.cpp index 6358e41..a5a20ab 100644 --- a/test/windows_shared_memory_mapping_test.cpp +++ b/test/windows_shared_memory_mapping_test.cpp @@ -23,98 +23,93 @@ using namespace boost::interprocess; int main () { - std::string process_name; - test::get_process_id_name(process_name); - try{ - const std::size_t FileSize = 99999*2; - //Create shared memory and file mapping - windows_shared_memory mapping(create_only, process_name.c_str(), read_write, FileSize); - + const char *names[2] = { test::get_process_id_name(), 0 }; + for(unsigned int i = 0; i < sizeof(names)/sizeof(names[0]); ++i) { + const std::size_t FileSize = 99999*2; //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_write); + windows_shared_memory mapping + (create_only, names[i], read_write, FileSize); - //Create two mapped regions, one half of the file each - mapped_region region (mapping - ,read_write - ,0 - ,FileSize/2 - ,0); + { - mapped_region region2(mapping - ,read_write - ,FileSize/2 - ,FileSize - FileSize/2 - ,0); + //Create two mapped regions, one half of the file each + mapped_region region (mapping + ,read_write + ,0 + ,FileSize/2 + ,0); - //Fill two regions with a pattern - unsigned char *filler = static_cast(region.get_address()); - for(std::size_t i = 0 - ;i < FileSize/2 - ;++i){ - *filler++ = static_cast(i); - } + mapped_region region2(mapping + ,read_write + ,FileSize/2 + ,FileSize - FileSize/2 + ,0); - filler = static_cast(region2.get_address()); - for(std::size_t i = FileSize/2 - ;i < FileSize - ;++i){ - *filler++ = static_cast(i); - } - } + //Fill two regions with a pattern + unsigned char *filler = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + *filler++ = static_cast(i); + } - //See if the pattern is correct in the file using two mapped regions - { - //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_write); - mapped_region region(mapping, read_write, 0, FileSize/2, 0); - mapped_region region2(mapping, read_write, FileSize/2, 0/*FileSize - FileSize/2*/, 0); - - unsigned char *checker = (unsigned char*)region.get_address(); - //Check pattern - for(std::size_t i = 0 - ;i < FileSize/2 - ;++i){ - if(*checker++ != static_cast(i)){ - return 1; + filler = static_cast(region2.get_address()); + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + *filler++ = static_cast(i); } } - //Check second half - checker = (unsigned char *)region2.get_address(); + //See if the pattern is correct in the file using two mapped regions + { + mapped_region region (mapping, read_only, 0, FileSize/2, 0); + mapped_region region2(mapping, read_only, FileSize/2, FileSize - FileSize/2, 0); - //Check pattern - for(std::size_t i = FileSize/2 - ;i < FileSize - ;++i){ - if(*checker++ != static_cast(i)){ - return 1; + unsigned char *checker = (unsigned char*)region.get_address(); + //Check pattern + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + if(*checker++ != static_cast(i)){ + return 1; + } + } + + //Check second half + checker = (unsigned char *)region2.get_address(); + + //Check pattern + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + if(*checker++ != static_cast(i)){ + return 1; + } } } - } - //Now check the pattern mapping a single read only mapped_region - { - //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_only); + //Now check the pattern mapping a single read only mapped_region + { + //Create a single regions, mapping all the file + mapped_region region (mapping, read_only); - //Create a single regions, mapping all the file - mapped_region region (mapping - ,read_only); - - //Check pattern - unsigned char *pattern = static_cast(region.get_address()); - for(std::size_t i = 0 - ;i < FileSize - ;++i, ++pattern){ - if(*pattern != static_cast(i)){ - return 1; + //Check pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } } } } } catch(std::exception &exc){ + //shared_memory_object::remove(test::get_process_id_name()); std::cout << "Unhandled exception: " << exc.what() << std::endl; return 1; } diff --git a/test/windows_shared_memory_test.cpp b/test/windows_shared_memory_test.cpp index 4250241..2f8512e 100644 --- a/test/windows_shared_memory_test.cpp +++ b/test/windows_shared_memory_test.cpp @@ -68,6 +68,7 @@ int main () std::cout << ex.what() << std::endl; return 1; } + return 0; }