diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 6eb1d7c..fdae0b2 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -25,8 +25,15 @@ doxygen autodoc EXTRACT_ALL=NO HIDE_UNDOC_MEMBERS=YES EXTRACT_PRIVATE=NO + ENABLE_PREPROCESSING=YES EXPAND_ONLY_PREDEF=YES - PREDEFINED=BOOST_INTERPROCESS_DOXYGEN_INVOKED + MACRO_EXPANSION=YES + "PREDEFINED=\"BOOST_INTERPROCESS_DOXYGEN_INVOKED\" \\ + \"BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(a)= \" \\ + \"BOOST_INTERPROCESS_RV_REF(a)=a &&\" \\ + \"BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(a)=a &&\" \\ + \"BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(a)=a &&\" \\ + \"BOOST_INTERPROCESS_FWD_REF(a)=a &&\"" "boost.doxygen.reftitle=Boost.Interprocess Reference" ; diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index c1bdc02..dc0d29d 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -94,13 +94,8 @@ You can just allocate a portion of a shared memory segment, copy the message to that buffer, send the offset of that portion of shared memory to another process, and you are done. Let's see the example: -[import ../example/doc_ipc_messageA.cpp] -[doc_ipc_messageA] - -In receiver process one just could write the following lines: - -[import ../example/doc_ipc_messageB.cpp] -[doc_ipc_messageB] +[import ../example/doc_ipc_message.cpp] +[doc_ipc_message] [endsect] @@ -108,15 +103,10 @@ In receiver process one just could write the following lines: You want to create objects in a shared memory segment, giving a string name to them so that any other process can find, use and delete them from the segment when the objects are not -needed anymore. Just write in one process: +needed anymore. Example: -[import ../example/doc_named_allocA.cpp] -[doc_named_allocA] - -In other process execute the following: - -[import ../example/doc_named_allocB.cpp] -[doc_named_allocB] +[import ../example/doc_named_alloc.cpp] +[doc_named_alloc] [endsect] @@ -148,16 +138,19 @@ list, map, so you can avoid these manual data structures just like with standard mapped files. For example, we can construct STL-like containers in shared memory. To do this, we just need to create a special (managed) shared memory segment, declare a [*Boost.Interprocess] allocator and construct the vector in shared memory -just if it was any other object. Just execute this first process: +just if it was any other object. -[import ../example/doc_contA.cpp] -[doc_contA] +The class that allows this complex structures in shared memory is called +[classref boost::interprocess::managed_shared_memory] and it's easy to use. +Just execute this example without arguments: -After this process is executed we can search the constructed vector and use it with -STL algorithms: +[import ../example/doc_spawn_vector.cpp] +[doc_spawn_vector] -[import ../example/doc_contB.cpp] -[doc_contB] +The parent process will create an special shared memory class that allows easy construction +of many complex data structures associated with a name. The parent process executes the same +program with an additional argument so the child process opens the shared memory and uses +the vector and erases it. [endsect] @@ -498,16 +491,11 @@ For more details regarding `mapped_region` see the Let's see a simple example of shared memory use. A server process creates a shared memory object, maps it and initializes all the bytes to a value. After that, a client process opens the shared memory, maps it, and checks -that the data is correctly initialized. This is the server process: +that the data is correctly initialized: [import ../example/doc_shared_memory.cpp] [doc_shared_memory] -Now the client process: - -[import ../example/doc_shared_memory2.cpp] -[doc_shared_memory2] - [endsect] [section:emulation Emulation for systems without shared memory objects] @@ -521,12 +509,11 @@ POSIX: defined by POSIX (see [link interprocess.sharedmemorybetweenprocesses.sharedmemory.windows_shared_memory Native windows shared memory] section for more information). -* Some UNIX systems don't support shared memory objects at all. MacOS is - one of these operating systems. +* Some UNIX systems don't fully support POSIX shared memory objects at all. In those platforms, shared memory is emulated with mapped files created in the temporary files directory. Because of this emulation, shared memory -has filesystem lifetime in those systems. +has filesystem lifetime in some of those systems. [endsect] @@ -554,12 +541,9 @@ the name will subsequently cause the creation of a shared memory object of this name exists (that is, trying to open an object with that name will fail and an object of the same name can be created again). -In Windows operating systems, the function fails if the object is being used, -so a programmer can't consider the UNIX behavior as the portable behavior: - -`shared_memory_object::remove` [*can] fail if the shared memory is still in use, -but this does not mean that it [*will] fail if it's in use. Just the same -behavior as the standard C (stdio.h) `int remove(const char *path)` function. +In Windows operating systems, current version supports an usually acceptable emulation +of the UNIX unlink behaviour: the file is randomly renamed and marked as to be deleted when +the last open handle is closed. [endsect] @@ -586,7 +570,6 @@ 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 @@ -624,20 +607,13 @@ shared memory object, maps it and initializes all the bytes to a value. After th a client process opens the shared memory, maps it, and checks that the data is correctly initialized. Take in care that [*if the server exits before the client connects to the shared memory the client connection will fail], because -the shared memory segment is destroyed when no processes are attached to the memory. +the shared memory segment is destroyed when no proces is attached to the memory. This is the server process: [import ../example/doc_windows_shared_memory.cpp] [doc_windows_shared_memory] -Now, before destroying the -[classref boost::interprocess::windows_shared_memory windows_shared memory] -object, launch the client process: - -[import ../example/doc_windows_shared_memory2.cpp] -[doc_windows_shared_memory2] - As we can see, native windows shared memory needs synchronization to make sure that the shared memory won't be destroyed before the client is launched. @@ -801,16 +777,11 @@ Let's reproduce the same example described in the shared memory section, using memory mapped files. A server process creates a shared memory segment, maps it and initializes all the bytes to a value. After that, a client process opens the shared memory, maps it, and checks -that the data is correctly initialized. This is the server process: +that the data is correctly initialized:: [import ../example/doc_file_mapping.cpp] [doc_file_mapping] -Now the client process: - -[import ../example/doc_file_mapping2.cpp] -[doc_file_mapping2] - [endsect] [endsect] @@ -1478,17 +1449,17 @@ will write a flag when ends writing the traces This is the process main process. Creates the shared memory, constructs the cyclic buffer and start writing traces: -[import ../example/doc_anonymous_mutexA.cpp] +[import ../example/comp_doc_anonymous_mutexA.cpp] [doc_anonymous_mutexA] The second process opens the shared memory, obtains access to the cyclic buffer and starts writing traces: -[import ../example/doc_anonymous_mutexB.cpp] +[import ../example/comp_doc_anonymous_mutexB.cpp] [doc_anonymous_mutexB] -As we can see, a mutex is useful to protect data but not to notify to another process -an event. For this, we need a condition variable, as we will see in the next section. +As we can see, a mutex is useful to protect data but not to notify an event to another +process. For this, we need a condition variable, as we will see in the next section. [endsect] @@ -1583,13 +1554,13 @@ This is the process main process. Creates the shared memory, places there the buffer and starts writing messages one by one until it writes "last message" to indicate that there are no more messages to print: -[import ../example/doc_anonymous_conditionA.cpp] +[import ../example/comp_doc_anonymous_conditionA.cpp] [doc_anonymous_conditionA] The second process opens the shared memory and prints each message until the "last message" message is received: -[import ../example/doc_anonymous_conditionB.cpp] +[import ../example/comp_doc_anonymous_conditionB.cpp] [doc_anonymous_conditionB] With condition variables, a process can block if it can't continue the work, @@ -1665,13 +1636,13 @@ This is the process main process. Creates the shared memory, places there the integer array and starts integers one by one, blocking if the array is full: -[import ../example/doc_anonymous_semaphoreA.cpp] +[import ../example/comp_doc_anonymous_semaphoreA.cpp] [doc_anonymous_semaphoreA] The second process opens the shared memory and copies the received integers to it's own buffer: -[import ../example/doc_anonymous_semaphoreB.cpp] +[import ../example/comp_doc_anonymous_semaphoreB.cpp] [doc_anonymous_semaphoreB] The same interprocess communication can be achieved with a condition variables @@ -2152,11 +2123,11 @@ more features and operations, see their reference for more informations [/section:upgradable_mutexes_example Anonymous Upgradable Mutex Example] -[/import ../example/doc_anonymous_upgradable_mutexA.cpp] +[/import ../example/comp_doc_anonymous_upgradable_mutexA.cpp] [/doc_anonymous_upgradable_mutexA] -[/import ../example/doc_anonymous_upgradable_mutexB.cpp] +[/import ../example/comp_doc_anonymous_upgradable_mutexB.cpp] [/doc_anonymous_upgradable_mutexB] [/endsect] @@ -2722,7 +2693,7 @@ objects are created pointing to the same file, no synchronization is guaranteed. POSIX, when two file descriptors are used to lock a file if a descriptor is closed, all file locks set by the calling process are cleared. -To sum up, if you plan to use file locking in your processes, use the following +To sum up, if you plan to use portable file locking in your processes, use the following restrictions: * [*For each file, use a single `file_lock` object per process.] @@ -2867,12 +2838,12 @@ In the following example, the first process creates the message queue, and write an array of integers on it. The other process just reads the array and checks that the sequence number is correct. This is the first process: -[import ../example/doc_message_queueA.cpp] +[import ../example/comp_doc_message_queueA.cpp] [doc_message_queueA] This is the second process: -[import ../example/doc_message_queueB.cpp] +[import ../example/comp_doc_message_queueB.cpp] [doc_message_queueB] To know more about this class and all its operations, please see the @@ -3246,11 +3217,16 @@ To use a managed mapped file, you must include the following header: managed_mapped_file mfile (open_or_create, "MyMappedFile", //Mapped file name 65536); //Mapped file size When the `managed_mapped_file` object is destroyed, the file is automatically unmapped, and all the resources are freed. To remove -the file from the filesystem you can use standard C `std::remove` -or [*Boost.Filesystem]'s `remove()` functions. File removing might fail +the file from the filesystem you could use standard C `std::remove` +or [*Boost.Filesystem]'s `remove()` functions, but file removing might fail if any process still has the file mapped in memory or the file is open by any process. +To obtain a more portable behaviour, use `file_mapping::remove(const char *)` operation, which +will remove the file even if it's being mapped. However, removal will fail in some OS systems if +the file (eg. by C++ file streams) and no delete share permission was granted to the file. But in +most common cases `file_mapping::remove` is portable enough. + [endsect] For more information about managed mapped file capabilities, see @@ -3871,20 +3847,20 @@ Here is the declaration of the function: [c++] - enum allocation_type + enum boost::interprocess::allocation_type { //Bitwise OR (|) combinable values - allocate_new = ..., - expand_fwd = ..., - expand_bwd = ..., - shrink_in_place = ..., - nothrow_allocation = ... + boost::interprocess::allocate_new = ..., + boost::interprocess::expand_fwd = ..., + boost::interprocess::expand_bwd = ..., + boost::interprocess::shrink_in_place = ..., + boost::interprocess::nothrow_allocation = ... }; template std::pair - allocation_command( allocation_type command + allocation_command( boost::interprocess::allocation_type command , std::size_t limit_size , std::size_t preferred_size , std::size_t &received_size @@ -3893,66 +3869,66 @@ Here is the declaration of the function: [*Preconditions for the function]: -* If the parameter command contains the value `shrink_in_place` it can't -contain any of these values: `expand_fwd`, `expand_bwd`. +* If the parameter command contains the value `boost::interprocess::shrink_in_place` it can't +contain any of these values: `boost::interprocess::expand_fwd`, `boost::interprocess::expand_bwd`. -* If the parameter command contains `expand_fwd` or `expand_bwd`, the parameter +* If the parameter command contains `boost::interprocess::expand_fwd` or `boost::interprocess::expand_bwd`, the parameter `reuse_ptr` must be non-null and returned by a previous allocation function. -* If the parameter command contains the value `shrink_in_place`, the parameter +* If the parameter command contains the value `boost::interprocess::shrink_in_place`, the parameter `limit_size` must be equal or greater than the parameter `preferred_size`. -* If the parameter `command` contains any of these values: `expand_fwd` or `expand_bwd`, +* If the parameter `command` contains any of these values: `boost::interprocess::expand_fwd` or `boost::interprocess::expand_bwd`, the parameter `limit_size` must be equal or less than the parameter `preferred_size`. [*Which are the effects of this function:] -* If the parameter command contains the value `shrink_in_place`, the function +* If the parameter command contains the value `boost::interprocess::shrink_in_place`, the function will try to reduce the size of the memory block referenced by pointer `reuse_ptr` to the value `preferred_size` moving only the end of the block. If it's not possible, it will try to reduce the size of the memory block as much as possible as long as this results in `size(p) <= limit_size`. Success is reported only if this results in `preferred_size <= size(p)` and `size(p) <= limit_size`. -* If the parameter `command` only contains the value `expand_fwd` (with optional - additional `nothrow_allocation`), the allocator will try to increase the size of the +* If the parameter `command` only contains the value `boost::interprocess::expand_fwd` (with optional + additional `boost::interprocess::nothrow_allocation`), the allocator will try to increase the size of the memory block referenced by pointer reuse moving only the end of the block to the value `preferred_size`. If it's not possible, it will try to increase the size of the memory block as much as possible as long as this results in `size(p) >= limit_size`. Success is reported only if this results in `limit_size <= size(p)`. -* If the parameter `command` only contains the value `expand_bwd` (with optional - additional `nothrow_allocation`), the allocator will try to increase the size of +* If the parameter `command` only contains the value `boost::interprocess::expand_bwd` (with optional + additional `boost::interprocess::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 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)`. -* If the parameter `command` only contains the value `allocate_new` (with optional - additional `nothrow_allocation`), the allocator will try to allocate memory for +* If the parameter `command` only contains the value `boost::interprocess::allocate_new` (with optional + additional `boost::interprocess::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. -* If the parameter `command` only contains a combination of `expand_fwd` and - `allocate_new`, (with optional additional `nothrow_allocation`) the allocator will +* If the parameter `command` only contains a combination of `boost::interprocess::expand_fwd` and + `boost::interprocess::allocate_new`, (with optional additional `boost::interprocess::nothrow_allocation`) the allocator will try first the forward expansion. If this fails, it would try a new allocation. -* If the parameter `command` only contains a combination of `expand_bwd` and - `allocate_new` (with optional additional `nothrow_allocation`), the allocator will +* If the parameter `command` only contains a combination of `boost::interprocess::expand_bwd` and + `boost::interprocess::allocate_new` (with optional additional `boost::interprocess::nothrow_allocation`), the allocator will try first to obtain `preferred_size` objects using both methods if necessary. If this fails, it will try to obtain `limit_size` objects using both methods if necessary. -* If the parameter `command` only contains a combination of `expand_fwd` and - `expand_bwd` (with optional additional `nothrow_allocation`), the allocator will +* If the parameter `command` only contains a combination of `boost::interprocess::expand_fwd` and + `boost::interprocess::expand_bwd` (with optional additional `boost::interprocess::nothrow_allocation`), the allocator will try first forward expansion. If this fails it will try to obtain preferred_size objects using backwards expansion or a combination of forward and backwards expansion. If this fails, it will try to obtain `limit_size` objects using both methods if necessary. * If the parameter `command` only contains a combination of allocation_new, - `expand_fwd` and `expand_bwd`, (with optional additional `nothrow_allocation`) + `boost::interprocess::expand_fwd` and `boost::interprocess::expand_bwd`, (with optional additional `boost::interprocess::nothrow_allocation`) the allocator will try first forward expansion. If this fails it will try to obtain preferred_size objects using new allocation, backwards expansion or a combination of forward and backwards expansion. If this fails, it will try to obtain `limit_size` @@ -3967,13 +3943,13 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * The allocator is unable to allocate/expand/shrink the memory or there is an error in preconditions -* The parameter command does not contain `nothrow_allocation`. +* The parameter command does not contain `boost::interprocess::nothrow_allocation`. [*This function returns:] * The address of the allocated memory or the new address of the expanded memory as the first member of the pair. If the parameter command contains - `nothrow_allocation` the first member will be 0 + `boost::interprocess::nothrow_allocation` the first member will be 0 if the allocation/expansion fails or there is an error in preconditions. * The second member of the pair will be false if the memory has been allocated, @@ -5018,7 +4994,7 @@ Let's see an example: [endsect] -[section:containers_and_move_semantics Move semantics in Interprocess containers] +[section:containers_and_move Move semantics in Interprocess containers] [*Boost.Interprocess] containers support move semantics, which means that the contents of a container can be moved from a container two another one, without any copying. The @@ -5030,7 +5006,7 @@ objects in the container, avoiding unnecessary copies. To transfer the contents of a container to another one, use -`boost::interprocess::move()` function, as shown in the example. For more details +`boost::move()` function, as shown in the example. For more details about functions supporting move-semantics, see the reference section of Boost.Interprocess containers: @@ -6541,6 +6517,17 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_39_00 Boost 1.39 Release] + +* Added experimental `stable_vector` container. +* `shared_memory_object::remove` has now POSIX `unlink` semantics and + `file_mapping::remove` was added to obtain POSIX `unlink` semantics with mapped files. +* Shared memory in windows has now kernel lifetime instead of filesystem lifetime: shared + memory will disappear when the system reboots. +* Updated move semantics. + +[endsect] + [section:release_notes_boost_1_38_00 Boost 1.38 Release] * Updated documentation to show rvalue-references funcions instead of emulation functions. diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 9551f9f..ba27162 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -19,7 +19,7 @@ rule test_all { local all_rules = ; - for local fileb in [ glob *.cpp ] + for local fileb in [ glob comp*.cpp ] { all_rules += [ link $(fileb) /boost/thread//boost_thread : # additional args @@ -28,6 +28,17 @@ rule test_all ] ; } + for local fileb in [ glob doc_*.cpp ] + { + all_rules += [ run $(fileb) /boost/thread//boost_thread + : # additional args + : # test-files + : # requirements + acc:-lrt + acc-pa_risc:-lrt + ] ; + } + return $(all_rules) ; } diff --git a/example/doc_anonymous_conditionA.cpp b/example/comp_doc_anonymous_conditionA.cpp similarity index 88% rename from example/doc_anonymous_conditionA.cpp rename to example/comp_doc_anonymous_conditionA.cpp index 1fb3336..cd0c7d3 100644 --- a/example/doc_anonymous_conditionA.cpp +++ b/example/comp_doc_anonymous_conditionA.cpp @@ -21,13 +21,17 @@ using namespace boost::interprocess; int main () { - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); + //Erase previous shared memory and schedule erasure on exit + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create - ,"shared_memory" //name + ,"MySharedMemory" //name ,read_write //read-write mode ); try{ @@ -66,13 +70,10 @@ int main () } } catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); std::cout << ex.what() << std::endl; return 1; } - //Erase shared memory - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_anonymous_conditionB.cpp b/example/comp_doc_anonymous_conditionB.cpp similarity index 92% rename from example/doc_anonymous_conditionB.cpp rename to example/comp_doc_anonymous_conditionB.cpp index 06d0a55..baa6a58 100644 --- a/example/doc_anonymous_conditionB.cpp +++ b/example/comp_doc_anonymous_conditionB.cpp @@ -23,7 +23,7 @@ int main () //Create a shared memory object. shared_memory_object shm (open_only //only create - ,"shared_memory" //name + ,"MySharedMemory" //name ,read_write //read-write mode ); @@ -61,13 +61,10 @@ int main () while(!end_loop); } catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); std::cout << ex.what() << std::endl; return 1; } - //Erase shared memory - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_anonymous_mutexA.cpp b/example/comp_doc_anonymous_mutexA.cpp similarity index 87% rename from example/doc_anonymous_mutexA.cpp rename to example/comp_doc_anonymous_mutexA.cpp index 04710fb..bbbc33c 100644 --- a/example/doc_anonymous_mutexA.cpp +++ b/example/comp_doc_anonymous_mutexA.cpp @@ -21,13 +21,17 @@ using namespace boost::interprocess; int main () { try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create - ,"shared_memory" //name + ,"MySharedMemory" //name ,read_write //read-write mode ); @@ -65,12 +69,9 @@ int main () } } catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); std::cout << ex.what() << std::endl; return 1; } - //Erase shared memory - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/comp_doc_anonymous_mutexB.cpp b/example/comp_doc_anonymous_mutexB.cpp new file mode 100644 index 0000000..4a7ed40 --- /dev/null +++ b/example/comp_doc_anonymous_mutexB.cpp @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_mutexB +#include +#include +#include +#include "doc_anonymous_mutex_shared_data.hpp" +#include +#include + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Open the shared memory object. + shared_memory_object shm + (open_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_memory_log * data = static_cast(addr); + + //Write some logs + for(int i = 0; i < 100; ++i){ + //Lock the mutex + scoped_lock lock(data->mutex); + std::sprintf(data->items[(data->current_line++) % shared_memory_log::NumItems] + ,"%s_%d", "process_a", i); + if(i == (shared_memory_log::NumItems-1)) + data->end_b = true; + //Mutex is released here + } + + //Wait until the other process ends + while(1){ + scoped_lock lock(data->mutex); + if(data->end_a) + break; + } + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_semaphoreA.cpp b/example/comp_doc_anonymous_semaphoreA.cpp new file mode 100644 index 0000000..856ecfc --- /dev/null +++ b/example/comp_doc_anonymous_semaphoreA.cpp @@ -0,0 +1,64 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_semaphoreA +#include +#include +#include +#include "doc_anonymous_semaphore_shared_data.hpp" + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a shared memory object. + shared_memory_object shm + (create_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Set size + shm.truncate(sizeof(shared_memory_buffer)); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_memory_buffer * data = new (addr) shared_memory_buffer; + + const int NumMsg = 100; + + //Insert data in the array + for(int i = 0; i < NumMsg; ++i){ + data->nempty.wait(); + data->mutex.wait(); + data->items[i % shared_memory_buffer::NumItems] = i; + data->mutex.post(); + data->nstored.post(); + } + + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_semaphoreB.cpp b/example/comp_doc_anonymous_semaphoreB.cpp new file mode 100644 index 0000000..29975f7 --- /dev/null +++ b/example/comp_doc_anonymous_semaphoreB.cpp @@ -0,0 +1,61 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_semaphoreB +#include +#include +#include +#include "doc_anonymous_semaphore_shared_data.hpp" + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a shared memory object. + shared_memory_object shm + (open_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Obtain the shared structure + shared_memory_buffer * data = static_cast(addr); + + const int NumMsg = 100; + + int extracted_data [NumMsg]; + + //Extract the data + for(int i = 0; i < NumMsg; ++i){ + data->nstored.wait(); + data->mutex.wait(); + extracted_data[i] = data->items[i % shared_memory_buffer::NumItems]; + data->mutex.post(); + data->nempty.post(); + } + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_upgradable_mutexA.cpp b/example/comp_doc_anonymous_upgradable_mutexA.cpp new file mode 100644 index 0000000..b07d9dd --- /dev/null +++ b/example/comp_doc_anonymous_upgradable_mutexA.cpp @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_upgradable_mutexA +#include +#include +#include +#include "doc_upgradable_mutex_shared_data.hpp" +#include +#include + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a shared memory object. + shared_memory_object shm + (create_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Set size + shm.truncate(sizeof(shared_data)); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_data * data = new (addr) shared_data; + + //Write some logs + for(int i = 0; i < shared_data::NumItems; ++i){ + //Lock the upgradable_mutex + scoped_lock lock(data->upgradable_mutex); + std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] + ,"%s_%d", "process_a", i); + if(i == (shared_data::NumItems-1)) + data->end_a = true; + //Mutex is released here + } + + //Wait until the other process ends + while(1){ + scoped_lock lock(data->upgradable_mutex); + if(data->end_b) + break; + } + + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_upgradable_mutexB.cpp b/example/comp_doc_anonymous_upgradable_mutexB.cpp new file mode 100644 index 0000000..e0448e7 --- /dev/null +++ b/example/comp_doc_anonymous_upgradable_mutexB.cpp @@ -0,0 +1,70 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_upgradable_mutexB +#include +#include +#include +#include "doc_upgradable_mutex_shared_data.hpp" +#include +#include + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Open the shared memory object. + shared_memory_object shm + (open_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_data * data = static_cast(addr); + + //Write some logs + for(int i = 0; i < 100; ++i){ + //Lock the upgradable_mutex + scoped_lock lock(data->upgradable_mutex); + std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] + ,"%s_%d", "process_a", i); + if(i == (shared_data::NumItems-1)) + data->end_b = true; + //Mutex is released here + } + + //Wait until the other process ends + while(1){ + scoped_lock lock(data->upgradable_mutex); + if(data->end_a) + break; + } + return 0; +} +//] + +#include diff --git a/example/doc_message_queueA.cpp b/example/comp_doc_message_queueA.cpp similarity index 100% rename from example/doc_message_queueA.cpp rename to example/comp_doc_message_queueA.cpp diff --git a/example/doc_message_queueB.cpp b/example/comp_doc_message_queueB.cpp similarity index 100% rename from example/doc_message_queueB.cpp rename to example/comp_doc_message_queueB.cpp diff --git a/example/doc_adaptive_pool.cpp b/example/doc_adaptive_pool.cpp index 9aeb0d4..e013ea3 100644 --- a/example/doc_adaptive_pool.cpp +++ b/example/doc_adaptive_pool.cpp @@ -18,46 +18,44 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a adaptive_pool that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef adaptive_pool - adaptive_pool_t; - adaptive_pool_t allocator_instance(segment.get_segment_manager()); + //Create a adaptive_pool that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef adaptive_pool + adaptive_pool_t; + adaptive_pool_t allocator_instance(segment.get_segment_manager()); - //Create another adaptive_pool. Since the segment manager address - //is the same, this adaptive_pool will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - adaptive_pool_t allocator_instance2(segment.get_segment_manager()); + //Create another adaptive_pool. Since the segment manager address + //is the same, this adaptive_pool will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + adaptive_pool_t allocator_instance2(segment.get_segment_manager()); - //Create another adaptive_pool using copy-constructor. This - //adaptive_pool will also be attached to the same pool - adaptive_pool_t allocator_instance3(allocator_instance2); + //Create another adaptive_pool using copy-constructor. This + //adaptive_pool will also be attached to the same pool + adaptive_pool_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_allocator.cpp b/example/doc_allocator.cpp index 87b071d..132658f 100644 --- a/example/doc_allocator.cpp +++ b/example/doc_allocator.cpp @@ -18,7 +18,12 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create shared memory managed_shared_memory segment(create_only, diff --git a/example/doc_anonymous_mutexB.cpp b/example/doc_anonymous_mutexB.cpp deleted file mode 100644 index c7854eb..0000000 --- a/example/doc_anonymous_mutexB.cpp +++ /dev/null @@ -1,70 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_mutexB -#include -#include -#include -#include "doc_anonymous_mutex_shared_data.hpp" -#include -#include - -using namespace boost::interprocess; - -int main () -{ - try{ - //Open the shared memory object. - shared_memory_object shm - (open_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_memory_log * data = static_cast(addr); - - //Write some logs - for(int i = 0; i < 100; ++i){ - //Lock the mutex - scoped_lock lock(data->mutex); - std::sprintf(data->items[(data->current_line++) % shared_memory_log::NumItems] - ,"%s_%d", "process_a", i); - if(i == (shared_memory_log::NumItems-1)) - data->end_b = true; - //Mutex is released here - } - - //Wait until the other process ends - while(1){ - scoped_lock lock(data->mutex); - if(data->end_a) - break; - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - shared_memory_object::remove("shared_memory"); - return 0; -} -//] -#include diff --git a/example/doc_anonymous_semaphoreA.cpp b/example/doc_anonymous_semaphoreA.cpp deleted file mode 100644 index f687049..0000000 --- a/example/doc_anonymous_semaphoreA.cpp +++ /dev/null @@ -1,70 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_semaphoreA -#include -#include -#include -#include "doc_anonymous_semaphore_shared_data.hpp" - -using namespace boost::interprocess; - -int main () -{ - try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); - - //Create a shared memory object. - shared_memory_object shm - (create_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Set size - shm.truncate(sizeof(shared_memory_buffer)); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_memory_buffer * data = new (addr) shared_memory_buffer; - - const int NumMsg = 100; - - //Insert data in the array - for(int i = 0; i < NumMsg; ++i){ - data->nempty.wait(); - data->mutex.wait(); - data->items[i % shared_memory_buffer::NumItems] = i; - data->mutex.post(); - data->nstored.post(); - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - - //Erase shared memory - shared_memory_object::remove("shared_memory"); - - return 0; -} -//] -#include diff --git a/example/doc_anonymous_semaphoreB.cpp b/example/doc_anonymous_semaphoreB.cpp deleted file mode 100644 index daf4e98..0000000 --- a/example/doc_anonymous_semaphoreB.cpp +++ /dev/null @@ -1,66 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_semaphoreB -#include -#include -#include -#include "doc_anonymous_semaphore_shared_data.hpp" - -using namespace boost::interprocess; - -int main () -{ - try{ - //Create a shared memory object. - shared_memory_object shm - (open_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Obtain the shared structure - shared_memory_buffer * data = static_cast(addr); - - const int NumMsg = 100; - - int extracted_data [NumMsg]; - - //Extract the data - for(int i = 0; i < NumMsg; ++i){ - data->nstored.wait(); - data->mutex.wait(); - extracted_data[i] = data->items[i % shared_memory_buffer::NumItems]; - data->mutex.post(); - data->nempty.post(); - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - - //Erase shared memory - shared_memory_object::remove("shared_memory"); - - return 0; -} -//] -#include diff --git a/example/doc_anonymous_upgradable_mutexA.cpp b/example/doc_anonymous_upgradable_mutexA.cpp deleted file mode 100644 index 158ea1c..0000000 --- a/example/doc_anonymous_upgradable_mutexA.cpp +++ /dev/null @@ -1,79 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_upgradable_mutexA -#include -#include -#include -#include "doc_upgradable_mutex_shared_data.hpp" -#include -#include - -using namespace boost::interprocess; - -int main () -{ - try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); - - //Create a shared memory object. - shared_memory_object shm - (create_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Set size - shm.truncate(sizeof(shared_data)); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_data * data = new (addr) shared_data; - - //Write some logs - for(int i = 0; i < shared_data::NumItems; ++i){ - //Lock the upgradable_mutex - scoped_lock lock(data->upgradable_mutex); - std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] - ,"%s_%d", "process_a", i); - if(i == (shared_data::NumItems-1)) - data->end_a = true; - //Mutex is released here - } - - //Wait until the other process ends - while(1){ - scoped_lock lock(data->upgradable_mutex); - if(data->end_b) - break; - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - - //Erase shared memory - shared_memory_object::remove("shared_memory"); - - return 0; -} -//] -#include diff --git a/example/doc_anonymous_upgradable_mutexB.cpp b/example/doc_anonymous_upgradable_mutexB.cpp deleted file mode 100644 index 1b83e11..0000000 --- a/example/doc_anonymous_upgradable_mutexB.cpp +++ /dev/null @@ -1,72 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_upgradable_mutexB -#include -#include -#include -#include "doc_upgradable_mutex_shared_data.hpp" -#include -#include - -using namespace boost::interprocess; - -int main () -{ - try{ - //Open the shared memory object. - shared_memory_object shm - (open_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_data * data = static_cast(addr); - - //Write some logs - for(int i = 0; i < 100; ++i){ - //Lock the upgradable_mutex - scoped_lock lock(data->upgradable_mutex); - std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] - ,"%s_%d", "process_a", i); - if(i == (shared_data::NumItems-1)) - data->end_b = true; - //Mutex is released here - } - - //Wait until the other process ends - while(1){ - scoped_lock lock(data->upgradable_mutex); - if(data->end_a) - break; - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - shared_memory_object::remove("shared_memory"); - return 0; -} -//] - -#include diff --git a/example/doc_bufferstream.cpp b/example/doc_bufferstream.cpp index 4fd6d75..9e14d6a 100644 --- a/example/doc_bufferstream.cpp +++ b/example/doc_bufferstream.cpp @@ -14,72 +14,73 @@ #include #include #include +#include using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Fill data - std::vector data, data2; - data.reserve(100); - for(int i = 0; i < 100; ++i){ - data.push_back(i); - } + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Allocate a buffer in shared memory to write data - char *my_cstring = - segment.construct("MyCString")[100*5](0); - bufferstream mybufstream(my_cstring, 100*5); - - //Now write data to the buffer - for(int i = 0; i < 100; ++i){ - mybufstream << data[i] << std::endl; - } - - //Check there was no overflow attempt - assert(mybufstream.good()); - - //Extract all values from the shared memory string - //directly to a vector. - data2.reserve(100); - std::istream_iterator it(mybufstream), itend; - std::copy(it, itend, std::back_inserter(data2)); - - //This extraction should have ended will fail error since - //the numbers formatted in the buffer end before the end - //of the buffer. (Otherwise it would trigger eofbit) - assert(mybufstream.fail()); - - //Compare data - assert(std::equal(data.begin(), data.end(), data2.begin())); - - //Clear errors and rewind - mybufstream.clear(); - mybufstream.seekp(0, std::ios::beg); - - //Now write again the data trying to do a buffer overflow - for(int i = 0; i < 500; ++i){ - mybufstream << data[i] << std::endl; - } - - //Now make sure badbit is active - //which means overflow attempt. - assert(!mybufstream.good()); - assert(mybufstream.bad()); - segment.destroy_ptr(my_cstring); + //Fill data + std::vector data; + data.reserve(100); + for(int i = 0; i < 100; ++i){ + data.push_back(i); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + const std::size_t BufferSize = 100*5; + + //Allocate a buffer in shared memory to write data + char *my_cstring = + segment.construct("MyCString")[BufferSize](0); + bufferstream mybufstream(my_cstring, BufferSize); + + //Now write data to the buffer + for(int i = 0; i < 100; ++i){ + mybufstream << data[i] << std::endl; } - shared_memory_object::remove("MySharedMemory"); + + //Check there was no overflow attempt + assert(mybufstream.good()); + + //Extract all values from the shared memory string + //directly to a vector. + std::vector data2; + std::istream_iterator it(mybufstream), itend; + std::copy(it, itend, std::back_inserter(data2)); + + //This extraction should have ended will fail error since + //the numbers formatted in the buffer end before the end + //of the buffer. (Otherwise it would trigger eofbit) + assert(mybufstream.fail()); + + //Compare data + assert(std::equal(data.begin(), data.end(), data2.begin())); + + //Clear errors and rewind + mybufstream.clear(); + mybufstream.seekp(0, std::ios::beg); + + //Now write again the data trying to do a buffer overflow + for(int i = 0, m = data.size()*5; i < m; ++i){ + mybufstream << data[i%5] << std::endl; + } + + //Now make sure badbit is active + //which means overflow attempt. + assert(!mybufstream.good()); + assert(mybufstream.bad()); + segment.destroy_ptr(my_cstring); return 0; } //] diff --git a/example/doc_cached_adaptive_pool.cpp b/example/doc_cached_adaptive_pool.cpp index c138ef0..6f0f7bf 100644 --- a/example/doc_cached_adaptive_pool.cpp +++ b/example/doc_cached_adaptive_pool.cpp @@ -18,54 +18,53 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create a cached_adaptive_pool that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef cached_adaptive_pool - cached_adaptive_pool_t; - cached_adaptive_pool_t allocator_instance(segment.get_segment_manager()); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //The max cached nodes are configurable per instance - allocator_instance.set_max_cached_nodes(3); + //Create a cached_adaptive_pool that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef cached_adaptive_pool + cached_adaptive_pool_t; + cached_adaptive_pool_t allocator_instance(segment.get_segment_manager()); - //Create another cached_adaptive_pool. Since the segment manager address - //is the same, this cached_adaptive_pool will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - cached_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); + //The max cached nodes are configurable per instance + allocator_instance.set_max_cached_nodes(3); - //The max cached nodes are configurable per instance - allocator_instance2.set_max_cached_nodes(5); + //Create another cached_adaptive_pool. Since the segment manager address + //is the same, this cached_adaptive_pool will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + cached_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); - //Create another cached_adaptive_pool using copy-constructor. This - //cached_adaptive_pool will also be attached to the same pool - cached_adaptive_pool_t allocator_instance3(allocator_instance2); + //The max cached nodes are configurable per instance + allocator_instance2.set_max_cached_nodes(5); - //We can clear the cache - allocator_instance3.deallocate_cache(); + //Create another cached_adaptive_pool using copy-constructor. This + //cached_adaptive_pool will also be attached to the same pool + cached_adaptive_pool_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //We can clear the cache + allocator_instance3.deallocate_cache(); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_cached_node_allocator.cpp b/example/doc_cached_node_allocator.cpp index 091a17e..0d19046 100644 --- a/example/doc_cached_node_allocator.cpp +++ b/example/doc_cached_node_allocator.cpp @@ -18,54 +18,53 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create a cached_node_allocator that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef cached_node_allocator - cached_node_allocator_t; - cached_node_allocator_t allocator_instance(segment.get_segment_manager()); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //The max cached nodes are configurable per instance - allocator_instance.set_max_cached_nodes(3); + //Create a cached_node_allocator that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef cached_node_allocator + cached_node_allocator_t; + cached_node_allocator_t allocator_instance(segment.get_segment_manager()); - //Create another cached_node_allocator. Since the segment manager address - //is the same, this cached_node_allocator will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - cached_node_allocator_t allocator_instance2(segment.get_segment_manager()); + //The max cached nodes are configurable per instance + allocator_instance.set_max_cached_nodes(3); - //The max cached nodes are configurable per instance - allocator_instance2.set_max_cached_nodes(5); + //Create another cached_node_allocator. Since the segment manager address + //is the same, this cached_node_allocator will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + cached_node_allocator_t allocator_instance2(segment.get_segment_manager()); - //Create another cached_node_allocator using copy-constructor. This - //cached_node_allocator will also be attached to the same pool - cached_node_allocator_t allocator_instance3(allocator_instance2); + //The max cached nodes are configurable per instance + allocator_instance2.set_max_cached_nodes(5); - //We can clear the cache - allocator_instance3.deallocate_cache(); + //Create another cached_node_allocator using copy-constructor. This + //cached_node_allocator will also be attached to the same pool + cached_node_allocator_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //We can clear the cache + allocator_instance3.deallocate_cache(); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_complex_map.cpp b/example/doc_complex_map.cpp index 1d64dac..e8d7238 100644 --- a/example/doc_complex_map.cpp +++ b/example/doc_complex_map.cpp @@ -52,28 +52,31 @@ typedef map< char_string, complex_data int main () { - shared_memory_object::remove("MySharedMemory"); - remove_shared_memory_on_destroy remove_on_destroy("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy { - //Create shared memory - managed_shared_memory segment(create_only,"MySharedMemory", 65536); + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //An allocator convertible to any allocator type - void_allocator alloc_inst (segment.get_segment_manager()); + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); - //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); + //An allocator convertible to any allocator type + void_allocator alloc_inst (segment.get_segment_manager()); - 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); - } + //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; } diff --git a/example/doc_cont.cpp b/example/doc_cont.cpp index 6b899ae..cd0680d 100644 --- a/example/doc_cont.cpp +++ b/example/doc_cont.cpp @@ -17,48 +17,47 @@ int main () { using namespace boost::interprocess; - shared_memory_object::remove("MySharedMemory"); - try{ - //A managed shared memory where we can construct objects - //associated with a c-string - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Alias an STL-like allocator of ints that allocates ints from the segment - typedef allocator - ShmemAllocator; + //A managed shared memory where we can construct objects + //associated with a c-string + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Alias a vector that uses the previous STL-like allocator - typedef vector MyVector; + //Alias an STL-like allocator of ints that allocates ints from the segment + typedef allocator + ShmemAllocator; - int initVal[] = {0, 1, 2, 3, 4, 5, 6 }; - const int *begVal = initVal; - const int *endVal = initVal + sizeof(initVal)/sizeof(initVal[0]); + //Alias a vector that uses the previous STL-like allocator + typedef vector MyVector; - //Initialize the STL-like allocator - const ShmemAllocator alloc_inst (segment.get_segment_manager()); + int initVal[] = {0, 1, 2, 3, 4, 5, 6 }; + const int *begVal = initVal; + const int *endVal = initVal + sizeof(initVal)/sizeof(initVal[0]); - //Construct the vector in the shared memory segment with the STL-like allocator - //from a range of iterators - MyVector *myvector = - segment.construct - ("MyVector")/*object name*/ - (begVal /*first ctor parameter*/, - endVal /*second ctor parameter*/, - alloc_inst /*third ctor parameter*/); + //Initialize the STL-like allocator + const ShmemAllocator alloc_inst (segment.get_segment_manager()); - //Use vector as your want - std::sort(myvector->rbegin(), myvector->rend()); - // . . . - //When done, destroy and delete vector from the segment - segment.destroy("MyVector"); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Construct the vector in the shared memory segment with the STL-like allocator + //from a range of iterators + MyVector *myvector = + segment.construct + ("MyVector")/*object name*/ + (begVal /*first ctor parameter*/, + endVal /*second ctor parameter*/, + alloc_inst /*third ctor parameter*/); + + //Use vector as your want + std::sort(myvector->rbegin(), myvector->rend()); + // . . . + //When done, destroy and delete vector from the segment + segment.destroy("MyVector"); return 0; } //] diff --git a/example/doc_contA.cpp b/example/doc_contA.cpp deleted file mode 100644 index 72812da..0000000 --- a/example/doc_contA.cpp +++ /dev/null @@ -1,60 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_contA -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //Shared memory front-end that is able to construct objects - //associated with a c-string. Erase previous shared memory with the name - //to be used and create the memory segment at the specified address and initialize resources - shared_memory_object::remove("MySharedMemory"); - managed_shared_memory segment - (create_only - ,"MySharedMemory" //segment name - ,65536); //segment size in bytes - - //Alias an STL compatible allocator of ints that allocates ints from the managed - //shared memory segment. This allocator will allow to place containers - //in managed shared memory segments - typedef allocator - ShmemAllocator; - - //Alias a vector that uses the previous STL-like allocator - typedef vector MyVector; - - //Initialize shared memory STL-compatible allocator - const ShmemAllocator alloc_inst (segment.get_segment_manager()); - - //Construct a shared memory - MyVector *myvector = - segment.construct("MyVector") //object name - (alloc_inst);//first ctor parameter - - //Insert data in the vector - for(int i = 0; i < 100; ++i){ - myvector->push_back(i); - } - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_contB.cpp b/example/doc_contB.cpp deleted file mode 100644 index 4aad144..0000000 --- a/example/doc_contB.cpp +++ /dev/null @@ -1,57 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_contB -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //A special shared memory where we can - //construct objects associated with a name. - //Connect to the already created shared memory segment - //and initialize needed resources - managed_shared_memory segment - (open_only - ,"MySharedMemory"); //segment name - - //Alias an STL compatible allocator of ints that allocates ints from the managed - //shared memory segment. This allocator will allow to place containers - //in managed shared memory segments - typedef allocator - ShmemAllocator; - - //Alias a vector that uses the previous STL-like allocator - typedef vector MyVector; - - //Find the vector using the c-string name - MyVector *myvector = segment.find("MyVector").first; - - //Use vector in reverse order - std::sort(myvector->rbegin(), myvector->rend()); - // . . . - - //When done, destroy the vector from the segment - segment.destroy("MyVector"); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_file_mapping.cpp b/example/doc_file_mapping.cpp index 568f577..3286cef 100644 --- a/example/doc_file_mapping.cpp +++ b/example/doc_file_mapping.cpp @@ -13,35 +13,36 @@ #include #include #include +#include +#include #include #include -#include //std::remove +#include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; - try{ - //Create a file - std::filebuf fbuf; - fbuf.open("file.bin", std::ios_base::in | std::ios_base::out - | std::ios_base::trunc | std::ios_base::binary); + const std::size_t FileSize = 10000; + if(argc == 1){ //Parent process executes this + { //Create a file + std::filebuf fbuf; + fbuf.open("file.bin", std::ios_base::in | std::ios_base::out + | std::ios_base::trunc | std::ios_base::binary); + //Set the size + fbuf.pubseekoff(FileSize-1, std::ios_base::beg); + fbuf.sputc(0); + } + //Remove file on exit + struct file_remove + { + ~file_remove (){ file_mapping::remove("file.bin"); } + } destroy_on_exit; - //Set the size - fbuf.pubseekoff(9999, std::ios_base::beg); - fbuf.sputc(0); - fbuf.close(); - - //Create a file mapping. + //Create a file mapping file_mapping m_file("file.bin", read_write); - //Map the whole file in this process - mapped_region region - (m_file //What to map - ,read_write //Map it as read-write - ); - - if(region.get_size() != 10000) - return 1; + //Map the whole file with read-write permissions in this process + mapped_region region(m_file, read_write); //Get the address of the mapped region void * addr = region.get_address(); @@ -50,12 +51,42 @@ int main () //Write all the memory to 1 std::memset(addr, 1, size); + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; } - catch(interprocess_exception &ex){ - std::remove("file.bin"); - std::cout << ex.what() << std::endl; - return 1; + else{ //Child process executes this + { //Open the file mapping and map it as read-only + file_mapping m_file ("file.bin", read_only); + mapped_region region(m_file, read_only); + + //Get the address of the mapped region + void * addr = region.get_address(); + std::size_t size = region.get_size(); + + //Check that memory was initialized to 1 + const char *mem = static_cast(addr); + for(std::size_t i = 0; i < size; ++i) + if(*mem++ != 1) + return 1; //Error checking memory + } + { //Now test it reading the file + std::filebuf fbuf; + fbuf.open("file.bin", std::ios_base::in | std::ios_base::binary); + + //Read it to memory + std::vector vect(FileSize, 0); + fbuf.sgetn(&vect[0], std::streamsize(vect.size())); + + //Check that memory was initialized to 1 + const char *mem = static_cast(&vect[0]); + for(std::size_t i = 0; i < FileSize; ++i) + if(*mem++ != 1) + return 1; //Error checking memory + } } + return 0; } //] diff --git a/example/doc_file_mapping2.cpp b/example/doc_file_mapping2.cpp deleted file mode 100644 index 058963f..0000000 --- a/example/doc_file_mapping2.cpp +++ /dev/null @@ -1,74 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_file_mapping2 -#include -#include -#include -#include -#include -#include //std::remove -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //Open the file mapping - file_mapping m_file ("file.bin", read_only); - - //Map the whole file in this process - mapped_region region - (m_file //What to map - ,read_only //Map it as read-only - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - std::size_t size = region.get_size(); - - //Check that memory was initialized to 1 - const char *mem = static_cast(addr); - for(std::size_t i = 0; i < size; ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - - //Now test it reading the file - std::filebuf fbuf; - fbuf.open("file.bin", std::ios_base::in | std::ios_base::binary); - - //Read it to memory - std::vector vect(region.get_size(), 0); - fbuf.sgetn(&vect[0], std::streamsize(vect.size())); - - //Check that memory was initialized to 1 - mem = static_cast(&vect[0]); - for(std::size_t i = 0; i < size; ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - - std::cout << "Test successful!" << std::endl; - } - catch(interprocess_exception &ex){ - std::remove("file.bin"); - std::cout << "Unexpected exception: " << ex.what() << std::endl; - return 1; - } - std::remove("file.bin"); - return 0; -} -//] -#include diff --git a/example/doc_intrusive.cpp b/example/doc_intrusive.cpp index 1f898ad..1548959 100644 --- a/example/doc_intrusive.cpp +++ b/example/doc_intrusive.cpp @@ -7,6 +7,7 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// + #include #include //[doc_intrusive @@ -68,42 +69,40 @@ class intrusive_ptr_owner : m_intrusive_ptr(ptr){} }; -int main () +int main() { - shared_memory_object::remove("my_shmem"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory shmem(create_only, "my_shmem", 10000); + //Create shared memory + managed_shared_memory shmem(create_only, "MySharedMemory", 10000); - //Create the unique reference counted object in shared memory - N::reference_counted_class *ref_counted = - shmem.construct - ("ref_counted")(shmem.get_segment_manager()); + //Create the unique reference counted object in shared memory + N::reference_counted_class *ref_counted = + shmem.construct + ("ref_counted")(shmem.get_segment_manager()); - //Create an array of ten intrusive pointer owners in shared memory - intrusive_ptr_owner *intrusive_owner_array = - shmem.construct - (anonymous_instance)[10](ref_counted); + //Create an array of ten intrusive pointer owners in shared memory + intrusive_ptr_owner *intrusive_owner_array = + shmem.construct + (anonymous_instance)[10](ref_counted); - //Now test that reference count is ten - if(ref_counted->use_count() != 10) - return 1; + //Now test that reference count is ten + if(ref_counted->use_count() != 10) + return 1; - //Now destroy the array of intrusive pointer owners - //This should destroy every intrusive_ptr and because of - //that reference_counted_class will be destroyed - shmem.destroy_ptr(intrusive_owner_array); + //Now destroy the array of intrusive pointer owners + //This should destroy every intrusive_ptr and because of + //that reference_counted_class will be destroyed + shmem.destroy_ptr(intrusive_owner_array); - //Now the reference counted object should have been destroyed - if(shmem.find("ref_counted").first) - return 1; - } - catch(...){ - shared_memory_object::remove("my_shmem"); - throw; - } - shared_memory_object::remove("my_shmem"); + //Now the reference counted object should have been destroyed + if(shmem.find("ref_counted").first) + return 1; //Success! return 0; } diff --git a/example/doc_ipc_message.cpp b/example/doc_ipc_message.cpp new file mode 100644 index 0000000..edceb85 --- /dev/null +++ b/example/doc_ipc_message.cpp @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +//[run_ipc_message +#include +#include //std::system +#include + +int main (int argc, char *argv[]) +{ + using namespace boost::interprocess; + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a managed shared memory segment + managed_shared_memory segment(create_only, "MySharedMemory", 65536); + + //Allocate a portion of the segment (raw memory) + std::size_t free_memory = segment.get_free_memory(); + void * shptr = segment.allocate(1024/*bytes to allocate*/); + + //Check invariant + if(free_memory <= segment.get_free_memory()) + return 1; + + //An handle from the base address can identify any byte of the shared + //memory segment even if it is mapped in different base addresses + managed_shared_memory::handle_t handle = segment.get_handle_from_address(shptr); + std::stringstream s; + s << argv[0] << " " << handle << std::ends; + + //Launch child process + if(0 != std::system(s.str().c_str())) + return 1; + //Check memory has been freed + if(free_memory != segment.get_free_memory()) + return 1; + } + else{ + //Open managed segment + managed_shared_memory segment(open_only, "MySharedMemory"); + + //An handle from the base address can identify any byte of the shared + //memory segment even if it is mapped in different base addresses + managed_shared_memory::handle_t handle = 0; + + //Obtain handle value + std::stringstream s; s << argv[1]; s >> handle; + + //Get buffer local address from handle + void *msg = segment.get_address_from_handle(handle); + + //Deallocate previously allocated memory + segment.deallocate(msg); + } + return 0; +} +//] +#include diff --git a/example/doc_ipc_messageA.cpp b/example/doc_ipc_messageA.cpp deleted file mode 100644 index 3a730f1..0000000 --- a/example/doc_ipc_messageA.cpp +++ /dev/null @@ -1,55 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_ipc_messageA -#include - -int main () -{ - using namespace boost::interprocess; - - //A special shared memory from which we are - //able to allocate raw memory buffers. - //First remove any old shared memory of the same name, create - //the shared memory segment and initialize needed resources - shared_memory_object::remove("MySharedMemory"); - try{ - managed_shared_memory segment - (create_only, - "MySharedMemory", //segment name - 65536); //segment size in bytes - - //Allocate a portion of the segment - void * shptr = segment.allocate(1024/*bytes to allocate*/); - - //An handle from the base address can identify any byte of the shared - //memory segment even if it is mapped in different base addresses - managed_shared_memory::handle_t handle = segment.get_handle_from_address(shptr); - (void)handle; - // Copy message to buffer - // . . . - // Send handle to other process - // . . . - // Wait response from other process - // . . . - - //Deallocate the portion previously allocated - segment.deallocate(shptr); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_ipc_messageB.cpp b/example/doc_ipc_messageB.cpp deleted file mode 100644 index 2c30d1a..0000000 --- a/example/doc_ipc_messageB.cpp +++ /dev/null @@ -1,47 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_ipc_messageB -#include - -int main () -{ - using namespace boost::interprocess; - - try{ - //A special shared memory from which we are - //able to allocate raw memory buffers. - //Connect to the already created shared memory segment - //and initialize needed resources - managed_shared_memory segment(open_only, "MySharedMemory"); //segment name - - //An handle from the base address can identify any byte of the shared - //memory segment even if it is mapped in different base addresses - managed_shared_memory::handle_t handle = 0; - - //Wait handle msg from the other process and put it in - //"handle" local variable - //Get buffer local address from handle - void *msg = segment.get_address_from_handle(handle); - (void)msg; - //Do anything with msg - //. . . - //Send ack to sender process - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_managed_aligned_allocation.cpp b/example/doc_managed_aligned_allocation.cpp index 2af9266..f94f569 100644 --- a/example/doc_managed_aligned_allocation.cpp +++ b/example/doc_managed_aligned_allocation.cpp @@ -16,53 +16,52 @@ int main() { using namespace boost::interprocess; + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Managed memory segment that allocates portions of a shared memory //segment with the default management algorithm - shared_memory_object::remove("MyManagedShm"); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 65536); - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 65536); + const std::size_t Alignment = 128; - const std::size_t Alignment = 128; + //Allocate 100 bytes aligned to Alignment from segment, throwing version + void *ptr = managed_shm.allocate_aligned(100, Alignment); - //Allocate 100 bytes aligned to Alignment from segment, throwing version - void *ptr = managed_shm.allocate_aligned(100, Alignment); + //Check alignment + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); - //Check alignment - assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); + //Deallocate it + managed_shm.deallocate(ptr); - //Deallocate it - managed_shm.deallocate(ptr); + //Non throwing version + ptr = managed_shm.allocate_aligned(100, Alignment, std::nothrow); - //Non throwing version - ptr = managed_shm.allocate_aligned(100, Alignment, std::nothrow); + //Check alignment + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); - //Check alignment - assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); + //Deallocate it + managed_shm.deallocate(ptr); - //Deallocate it - managed_shm.deallocate(ptr); + //If we want to efficiently allocate aligned blocks of memory + //use managed_shared_memory::PayloadPerAllocation value + assert(Alignment > managed_shared_memory::PayloadPerAllocation); - //If we want to efficiently allocate aligned blocks of memory - //use managed_shared_memory::PayloadPerAllocation value - assert(Alignment > managed_shared_memory::PayloadPerAllocation); + //This allocation will maximize the size of the aligned memory + //and will increase the possibility of finding more aligned memory + ptr = managed_shm.allocate_aligned + (3*Alignment - managed_shared_memory::PayloadPerAllocation, Alignment); - //This allocation will maximize the size of the aligned memory - //and will increase the possibility of finding more aligned memory - ptr = managed_shm.allocate_aligned - (3*Alignment - managed_shared_memory::PayloadPerAllocation, Alignment); + //Check alignment + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); - //Check alignment - assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); + //Deallocate it + managed_shm.deallocate(ptr); - //Deallocate it - managed_shm.deallocate(ptr); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); return 0; } //] diff --git a/example/doc_managed_allocation_command.cpp b/example/doc_managed_allocation_command.cpp index b77f838..8023c6d 100644 --- a/example/doc_managed_allocation_command.cpp +++ b/example/doc_managed_allocation_command.cpp @@ -16,73 +16,71 @@ int main() { using namespace boost::interprocess; + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Managed memory segment that allocates portions of a shared memory //segment with the default management algorithm - shared_memory_object::remove("MyManagedShm"); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 10000*sizeof(std::size_t)); - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 10000*sizeof(std::size_t)); + //Allocate at least 100 bytes, 1000 bytes if possible + std::size_t received_size, min_size = 100, preferred_size = 1000; + std::size_t *ptr = managed_shm.allocation_command + (boost::interprocess::allocate_new, min_size, preferred_size, received_size).first; - //Allocate at least 100 bytes, 1000 bytes if possible - std::size_t received_size, min_size = 100, preferred_size = 1000; - std::size_t *ptr = managed_shm.allocation_command - (allocate_new, min_size, preferred_size, received_size).first; + //Received size must be bigger than min_size + assert(received_size >= min_size); - //Received size must be bigger than min_size - assert(received_size >= min_size); + //Get free memory + std::size_t free_memory_after_allocation = managed_shm.get_free_memory(); - //Get free memory - std::size_t free_memory_after_allocation = managed_shm.get_free_memory(); + //Now write the data + for(std::size_t i = 0; i < received_size; ++i) ptr[i] = i; - //Now write the data - for(std::size_t i = 0; i < received_size; ++i) ptr[i] = i; + //Now try to triplicate the buffer. We won't admit an expansion + //lower to the double of the original buffer. + //This "should" be successful since no other class is allocating + //memory from the segment + std::size_t expanded_size; + std::pair ret = managed_shm.allocation_command + (boost::interprocess::expand_fwd, received_size*2, received_size*3, expanded_size, ptr); - //Now try to triplicate the buffer. We won't admit an expansion - //lower to the double of the original buffer. - //This "should" be successful since no other class is allocating - //memory from the segment - std::size_t expanded_size; - std::pair ret = managed_shm.allocation_command - (expand_fwd, received_size*2, received_size*3, expanded_size, ptr); + //Check invariants + assert(ret.second == true); + assert(ret.first == ptr); + assert(expanded_size >= received_size*2); - //Check invariants - assert(ret.second == true); - assert(ret.first == ptr); - assert(expanded_size >= received_size*2); + //Get free memory and compare + std::size_t free_memory_after_expansion = managed_shm.get_free_memory(); + assert(free_memory_after_expansion < free_memory_after_allocation); - //Get free memory and compare - std::size_t free_memory_after_expansion = managed_shm.get_free_memory(); - assert(free_memory_after_expansion < free_memory_after_allocation); + //Write new values + for(std::size_t i = received_size; i < expanded_size; ++i) ptr[i] = i; - //Write new values - for(std::size_t i = received_size; i < expanded_size; ++i) ptr[i] = i; + //Try to shrink approximately to min_size, but the new size + //should be smaller than min_size*2. + //This "should" be successful since no other class is allocating + //memory from the segment + std::size_t shrunk_size; + ret = managed_shm.allocation_command + (boost::interprocess::shrink_in_place, min_size*2, min_size, shrunk_size, ptr); - //Try to shrink approximately to min_size, but the new size - //should be smaller than min_size*2. - //This "should" be successful since no other class is allocating - //memory from the segment - std::size_t shrunk_size; - ret = managed_shm.allocation_command - (shrink_in_place, min_size*2, min_size, shrunk_size, ptr); + //Check invariants + assert(ret.second == true); + assert(ret.first == ptr); + assert(shrunk_size <= min_size*2); + assert(shrunk_size >= min_size); - //Check invariants - assert(ret.second == true); - assert(ret.first == ptr); - assert(shrunk_size <= min_size*2); - assert(shrunk_size >= min_size); + //Get free memory and compare + std::size_t free_memory_after_shrinking = managed_shm.get_free_memory(); + assert(free_memory_after_shrinking > free_memory_after_expansion); - //Get free memory and compare - std::size_t free_memory_after_shrinking = managed_shm.get_free_memory(); - assert(free_memory_after_shrinking > free_memory_after_expansion); - - //Deallocate the buffer - managed_shm.deallocate(ptr); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); + //Deallocate the buffer + managed_shm.deallocate(ptr); return 0; } //] diff --git a/example/doc_managed_construction_info.cpp b/example/doc_managed_construction_info.cpp index 8a3f711..f573181 100644 --- a/example/doc_managed_construction_info.cpp +++ b/example/doc_managed_construction_info.cpp @@ -21,41 +21,39 @@ class my_class int main() { using namespace boost::interprocess; - typedef managed_shared_memory msm; - shared_memory_object::remove("MyManagedShm"); - try{ - msm managed_shm(create_only, "MyManagedShm", 10000*sizeof(std::size_t)); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Construct objects - my_class *named_object = managed_shm.construct("Object name")[1](); - my_class *unique_object = managed_shm.construct(unique_instance)[2](); - my_class *anon_object = managed_shm.construct(anonymous_instance)[3](); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 10000*sizeof(std::size_t)); - //Now test "get_instance_name" function. - assert(0 == std::strcmp(msm::get_instance_name(named_object), "Object name")); - assert(0 == msm::get_instance_name(unique_object)); - assert(0 == msm::get_instance_name(anon_object)); + //Construct objects + my_class *named_object = managed_shm.construct("Object name")[1](); + my_class *unique_object = managed_shm.construct(unique_instance)[2](); + my_class *anon_object = managed_shm.construct(anonymous_instance)[3](); - //Now test "get_instance_type" function. - assert(named_type == msm::get_instance_type(named_object)); - assert(unique_type == msm::get_instance_type(unique_object)); - assert(anonymous_type == msm::get_instance_type(anon_object)); + //Now test "get_instance_name" function. + assert(0 == std::strcmp(managed_shared_memory::get_instance_name(named_object), "Object name")); + assert(0 == managed_shared_memory::get_instance_name(unique_object)); + assert(0 == managed_shared_memory::get_instance_name(anon_object)); - //Now test "get_instance_length" function. - assert(1 == msm::get_instance_length(named_object)); - assert(2 == msm::get_instance_length(unique_object)); - assert(3 == msm::get_instance_length(anon_object)); + //Now test "get_instance_type" function. + assert(named_type == managed_shared_memory::get_instance_type(named_object)); + assert(unique_type == managed_shared_memory::get_instance_type(unique_object)); + assert(anonymous_type == managed_shared_memory::get_instance_type(anon_object)); - managed_shm.destroy_ptr(named_object); - managed_shm.destroy_ptr(unique_object); - managed_shm.destroy_ptr(anon_object); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); + //Now test "get_instance_length" function. + assert(1 == managed_shared_memory::get_instance_length(named_object)); + assert(2 == managed_shared_memory::get_instance_length(unique_object)); + assert(3 == managed_shared_memory::get_instance_length(anon_object)); + + managed_shm.destroy_ptr(named_object); + managed_shm.destroy_ptr(unique_object); + managed_shm.destroy_ptr(anon_object); return 0; } //] diff --git a/example/doc_managed_copy_on_write.cpp b/example/doc_managed_copy_on_write.cpp index 304be95..7daa76e 100644 --- a/example/doc_managed_copy_on_write.cpp +++ b/example/doc_managed_copy_on_write.cpp @@ -11,7 +11,6 @@ //[doc_managed_copy_on_write #include #include //std::fstream -#include //std::remove #include //std::distance int main() @@ -19,8 +18,8 @@ int main() using namespace boost::interprocess; //Try to erase any previous managed segment with the same name - std::remove("MyManagedFile"); - std::remove("MyManagedFile2"); + file_mapping::remove("MyManagedFile"); + file_mapping::remove("MyManagedFile2"); remove_file_on_destroy destroyer1("MyManagedFile"); remove_file_on_destroy destroyer2("MyManagedFile2"); diff --git a/example/doc_managed_external_buffer.cpp b/example/doc_managed_external_buffer.cpp index 051b430..f9e9855 100644 --- a/example/doc_managed_external_buffer.cpp +++ b/example/doc_managed_external_buffer.cpp @@ -43,7 +43,9 @@ int main() //be stored in the static_buffer! MyBufferList *list = objects_in_static_memory.construct(L"MyList") (objects_in_static_memory.get_segment_manager()); - + //<- + (void)list; + //-> //Since the allocation algorithm from wmanaged_external_buffer uses relative //pointers and all the pointers constructed int the static memory point //to objects in the same segment, we can create another static buffer diff --git a/example/doc_managed_grow.cpp b/example/doc_managed_grow.cpp index ee7a31e..1523222 100644 --- a/example/doc_managed_grow.cpp +++ b/example/doc_managed_grow.cpp @@ -21,48 +21,49 @@ class MyClass int main() { using namespace boost::interprocess; - try{ - { //Remove old shared memory if present - shared_memory_object::remove("MyManagedShm"); - //Create a managed shared memory - managed_shared_memory shm(create_only, "MyManagedShm", 1000); - //Check size - assert(shm.get_size() == 1000); - //Construct a named object - MyClass *myclass = shm.construct("MyClass")(); - //The managed segment is unmapped here - } - { - //Now that the segment is not mapped grow it adding extra 500 bytes - managed_shared_memory::grow("MyManagedShm", 500); - //Map it again - managed_shared_memory shm(open_only, "MyManagedShm"); - //Check size - assert(shm.get_size() == 1500); - //Check "MyClass" is still there - MyClass *myclass = shm.find("MyClass").first; - assert(myclass != 0); - //The managed segment is unmapped here - } - { - //Now minimize the size of the segment - managed_shared_memory::shrink_to_fit("MyManagedShm"); - //Map it again - managed_shared_memory shm(open_only, "MyManagedShm"); - //Check size - assert(shm.get_size() < 1000); - //Check "MyClass" is still there - MyClass *myclass = shm.find("MyClass").first; - assert(myclass != 0); - //The managed segment is unmapped here - } + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + { + //Create a managed shared memory + managed_shared_memory shm(create_only, "MySharedMemory", 1000); + //Check size + assert(shm.get_size() == 1000); + //Construct a named object + MyClass *myclass = shm.construct("MyClass")(); + //The managed segment is unmapped here + //<- + (void)myclass; + //-> } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; + { + //Now that the segment is not mapped grow it adding extra 500 bytes + managed_shared_memory::grow("MySharedMemory", 500); + //Map it again + managed_shared_memory shm(open_only, "MySharedMemory"); + //Check size + assert(shm.get_size() == 1500); + //Check "MyClass" is still there + MyClass *myclass = shm.find("MyClass").first; + assert(myclass != 0); + //The managed segment is unmapped here + } + { + //Now minimize the size of the segment + managed_shared_memory::shrink_to_fit("MySharedMemory"); + //Map it again + managed_shared_memory shm(open_only, "MySharedMemory"); + //Check size + assert(shm.get_size() < 1000); + //Check "MyClass" is still there + MyClass *myclass = shm.find("MyClass").first; + assert(myclass != 0); + //The managed segment is unmapped here } - //Remove the managed segment - shared_memory_object::remove("MyManagedShm"); return 0; } //] diff --git a/example/doc_managed_mapped_file.cpp b/example/doc_managed_mapped_file.cpp index 2dacbd0..091a7eb 100644 --- a/example/doc_managed_mapped_file.cpp +++ b/example/doc_managed_mapped_file.cpp @@ -24,59 +24,67 @@ int main () { const char *FileName = "file_mapping"; const std::size_t FileSize = 1000; - std::remove(FileName); + file_mapping::remove(FileName); try{ - managed_mapped_file mfile_memory(create_only, FileName, FileSize); - MyList * mylist = mfile_memory.construct("MyList") - (mfile_memory.get_segment_manager()); + std::size_t old_size = 0; + managed_mapped_file::handle_t list_handle; + { + managed_mapped_file mfile_memory(create_only, FileName, FileSize); + MyList *mylist = mfile_memory.construct("MyList") + (mfile_memory.get_segment_manager()); - //Obtain handle, that identifies the list in the buffer - managed_mapped_file::handle_t list_handle = mfile_memory.get_handle_from_address(mylist); + //Obtain handle, that identifies the list in the buffer + list_handle = mfile_memory.get_handle_from_address(mylist); - //Fill list until there is no more room in the file - try{ - while(1) { - mylist->insert(mylist->begin(), 0); + //Fill list until there is no more room in the file + try{ + while(1) { + mylist->insert(mylist->begin(), 0); + } } + catch(const bad_alloc &){ + //mapped file is full + } + //Let's obtain the size of the list + old_size = mylist->size(); } - catch(const bad_alloc &){ - //mapped file is full - } - //Let's obtain the size of the list - std::size_t old_size = mylist->size(); - //To make the list bigger, let's increase the mapped file //in FileSize bytes more. - //mfile_memory.grow(FileSize); + managed_mapped_file::grow(FileName, FileSize*2); - //If mapping address has changed, the old pointer is invalid, - //so use previously obtained handle to find the new pointer. - mylist = static_cast - (mfile_memory.get_address_from_handle(list_handle)); - - //Fill list until there is no more room in the file - try{ - while(1) { - mylist->insert(mylist->begin(), 0); + { + managed_mapped_file mfile_memory(open_only, FileName); + + + //If mapping address has changed, the old pointer is invalid, + //so use previously obtained handle to find the new pointer. + MyList *mylist = static_cast + (mfile_memory.get_address_from_handle(list_handle)); + + //Fill list until there is no more room in the file + try{ + while(1) { + mylist->insert(mylist->begin(), 0); + } } + catch(const bad_alloc &){ + //mapped file is full + } + + //Let's obtain the new size of the list + std::size_t new_size = mylist->size(); + + assert(new_size > old_size); + + //Destroy list + mfile_memory.destroy_ptr(mylist); } - catch(const bad_alloc &){ - //mapped file is full - } - - //Let's obtain the new size of the list - std::size_t new_size = mylist->size(); - - assert(new_size > old_size); - - //Destroy list - mfile_memory.destroy_ptr(mylist); } catch(...){ - std::remove(FileName); + file_mapping::remove(FileName); throw; } - std::remove(FileName); + file_mapping::remove(FileName); return 0; } diff --git a/example/doc_managed_multiple_allocation.cpp b/example/doc_managed_multiple_allocation.cpp index 3d508cf..e1ac02f 100644 --- a/example/doc_managed_multiple_allocation.cpp +++ b/example/doc_managed_multiple_allocation.cpp @@ -10,69 +10,59 @@ #include //[doc_managed_multiple_allocation #include +#include //boost::interprocess::move #include //assert #include //std::memset #include //std::nothrow #include //std::vector + int main() { using namespace boost::interprocess; - typedef managed_shared_memory::multiallocation_iterator multiallocation_iterator; + typedef managed_shared_memory::multiallocation_chain multiallocation_chain; - //Try to erase any previous managed segment with the same name - shared_memory_object::remove("MyManagedShm"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 65536); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 65536); - //Allocate 16 elements of 100 bytes in a single call. Non-throwing version. - multiallocation_iterator beg_it = managed_shm.allocate_many(100, 16, std::nothrow); + //Allocate 16 elements of 100 bytes in a single call. Non-throwing version. + multiallocation_chain chain(managed_shm.allocate_many(100, 16, std::nothrow)); - //To check for an error, we can use a boolean expression - //or compare it with a default constructed iterator - assert(!beg_it == (beg_it == multiallocation_iterator())); - - //Check if the memory allocation was successful - if(!beg_it) return 1; + //Check if the memory allocation was successful + if(chain.empty()) return 1; - //Allocated buffers - std::vector allocated_buffers; + //Allocated buffers + std::vector allocated_buffers; - //Initialize our data - for( multiallocation_iterator it = beg_it, end_it; it != end_it; ){ - allocated_buffers.push_back(&*it); - //The iterator must be incremented before overwriting memory - //because otherwise, the iterator is invalidated. - std::memset(&*it++, 0, 100); - } - - //Now deallocate - while(!allocated_buffers.empty()){ - managed_shm.deallocate(allocated_buffers.back()); - allocated_buffers.pop_back(); - } - - //Allocate 10 buffers of different sizes in a single call. Throwing version - std::size_t sizes[10]; - for(std::size_t i = 0; i < 10; ++i) - sizes[i] = i*3; - - beg_it = managed_shm.allocate_many(sizes, 10); - - //Iterate each allocated buffer and deallocate - //The "end" condition can be also checked with operator! - for(multiallocation_iterator it = beg_it; it;){ - //The iterator must be incremented before overwriting memory - //because otherwise, the iterator is invalidated. - managed_shm.deallocate(&*it++); - } + //Initialize our data + while(!chain.empty()){ + void *buf = chain.front(); + chain.pop_front(); + allocated_buffers.push_back(buf); + //The iterator must be incremented before overwriting memory + //because otherwise, the iterator is invalidated. + std::memset(buf, 0, 100); } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; + + //Now deallocate + while(!allocated_buffers.empty()){ + managed_shm.deallocate(allocated_buffers.back()); + allocated_buffers.pop_back(); } - shared_memory_object::remove("MyManagedShm"); + + //Allocate 10 buffers of different sizes in a single call. Throwing version + std::size_t sizes[10]; + for(std::size_t i = 0; i < 10; ++i) + sizes[i] = i*3; + + chain = managed_shm.allocate_many(sizes, 10); + managed_shm.deallocate_many(boost::interprocess::move(chain)); return 0; } //] diff --git a/example/doc_managed_raw_allocation.cpp b/example/doc_managed_raw_allocation.cpp index 0c31b12..ac7cf24 100644 --- a/example/doc_managed_raw_allocation.cpp +++ b/example/doc_managed_raw_allocation.cpp @@ -15,29 +15,28 @@ int main() { using namespace boost::interprocess; + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Managed memory segment that allocates portions of a shared memory //segment with the default management algorithm - shared_memory_object::remove("MyManagedShm"); - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 65536); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 65536); - //Allocate 100 bytes of memory from segment, throwing version - void *ptr = managed_shm.allocate(100); + //Allocate 100 bytes of memory from segment, throwing version + void *ptr = managed_shm.allocate(100); - //Deallocate it - managed_shm.deallocate(ptr); + //Deallocate it + managed_shm.deallocate(ptr); - //Non throwing version - ptr = managed_shm.allocate(100, std::nothrow); + //Non throwing version + ptr = managed_shm.allocate(100, std::nothrow); - //Deallocate it - managed_shm.deallocate(ptr); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); + //Deallocate it + managed_shm.deallocate(ptr); return 0; } //] diff --git a/example/doc_map.cpp b/example/doc_map.cpp index 5a7da62..a1b2b14 100644 --- a/example/doc_map.cpp +++ b/example/doc_map.cpp @@ -19,56 +19,55 @@ int main () { using namespace boost::interprocess; + + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Shared memory front-end that is able to construct objects //associated with a c-string. Erase previous shared memory with the name //to be used and create the memory segment at the specified address and initialize resources - shared_memory_object::remove("MySharedMemory"); + managed_shared_memory segment + (create_only + ,"MySharedMemory" //segment name + ,65536); //segment size in bytes - try{ - managed_shared_memory segment - (create_only - ,"MySharedMemory" //segment name - ,65536); //segment size in bytes + //Note that map's value_type is std::pair, + //so the allocator must allocate that pair. + typedef int KeyType; + typedef float MappedType; + typedef std::pair ValueType; - //Note that map's value_type is std::pair, - //so the allocator must allocate that pair. - typedef int KeyType; - typedef float MappedType; - typedef std::pair ValueType; + //Alias an STL compatible allocator of for the map. + //This allocator will allow to place containers + //in managed shared memory segments + typedef allocator + ShmemAllocator; - //Alias an STL compatible allocator of for the map. - //This allocator will allow to place containers - //in managed shared memory segments - typedef allocator - ShmemAllocator; + //Alias a map of ints that uses the previous STL-like allocator. + //Note that the third parameter argument is the ordering function + //of the map, just like with std::map, used to compare the keys. + typedef map, ShmemAllocator> MyMap; - //Alias a map of ints that uses the previous STL-like allocator. - //Note that the third parameter argument is the ordering function - //of the map, just like with std::map, used to compare the keys. - typedef map, ShmemAllocator> MyMap; + //Initialize the shared memory STL-compatible allocator + ShmemAllocator alloc_inst (segment.get_segment_manager()); - //Initialize the shared memory STL-compatible allocator - ShmemAllocator alloc_inst (segment.get_segment_manager()); + //Construct a shared memory map. + //Note that the first parameter is the comparison function, + //and the second one the allocator. + //This the same signature as std::map's constructor taking an allocator + MyMap *mymap = + segment.construct("MyMap") //object name + (std::less() //first ctor parameter + ,alloc_inst); //second ctor parameter - //Construct a shared memory map. - //Note that the first parameter is the comparison function, - //and the second one the allocator. - //This the same signature as std::map's constructor taking an allocator - MyMap *mymap = - segment.construct("MyMap") //object name - (std::less() //first ctor parameter - ,alloc_inst); //second ctor parameter - - //Insert data in the map - for(int i = 0; i < 100; ++i){ - mymap->insert(std::pair(i, (float)i)); - } + //Insert data in the map + for(int i = 0; i < 100; ++i){ + mymap->insert(std::pair(i, (float)i)); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_move_containers.cpp b/example/doc_move_containers.cpp index aeadf61..c831bda 100644 --- a/example/doc_move_containers.cpp +++ b/example/doc_move_containers.cpp @@ -28,58 +28,57 @@ int main () typedef allocator StringAllocator; typedef vector MyShmStringVector; - //Remove old shared memory and create new one - shared_memory_object::remove("myshm"); - try{ - managed_shared_memory shm(create_only, "myshm", 10000); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create allocators - CharAllocator charallocator (shm.get_segment_manager()); - StringAllocator stringallocator(shm.get_segment_manager()); + managed_shared_memory shm(create_only, "MySharedMemory", 10000); - //Create a vector of strings in shared memory. - MyShmStringVector *myshmvector = - shm.construct("myshmvector")(stringallocator); + //Create allocators + CharAllocator charallocator (shm.get_segment_manager()); + StringAllocator stringallocator(shm.get_segment_manager()); - //Insert 50 strings in shared memory. The strings will be allocated - //only once and no string copy-constructor will be called when inserting - //strings, leading to a great performance. - MyShmString string_to_compare(charallocator); - string_to_compare = "this is a long, long, long, long, long, long, string..."; - - myshmvector->reserve(50); - for(int i = 0; i < 50; ++i){ - MyShmString move_me(string_to_compare); - //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(boost::interprocess::move(move_me)); + //Create a vector of strings in shared memory. + MyShmStringVector *myshmvector = + shm.construct("myshmvector")(stringallocator); - //The source string is in default constructed state - assert(move_me.empty()); + //Insert 50 strings in shared memory. The strings will be allocated + //only once and no string copy-constructor will be called when inserting + //strings, leading to a great performance. + MyShmString string_to_compare(charallocator); + string_to_compare = "this is a long, long, long, long, long, long, string..."; + + myshmvector->reserve(50); + for(int i = 0; i < 50; ++i){ + MyShmString move_me(string_to_compare); + //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(boost::interprocess::move(move_me)); - //The newly created string will be equal to the "move_me"'s old contents - assert(myshmvector->back() == string_to_compare); - } + //The source string is in default constructed state + assert(move_me.empty()); - //Now erase a string... - myshmvector->pop_back(); - - //...And insert one in the first position. - //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(), boost::interprocess::move(string_to_compare)); - - //Destroy vector. This will free all strings that the vector contains - shm.destroy_ptr(myshmvector); + //The newly created string will be equal to the "move_me"'s old contents + assert(myshmvector->back() == string_to_compare); } - catch(...){ - shared_memory_object::remove("myshmvector"); - throw; - } - shared_memory_object::remove("myshmvector"); + + //Now erase a string... + myshmvector->pop_back(); + + //...And insert one in the first position. + //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(), boost::interprocess::move(string_to_compare)); + + //Destroy vector. This will free all strings that the vector contains + shm.destroy_ptr(myshmvector); return 0; } //] #include + diff --git a/example/doc_multi_index.cpp b/example/doc_multi_index.cpp index 24cbd63..dff5bd4 100644 --- a/example/doc_multi_index.cpp +++ b/example/doc_multi_index.cpp @@ -61,30 +61,27 @@ typedef bmi::multi_index_container< int main () { - //Erase previous shared memory with the name - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only,"MySharedMemory", 65536); + //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 + //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"); + //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)); return 0; } //] diff --git a/example/doc_named_allocA.cpp b/example/doc_named_alloc.cpp similarity index 50% rename from example/doc_named_allocA.cpp rename to example/doc_named_alloc.cpp index 84eb889..30767a8 100644 --- a/example/doc_named_allocA.cpp +++ b/example/doc_named_alloc.cpp @@ -9,24 +9,28 @@ ////////////////////////////////////////////////////////////////////////////// #include #include -//[doc_named_allocA +//[doc_named_alloc #include +#include //std::system +#include +#include #include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; typedef std::pair MyType; - try{ - //A special shared memory where we can - //construct objects associated with a name. - //First remove any old shared memory of the same name, create - //the shared memory segment and initialize needed resources - shared_memory_object::remove("MySharedMemory"); - managed_shared_memory segment - //create segment name segment size - (create_only, "MySharedMemory", 65536); + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Construct managed shared memory + managed_shared_memory segment(create_only, "MySharedMemory", 65536); //Create an object of MyType initialized to {0.0, 0} MyType *instance = segment.construct @@ -49,12 +53,50 @@ int main () [3] //number of elements ( &float_initializer[0] //Iterator for the 1st ctor argument , &int_initializer[0]); //Iterator for the 2nd ctor argument + + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; + + //<- + (void)instance; + (void)array; + (void)array_it; + //-> + + //Check child has destroyed all objects + if(segment.find("MyType array").first || + segment.find("MyType instance").first || + segment.find("MyType array from it").first) + return 1; } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + else{ + //Open managed shared memory + managed_shared_memory segment(open_only, "MySharedMemory"); + + std::pair res; + + //Find the array + res = segment.find ("MyType array"); + //Length should be 10 + if(res.second != 10) return 1; + + //Find the object + res = segment.find ("MyType instance"); + //Length should be 1 + if(res.second != 1) return 1; + + //Find the array constructed from iterators + res = segment.find ("MyType array from it"); + //Length should be 3 + if(res.second != 3) return 1; + + //We're done, delete all the objects + segment.destroy("MyType array"); + segment.destroy("MyType instance"); + segment.destroy("MyType array from it"); } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_named_allocB.cpp b/example/doc_named_allocB.cpp deleted file mode 100644 index 8b6bb65..0000000 --- a/example/doc_named_allocB.cpp +++ /dev/null @@ -1,63 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_named_allocB -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - typedef std::pair MyType; - - try{ - //A special shared memory where we can - //construct objects associated with a name. - //Connect to the already created shared memory segment - //and initialize needed resources - managed_shared_memory segment(open_only, "MySharedMemory"); - - std::pair res; - - //Find the array - res = segment.find ("MyType array"); - //Length should be 10 - assert(res.second == 10); - - //Find the object - res = segment.find ("MyType instance"); - //Length should be 1 - assert(res.second == 1); - - //Find the array constructed from iterators - res = segment.find ("MyType array from it"); - //Length should be 3 - assert(res.second == 3); - - //Use data - // . . . - - //We're done, delete all the objects - segment.destroy("MyType array"); - segment.destroy("MyType instance"); - segment.destroy("MyType array from it"); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_named_mutex.cpp b/example/doc_named_mutex.cpp index 80e7f98..3ff1fa6 100644 --- a/example/doc_named_mutex.cpp +++ b/example/doc_named_mutex.cpp @@ -13,6 +13,7 @@ #include #include #include +#include int main () { @@ -37,10 +38,12 @@ int main () } catch(interprocess_exception &ex){ named_mutex::remove("fstream_named_mutex"); + std::remove("file_name"); std::cout << ex.what() << std::endl; return 1; } named_mutex::remove("fstream_named_mutex"); + std::remove("file_name"); return 0; } //] diff --git a/example/doc_node_allocator.cpp b/example/doc_node_allocator.cpp index 00ba3da..68087a0 100644 --- a/example/doc_node_allocator.cpp +++ b/example/doc_node_allocator.cpp @@ -18,46 +18,44 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a node_allocator that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef node_allocator - node_allocator_t; - node_allocator_t allocator_instance(segment.get_segment_manager()); + //Create a node_allocator that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef node_allocator + node_allocator_t; + node_allocator_t allocator_instance(segment.get_segment_manager()); - //Create another node_allocator. Since the segment manager address - //is the same, this node_allocator will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - node_allocator_t allocator_instance2(segment.get_segment_manager()); + //Create another node_allocator. Since the segment manager address + //is the same, this node_allocator will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + node_allocator_t allocator_instance2(segment.get_segment_manager()); - //Create another node_allocator using copy-constructor. This - //node_allocator will also be attached to the same pool - node_allocator_t allocator_instance3(allocator_instance2); + //Create another node_allocator using copy-constructor. This + //node_allocator will also be attached to the same pool + node_allocator_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index efa7930..8931177 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -24,45 +24,41 @@ struct list_node int main () { - //Destroy any previous shared memory with the name to be used. - //Create a special shared memory from which we can - //allocate buffers of raw memory. - shared_memory_object::remove("MySharedMemory"); - try{ - managed_shared_memory segment( - create_only, - "MySharedMemory", //segment name - 65536); //segment size in bytes + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create linked list with 10 nodes in shared memory - offset_ptr prev = 0, current, first; + managed_shared_memory segment( + create_only, + "MySharedMemory", //segment name + 65536); //segment size in bytes - int i; - for(i = 0; i < 10; ++i, prev = current){ - current = static_cast(segment.allocate(sizeof(list_node))); - current->value = i; - current->next = 0; + //Create linked list with 10 nodes in shared memory + offset_ptr prev = 0, current, first; - if(!prev) - first = current; - else - prev->next = current; - } + int i; + for(i = 0; i < 10; ++i, prev = current){ + current = static_cast(segment.allocate(sizeof(list_node))); + current->value = i; + current->next = 0; - //Communicate list to other processes - //. . . - //When done, destroy list - for(current = first; current; /**/){ - prev = current; - current = current->next; - segment.deallocate(prev.get()); - } + if(!prev) + first = current; + else + prev->next = current; } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + + //Communicate list to other processes + //. . . + //When done, destroy list + for(current = first; current; /**/){ + prev = current; + current = current->next; + segment.deallocate(prev.get()); } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_private_adaptive_pool.cpp b/example/doc_private_adaptive_pool.cpp index 8a5ac1e..38303ea 100644 --- a/example/doc_private_adaptive_pool.cpp +++ b/example/doc_private_adaptive_pool.cpp @@ -18,42 +18,40 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a private_adaptive_pool that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef private_adaptive_pool - private_adaptive_pool_t; - private_adaptive_pool_t allocator_instance(segment.get_segment_manager()); + //Create a private_adaptive_pool that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef private_adaptive_pool + private_adaptive_pool_t; + private_adaptive_pool_t allocator_instance(segment.get_segment_manager()); - //Create another private_adaptive_pool. - private_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); + //Create another private_adaptive_pool. + private_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); - //Although the segment manager address - //is the same, this private_adaptive_pool will have its own pool so - //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". - //"allocator_instance2" is NOT equal to "allocator_instance" - assert(allocator_instance != allocator_instance2); + //Although the segment manager address + //is the same, this private_adaptive_pool will have its own pool so + //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". + //"allocator_instance2" is NOT equal to "allocator_instance" + assert(allocator_instance != allocator_instance2); - //Create another adaptive_pool using copy-constructor. - private_adaptive_pool_t allocator_instance3(allocator_instance2); + //Create another adaptive_pool using copy-constructor. + private_adaptive_pool_t allocator_instance3(allocator_instance2); - //This allocator is also unequal to allocator_instance2 - assert(allocator_instance2 != allocator_instance3); + //This allocator is also unequal to allocator_instance2 + assert(allocator_instance2 != allocator_instance3); - //Pools are destroyed with the allocators - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Pools are destroyed with the allocators return 0; } //] diff --git a/example/doc_private_node_allocator.cpp b/example/doc_private_node_allocator.cpp index e35f804..bbb7648 100644 --- a/example/doc_private_node_allocator.cpp +++ b/example/doc_private_node_allocator.cpp @@ -18,42 +18,40 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a private_node_allocator that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef private_node_allocator - private_node_allocator_t; - private_node_allocator_t allocator_instance(segment.get_segment_manager()); + //Create a private_node_allocator that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef private_node_allocator + private_node_allocator_t; + private_node_allocator_t allocator_instance(segment.get_segment_manager()); - //Create another private_node_allocator. - private_node_allocator_t allocator_instance2(segment.get_segment_manager()); + //Create another private_node_allocator. + private_node_allocator_t allocator_instance2(segment.get_segment_manager()); - //Although the segment manager address - //is the same, this private_node_allocator will have its own pool so - //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". - //"allocator_instance2" is NOT equal to "allocator_instance" - assert(allocator_instance != allocator_instance2); + //Although the segment manager address + //is the same, this private_node_allocator will have its own pool so + //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". + //"allocator_instance2" is NOT equal to "allocator_instance" + assert(allocator_instance != allocator_instance2); - //Create another node_allocator using copy-constructor. - private_node_allocator_t allocator_instance3(allocator_instance2); + //Create another node_allocator using copy-constructor. + private_node_allocator_t allocator_instance3(allocator_instance2); - //This allocator is also unequal to allocator_instance2 - assert(allocator_instance2 != allocator_instance3); + //This allocator is also unequal to allocator_instance2 + assert(allocator_instance2 != allocator_instance3); - //Pools are destroyed with the allocators - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Pools are destroyed with the allocators return 0; } //] diff --git a/example/doc_scoped_ptr.cpp b/example/doc_scoped_ptr.cpp index 3eb423f..d4a577e 100644 --- a/example/doc_scoped_ptr.cpp +++ b/example/doc_scoped_ptr.cpp @@ -47,60 +47,59 @@ class my_deleter int main () { //Create shared memory - shared_memory_object::remove("my_shmem"); - try{ - managed_shared_memory shmem(create_only, "my_shmem", 10000); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //In the first try, there will be no exceptions - //in the second try we will throw an exception - for(int i = 0; i < 2; ++i){ - //Create an object in shared memory - my_class * my_object = shmem.construct("my_object")(); - my_class * my_object2 = shmem.construct(anonymous_instance)(); - shmem.destroy_ptr(my_object2); - - //Since the next shared memory allocation can throw - //assign it to a scoped_ptr so that if an exception occurs - //we destroy the object automatically - my_deleter d(shmem.get_segment_manager()); + managed_shared_memory shmem(create_only, "MySharedMemory", 10000); - try{ - scoped_ptr > s_ptr(my_object, d); - //Let's emulate a exception capable operation - //In the second try, throw an exception - if(i == 1){ - throw(my_exception()); - } - //If we have passed the dangerous zone - //we can release the scoped pointer - //to avoid destruction - s_ptr.release(); + //In the first try, there will be no exceptions + //in the second try we will throw an exception + for(int i = 0; i < 2; ++i){ + //Create an object in shared memory + my_class * my_object = shmem.construct("my_object")(); + my_class * my_object2 = shmem.construct(anonymous_instance)(); + shmem.destroy_ptr(my_object2); + + //Since the next shared memory allocation can throw + //assign it to a scoped_ptr so that if an exception occurs + //we destroy the object automatically + my_deleter d(shmem.get_segment_manager()); + + try{ + scoped_ptr > s_ptr(my_object, d); + //Let's emulate a exception capable operation + //In the second try, throw an exception + if(i == 1){ + throw(my_exception()); } - catch(const my_exception &){} - //Here, scoped_ptr is destroyed - //so it we haven't thrown an exception - //the object should be there, otherwise, destroyed - if(i == 0){ - //Make sure the object is alive - if(!shmem.find("my_object").first){ - return 1; - } - //Now we can use it and delete it manually - shmem.destroy("my_object"); + //If we have passed the dangerous zone + //we can release the scoped pointer + //to avoid destruction + s_ptr.release(); + } + catch(const my_exception &){} + //Here, scoped_ptr is destroyed + //so it we haven't thrown an exception + //the object should be there, otherwise, destroyed + if(i == 0){ + //Make sure the object is alive + if(!shmem.find("my_object").first){ + return 1; } - else{ - //Make sure the object has been deleted - if(shmem.find("my_object").first){ - return 1; - } + //Now we can use it and delete it manually + shmem.destroy("my_object"); + } + else{ + //Make sure the object has been deleted + if(shmem.find("my_object").first){ + return 1; } } } - catch(...){ - shared_memory_object::remove("my_shmem"); - throw; - } - shared_memory_object::remove("my_shmem"); return 0; } //] diff --git a/example/doc_shared_memory.cpp b/example/doc_shared_memory.cpp index 3b5b7bc..053c031 100644 --- a/example/doc_shared_memory.cpp +++ b/example/doc_shared_memory.cpp @@ -11,18 +11,24 @@ //[doc_shared_memory #include #include -#include #include +#include +#include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; - try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); + + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create a shared memory object. - shared_memory_object shm (create_only, "shared_memory", read_write); + shared_memory_object shm (create_only, "MySharedMemory", read_write); //Set size shm.truncate(1000); @@ -32,11 +38,24 @@ int main () //Write all the memory to 1 std::memset(region.get_address(), 1, region.get_size()); + + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; + else{ + //Open already created shared memory object. + shared_memory_object shm (open_only, "MySharedMemory", read_only); + + //Map the whole shared memory in this process + mapped_region region(shm, read_only); + + //Check that memory was initialized to 1 + char *mem = static_cast(region.get_address()); + for(std::size_t i = 0; i < region.get_size(); ++i) + if(*mem++ != 1) + return 1; //Error checking memory } return 0; } diff --git a/example/doc_shared_memory2.cpp b/example/doc_shared_memory2.cpp deleted file mode 100644 index c977095..0000000 --- a/example/doc_shared_memory2.cpp +++ /dev/null @@ -1,48 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_shared_memory2 -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - shared_memory_object::remove("shared_memory"); - try{ - //Open already created shared memory object. - shared_memory_object shm (open_only, "shared_memory", read_only); - - //Map the whole shared memory in this process - mapped_region region(shm, read_only); - - //Check that memory was initialized to 1 - const char *mem = static_cast(region.get_address()); - for(std::size_t i = 0; i < region.get_size(); ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - std::cout << "Test successful!" << std::endl; - } - 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; -} -//] - -#include diff --git a/example/doc_shared_ptr.cpp b/example/doc_shared_ptr.cpp index ebdf6d5..3f41829 100644 --- a/example/doc_shared_ptr.cpp +++ b/example/doc_shared_ptr.cpp @@ -16,7 +16,6 @@ #include #include #include -#include //std::remove using namespace boost::interprocess; @@ -47,7 +46,7 @@ struct shared_ptr_owner int main () { //Destroy any previous file with the name to be used. - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); { managed_mapped_file file(create_only, "MyMappedFile", 4096); @@ -114,7 +113,7 @@ int main () //The reference count will be deallocated when all weak pointers //disappear. After that, the file is unmapped. } - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); return 0; } //] diff --git a/example/doc_shared_ptr_explicit.cpp b/example/doc_shared_ptr_explicit.cpp index 4a4121e..d1d97c7 100644 --- a/example/doc_shared_ptr_explicit.cpp +++ b/example/doc_shared_ptr_explicit.cpp @@ -31,8 +31,13 @@ typedef shared_ptr my_shared_ptr; int main () { - //Destroy any previous segment with the name to be used. - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + managed_shared_memory segment(create_only, "MySharedMemory", 4096); //Create a shared pointer in shared memory @@ -49,7 +54,6 @@ int main () //Destroy "shared ptr". "object to share" will be automatically destroyed segment.destroy_ptr(&shared_ptr_instance); - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_spawn_vector.cpp b/example/doc_spawn_vector.cpp new file mode 100644 index 0000000..6ec0789 --- /dev/null +++ b/example/doc_spawn_vector.cpp @@ -0,0 +1,79 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2009. 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 +//[run_doc_spawn_vector +#include +#include +#include +#include +#include //std::system + +using namespace boost::interprocess; + +//Define an STL compatible allocator of ints that allocates from the managed_shared_memory. +//This allocator will allow placing containers in the segment +typedef allocator ShmemAllocator; + +//Alias a vector that uses the previous STL-like allocator so that allocates +//its values from the segment +typedef vector MyVector; + +//Main function. For parent process argc == 1, for child process argc == 2 +int main(int argc, char *argv[]) +{ + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a new segment with given name and size + managed_shared_memory segment(create_only ,"MySharedMemory", 65536); + + //Initialize shared memory STL-compatible allocator + const ShmemAllocator alloc_inst (segment.get_segment_manager()); + + //Construct a vector named "MyVector" in shared memory with argument alloc_inst + MyVector *myvector = segment.construct("MyVector")(alloc_inst); + + for(int i = 0; i < 100; ++i) //Insert data in the vector + myvector->push_back(i); + + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; + + //Check child has destroyed the vector + if(segment.find("MyVector").first) + return 1; + } + else{ //Child process + //Open the managed segment + managed_shared_memory segment(open_only, "MySharedMemory"); + + //Find the vector using the c-string name + MyVector *myvector = segment.find("MyVector").first; + + //Use vector in reverse order + std::sort(myvector->rbegin(), myvector->rend()); + + //When done, destroy the vector from the segment + segment.destroy("MyVector"); + } + + return 0; +}; + +//] +#include diff --git a/example/doc_unique_ptr.cpp b/example/doc_unique_ptr.cpp index 0b6d5b5..9506297 100644 --- a/example/doc_unique_ptr.cpp +++ b/example/doc_unique_ptr.cpp @@ -18,7 +18,6 @@ #include #include #include -#include //std::remove using namespace boost::interprocess; @@ -49,7 +48,7 @@ typedef list int main () { //Destroy any previous file with the name to be used. - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); { managed_mapped_file file(create_only, "MyMappedFile", 65536); @@ -72,9 +71,8 @@ int main () //Now insert all values for(int i = 0; i < 100; ++i){ - unique_vector->push_back( - make_managed_unique_ptr(file.construct(anonymous_instance)(i), file) - ); + unique_ptr_type p(make_managed_unique_ptr(file.construct(anonymous_instance)(i), file)); + unique_vector->push_back(boost::interprocess::move(p)); assert(unique_vector->back()->number_ == i); } @@ -84,7 +82,7 @@ int main () //Pass ownership of all values to the list for(int i = 99; !unique_vector->empty(); --i){ - unique_list->push_front(move(unique_vector->back())); + unique_list->push_front(boost::interprocess::move(unique_vector->back())); //The unique ptr of the vector is now empty... assert(unique_vector->back() == 0); unique_vector->pop_back(); @@ -114,7 +112,7 @@ int main () //Now destroy the list. All elements will be automatically deallocated. file.destroy_ptr(unique_list); } - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); return 0; } //] diff --git a/example/doc_unordered_map.cpp b/example/doc_unordered_map.cpp index 3839c6f..03e289f 100644 --- a/example/doc_unordered_map.cpp +++ b/example/doc_unordered_map.cpp @@ -20,46 +20,43 @@ int main () { using namespace boost::interprocess; - //Erase previous shared memory with the name - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only ,"MySharedMemory" ,65536); + //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; + //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; + //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; + //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 + //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)); - } + //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; } //] diff --git a/example/doc_vectorstream.cpp b/example/doc_vectorstream.cpp index 5c4ed1f..f0021f6 100644 --- a/example/doc_vectorstream.cpp +++ b/example/doc_vectorstream.cpp @@ -30,83 +30,81 @@ typedef basic_vectorstream MyVectorStream; int main () { - //Create shared memory - shared_memory_object::remove("MySharedMemory"); - try{ - managed_shared_memory segment( - create_only, - "MySharedMemory", //segment name - 65536); //segment size in bytes + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Construct shared memory vector - MyVector *myvector = - segment.construct("MyVector") - (IntAllocator(segment.get_segment_manager())); + managed_shared_memory segment( + create_only, + "MySharedMemory", //segment name + 65536); //segment size in bytes - //Fill vector - myvector->reserve(100); - for(int i = 0; i < 100; ++i){ - myvector->push_back(i); - } + //Construct shared memory vector + MyVector *myvector = + segment.construct("MyVector") + (IntAllocator(segment.get_segment_manager())); - //Create the vectorstream. To create the internal shared memory - //basic_string we need to pass the shared memory allocator as - //a constructor argument - MyVectorStream myvectorstream(CharAllocator(segment.get_segment_manager())); - - //Reserve the internal string - myvectorstream.reserve(100*5); - - //Write all vector elements as text in the internal string - //Data will be directly written in shared memory, because - //internal string's allocator is a shared memory allocator - for(std::size_t i = 0, max = myvector->size(); i < max; ++i){ - myvectorstream << (*myvector)[i] << std::endl; - } - - //Auxiliary vector to compare original data - MyVector *myvector2 = - segment.construct("MyVector2") - (IntAllocator(segment.get_segment_manager())); - - //Avoid reallocations - myvector2->reserve(100); - - //Extract all values from the internal - //string directly to a shared memory vector. - std::istream_iterator it(myvectorstream), itend; - std::copy(it, itend, std::back_inserter(*myvector2)); - - //Compare vectors - assert(std::equal(myvector->begin(), myvector->end(), myvector2->begin())); - - //Create a copy of the internal string - MyString stringcopy (myvectorstream.vector()); - - //Now we create a new empty shared memory string... - MyString *mystring = - segment.construct("MyString") - (CharAllocator(segment.get_segment_manager())); - - //...and we swap vectorstream's internal string - //with the new one: after this statement mystring - //will be the owner of the formatted data. - //No reallocations, no data copies - myvectorstream.swap_vector(*mystring); - - //Let's compare both strings - assert(stringcopy == *mystring); - - //Done, destroy and delete vectors and string from the segment - segment.destroy_ptr(myvector2); - segment.destroy_ptr(myvector); - segment.destroy_ptr(mystring); + //Fill vector + myvector->reserve(100); + for(int i = 0; i < 100; ++i){ + myvector->push_back(i); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + + //Create the vectorstream. To create the internal shared memory + //basic_string we need to pass the shared memory allocator as + //a constructor argument + MyVectorStream myvectorstream(CharAllocator(segment.get_segment_manager())); + + //Reserve the internal string + myvectorstream.reserve(100*5); + + //Write all vector elements as text in the internal string + //Data will be directly written in shared memory, because + //internal string's allocator is a shared memory allocator + for(std::size_t i = 0, max = myvector->size(); i < max; ++i){ + myvectorstream << (*myvector)[i] << std::endl; } - shared_memory_object::remove("MySharedMemory"); + + //Auxiliary vector to compare original data + MyVector *myvector2 = + segment.construct("MyVector2") + (IntAllocator(segment.get_segment_manager())); + + //Avoid reallocations + myvector2->reserve(100); + + //Extract all values from the internal + //string directly to a shared memory vector. + std::istream_iterator it(myvectorstream), itend; + std::copy(it, itend, std::back_inserter(*myvector2)); + + //Compare vectors + assert(std::equal(myvector->begin(), myvector->end(), myvector2->begin())); + + //Create a copy of the internal string + MyString stringcopy (myvectorstream.vector()); + + //Now we create a new empty shared memory string... + MyString *mystring = + segment.construct("MyString") + (CharAllocator(segment.get_segment_manager())); + + //...and we swap vectorstream's internal string + //with the new one: after this statement mystring + //will be the owner of the formatted data. + //No reallocations, no data copies + myvectorstream.swap_vector(*mystring); + + //Let's compare both strings + assert(stringcopy == *mystring); + + //Done, destroy and delete vectors and string from the segment + segment.destroy_ptr(myvector2); + segment.destroy_ptr(myvector); + segment.destroy_ptr(mystring); return 0; } //] diff --git a/example/doc_where_allocate.cpp b/example/doc_where_allocate.cpp index 7f14148..570de8e 100644 --- a/example/doc_where_allocate.cpp +++ b/example/doc_where_allocate.cpp @@ -29,45 +29,44 @@ int main () MyShmStringVector; //Open shared memory - shared_memory_object::remove("myshm"); - try{ - managed_shared_memory shm(create_only, "myshm", 10000); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create allocators - CharAllocator charallocator (shm.get_segment_manager()); - StringAllocator stringallocator(shm.get_segment_manager()); + managed_shared_memory shm(create_only, "MySharedMemory", 10000); - //This string is in only in this process (the pointer pointing to the - //buffer that will hold the text is not in shared memory). - //But the buffer that will hold "this is my text" is allocated from - //shared memory - MyShmString mystring(charallocator); - mystring = "this is my text"; + //Create allocators + CharAllocator charallocator (shm.get_segment_manager()); + StringAllocator stringallocator(shm.get_segment_manager()); - //This vector is only in this process (the pointer pointing to the - //buffer that will hold the MyShmString-s is not in shared memory). - //But the buffer that will hold 10 MyShmString-s is allocated from - //shared memory using StringAllocator. Since strings use a shared - //memory allocator (CharAllocator) the 10 buffers that hold - //"this is my text" text are also in shared memory. - MyShmStringVector myvector(stringallocator); - myvector.insert(myvector.begin(), 10, mystring); + //This string is in only in this process (the pointer pointing to the + //buffer that will hold the text is not in shared memory). + //But the buffer that will hold "this is my text" is allocated from + //shared memory + MyShmString mystring(charallocator); + mystring = "this is my text"; - //This vector is fully constructed in shared memory. All pointers - //buffers are constructed in the same shared memory segment - //This vector can be safely accessed from other processes. - MyShmStringVector *myshmvector = - shm.construct("myshmvector")(stringallocator); - myshmvector->insert(myshmvector->begin(), 10, mystring); + //This vector is only in this process (the pointer pointing to the + //buffer that will hold the MyShmString-s is not in shared memory). + //But the buffer that will hold 10 MyShmString-s is allocated from + //shared memory using StringAllocator. Since strings use a shared + //memory allocator (CharAllocator) the 10 buffers that hold + //"this is my text" text are also in shared memory. + MyShmStringVector myvector(stringallocator); + myvector.insert(myvector.begin(), 10, mystring); - //Destroy vector. This will free all strings that the vector contains - shm.destroy_ptr(myshmvector); - } - catch(...){ - shared_memory_object::remove("myshm"); - throw; - } - shared_memory_object::remove("myshm"); + //This vector is fully constructed in shared memory. All pointers + //buffers are constructed in the same shared memory segment + //This vector can be safely accessed from other processes. + MyShmStringVector *myshmvector = + shm.construct("myshmvector")(stringallocator); + myshmvector->insert(myshmvector->begin(), 10, mystring); + + //Destroy vector. This will free all strings that the vector contains + shm.destroy_ptr(myshmvector); return 0; } //] diff --git a/example/doc_windows_shared_memory.cpp b/example/doc_windows_shared_memory.cpp index 94cd380..28da11e 100644 --- a/example/doc_windows_shared_memory.cpp +++ b/example/doc_windows_shared_memory.cpp @@ -8,41 +8,61 @@ // ////////////////////////////////////////////////////////////////////////////// #include -#include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS + //[doc_windows_shared_memory #include #include -#include #include +#include +#include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; - try{ + + if(argc == 1){ //Parent process //Create a native windows shared memory object. - windows_shared_memory shm (create_only, "shared_memory", read_write, 1000); + windows_shared_memory shm (create_only, "MySharedMemory", read_write, 1000); //Map the whole shared memory in this process mapped_region region(shm, read_write); //Write all the memory to 1 - std::memset(region.get_address(), 1, 1000); + std::memset(region.get_address(), 1, region.get_size()); - //Launch the client process and wait until finishes... - //... + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; + //windows_shared_memory is destroyed when the last attached process dies... } - catch(interprocess_exception &ex){ - std::cout << ex.what() << std::endl; - return 1; + else{ + //Open already created shared memory object. + windows_shared_memory shm (open_only, "MySharedMemory", read_only); + + //Map the whole shared memory in this process + mapped_region region(shm, read_only); + + //Check that memory was initialized to 1 + char *mem = static_cast(region.get_address()); + for(std::size_t i = 0; i < region.get_size(); ++i) + if(*mem++ != 1) + return 1; //Error checking memory + return 0; } return 0; } //] -#else //#ifdef BOOST_WINDOWS + +#else //BOOST_INTERPROCESS_WINDOWS + int main() -{ return 0; } -#endif//#ifdef BOOST_WINDOWS +{ + return 0; +} + +#endif //BOOST_INTERPROCESS_WINDOWS #include diff --git a/example/doc_windows_shared_memory2.cpp b/example/doc_windows_shared_memory2.cpp deleted file mode 100644 index 405f244..0000000 --- a/example/doc_windows_shared_memory2.cpp +++ /dev/null @@ -1,55 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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 - -#ifdef BOOST_WINDOWS -//[doc_windows_shared_memory2 -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //Open already created shared memory object. - windows_shared_memory shm(open_only, "shared_memory", read_only); - - //Map the whole shared memory in this process - mapped_region region (shm, read_only); - - //Check that memory was initialized to 1 - const char *mem = static_cast(region.get_address()); - for(std::size_t i = 0; i < 1000; ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - - std::cout << "Test successful!" << std::endl; - } - catch(interprocess_exception &ex){ - std::cout << "Unexpected exception: " << ex.what() << std::endl; - return 1; - } - - return 0; -} -//] -#else //#ifdef BOOST_WINDOWS -int main() -{ return 0; } -#endif//#ifdef BOOST_WINDOWS - -#include - diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index fab13ca..cf12947 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -80,9 +82,9 @@ class adaptive_pool_base public: //------- - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -92,13 +94,9 @@ class adaptive_pool_base typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef boost::interprocess::version_type version; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains adaptive_pool_base from //!adaptive_pool_base @@ -266,7 +264,7 @@ class adaptive_pool typedef detail::adaptive_pool_base < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -388,7 +386,7 @@ class adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -399,12 +397,12 @@ class adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain 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 block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements); //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, @@ -412,7 +410,7 @@ class adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -425,7 +423,7 @@ class adaptive_pool //!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); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -438,7 +436,7 @@ class adaptive_pool //!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); + void deallocate_individual(multiallocation_chain it); #endif }; diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 60c7fb6..2918689 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -18,15 +18,17 @@ #include #include +#include + #include -#include +#include +#include #include -#include +#include #include #include #include #include -#include #include #include @@ -64,11 +66,11 @@ class allocator //Typedef to const void pointer typedef typename - detail::pointer_to_other + boost::pointer_to_other ::type cvoid_ptr; //Pointer to the allocator - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type alloc_ptr_t; //Not assignable from related allocator @@ -84,9 +86,9 @@ class allocator public: typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef typename detail::add_reference ::type reference; @@ -95,20 +97,13 @@ class allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; + typedef boost::interprocess::version_type version; /// @cond //Experimental. Don't use. - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef detail::multiallocation_chain_adaptor - multiallocation_chain; - + typedef boost::interprocess::detail::transform_multiallocation_chain + multiallocation_chain; /// @endcond //!Obtains an allocator that allocates @@ -174,7 +169,7 @@ class allocator } std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) @@ -189,19 +184,19 @@ class allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements) + multiallocation_chain allocate_many + (size_type elem_size, std::size_t num_elements) { - return multiallocation_iterator - (mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements)); + return multiallocation_chain(mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements)); } //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + multiallocation_chain allocate_many + (const size_type *elem_sizes, size_type n_elements) { - return multiallocation_iterator - (mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); + multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); } //!Allocates many elements of size elem_size in a contiguous block @@ -210,8 +205,10 @@ class allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it) - { return mp_mngr->deallocate_many(it.base()); } + void deallocate_many(multiallocation_chain chain) + { + return mp_mngr->deallocate_many(chain.extract_multiallocation_chain()); + } //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -225,7 +222,8 @@ class allocator //!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) + multiallocation_chain allocate_individual + (std::size_t num_elements) { return this->allocate_many(1, num_elements); } //!Deallocates memory previously allocated with allocate_one(). @@ -240,8 +238,8 @@ class allocator //!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) - { return this->deallocate_many(it); } + void deallocate_individual(multiallocation_chain chain) + { return this->deallocate_many(boost::interprocess::move(chain)); } //!Returns address of mutable object. //!Never throws diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index fc94fb7..f2fa301 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -143,7 +143,7 @@ class cached_adaptive_pool , 2> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -267,7 +267,7 @@ class cached_adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -278,12 +278,12 @@ class cached_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain 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 block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements); //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, @@ -291,7 +291,7 @@ class cached_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -304,7 +304,7 @@ class cached_adaptive_pool //!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); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -317,7 +317,7 @@ class cached_adaptive_pool //!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); + void deallocate_individual(multiallocation_chain chain); //!Sets the new max cached nodes value. This can provoke deallocations //!if "newmax" is less than current cached nodes. Never throws void set_max_cached_nodes(std::size_t newmax); diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 3801dc6..5799d6b 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -115,7 +115,7 @@ class cached_node_allocator , 2> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -238,7 +238,7 @@ class cached_node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -249,12 +249,12 @@ class cached_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain 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 block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements); //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, @@ -262,7 +262,7 @@ class cached_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -275,7 +275,7 @@ class cached_node_allocator //!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); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -288,7 +288,7 @@ class cached_node_allocator //!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); + void deallocate_individual(multiallocation_chain it); //!Sets the new max cached nodes value. This can provoke deallocations //!if "newmax" is less than current cached nodes. Never throws void set_max_cached_nodes(std::size_t newmax); diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 30a6c07..6a20fb8 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +55,6 @@ class private_adaptive_node_pool_impl public: typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: @@ -200,8 +201,9 @@ class private_adaptive_node_pool_impl //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - this->priv_reinsert_nodes_in_block - (multiallocation_iterator::create_simple_range(pElem)); + multiallocation_chain chain; + chain.push_front(void_pointer(pElem)); + this->priv_reinsert_nodes_in_block(chain, 1); //Update free block count if(m_totally_free_blocks > m_max_free_blocks){ this->priv_deallocate_free_blocks(m_max_free_blocks); @@ -209,13 +211,14 @@ class private_adaptive_node_pool_impl priv_invariants(); } - //!Allocates a singly linked list of n nodes ending in null pointer. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) + //!Allocates n nodes. + //!Can throw boost::interprocess::bad_alloc + multiallocation_chain allocate_nodes(const std::size_t n) { + multiallocation_chain chain; + std::size_t i = 0; try{ priv_invariants(); - std::size_t i = 0; while(i != n){ //If there are no free nodes we allocate all needed blocks if (m_block_multiset.empty()){ @@ -230,9 +233,9 @@ class private_adaptive_node_pool_impl 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); + chain.push_back(new_node); } - + if(free_nodes.empty()){ m_block_multiset.erase(m_block_multiset.begin()); } @@ -240,41 +243,23 @@ class private_adaptive_node_pool_impl } } catch(...){ - this->deallocate_nodes(nodes, nodes.size()); + this->deallocate_nodes(chain, i); throw; } priv_invariants(); - } - - //!Allocates n nodes, pointed by the multiallocation_iterator. - //!Can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) - { - multiallocation_chain chain; - this->allocate_nodes(chain, n); - return chain.get_it(); + return boost::interprocess::move(chain); } //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes) + void deallocate_nodes(multiallocation_chain nodes) { - this->deallocate_nodes(nodes.get_it()); - nodes.reset(); + return deallocate_nodes(nodes, nodes.size()); } //!Deallocates the first n nodes of a linked list of nodes. Never throws void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) { - assert(nodes.size() >= n); - for(std::size_t i = 0; i < n; ++i){ - this->deallocate_node(nodes.pop_front()); - } - } - - //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) - { - this->priv_reinsert_nodes_in_block(it); + this->priv_reinsert_nodes_in_block(nodes, n); if(m_totally_free_blocks > m_max_free_blocks){ this->priv_deallocate_free_blocks(m_max_free_blocks); } @@ -331,13 +316,12 @@ class private_adaptive_node_pool_impl } } - void priv_reinsert_nodes_in_block(multiallocation_iterator it) + void priv_reinsert_nodes_in_block(multiallocation_chain &chain, std::size_t n) { - multiallocation_iterator itend; block_iterator block_it(m_block_multiset.end()); - while(it != itend){ - void *pElem = &*it; - ++it; + while(n--){ + void *pElem = detail::get_pointer(chain.front()); + chain.pop_front(); priv_invariants(); block_info_t *block_info = this->priv_block_from_node(pElem); assert(block_info->free_nodes.size() < m_real_num_node); @@ -484,6 +468,7 @@ class private_adaptive_node_pool_impl std::size_t num_free_nodes = 0; for(; it != itend; ++it){ //Check for memory leak + std::size_t n = (std::size_t)it->free_nodes.size(); (void)n; assert(it->free_nodes.size() == m_real_num_node); ++num_free_nodes; } @@ -565,7 +550,7 @@ class private_adaptive_node_pool_impl } private: - typedef typename pointer_to_other + typedef typename boost::pointer_to_other ::type segment_mngr_base_ptr_t; const std::size_t m_max_free_blocks; diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index f5ccddd..998c415 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -8,25 +8,63 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP -#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP +#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP #include #include -#include + +#include + #include -#include //pointer_to_other, get_pointer +#include //get_pointer #include //std::pair #include //boost::addressof #include //BOOST_ASSERT #include //bad_alloc #include //scoped_lock -#include //allocation_type +#include //boost::interprocess::allocation_type +#include +#include #include //std::swap +#include +#include +#include namespace boost { namespace interprocess { + +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 detail { //!Object function that creates the node allocator if it is not created and @@ -41,7 +79,7 @@ struct get_or_create_node_pool_func { //Find or create the node_pool_t mp_node_pool = mp_segment_manager->template find_or_construct - (unique_instance)(mp_segment_manager); + (boost::interprocess::unique_instance)(mp_segment_manager); //If valid, increment link count if(mp_node_pool != 0) mp_node_pool->inc_ref_count(); @@ -78,7 +116,7 @@ struct destroy_if_last_link_func if(mp_node_pool->dec_ref_count() != 0) return; //Last link, let's destroy the segment_manager - mp_node_pool->get_segment_manager()->template destroy(unique_instance); + mp_node_pool->get_segment_manager()->template destroy(boost::interprocess::unique_instance); } //!Constructor. Initializes function @@ -106,16 +144,15 @@ template class cache_impl { typedef typename NodePool::segment_manager:: - void_pointer void_pointer; + void_pointer void_pointer; typedef typename pointer_to_other - ::type node_pool_ptr; - typedef typename NodePool::multiallocation_chain multiallocation_chain; - node_pool_ptr mp_node_pool; - multiallocation_chain m_cached_nodes; - std::size_t m_max_cached_nodes; + ::type node_pool_ptr; + typedef typename NodePool::multiallocation_chain multiallocation_chain; + node_pool_ptr mp_node_pool; + multiallocation_chain m_cached_nodes; + std::size_t m_max_cached_nodes; public: - typedef typename NodePool::multiallocation_iterator multiallocation_iterator; typedef typename NodePool::segment_manager segment_manager; cache_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes) @@ -149,31 +186,34 @@ class cache_impl { //If don't have any cached node, we have to get a new list of free nodes from the pool if(m_cached_nodes.empty()){ - mp_node_pool->allocate_nodes(m_cached_nodes, m_max_cached_nodes/2); + m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2); } - return m_cached_nodes.pop_front(); + void *ret = detail::get_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); + return ret; } - multiallocation_iterator cached_allocation(std::size_t n) + multiallocation_chain cached_allocation(std::size_t n) { multiallocation_chain chain; - std::size_t count = n; + std::size_t count = n, allocated(0); BOOST_TRY{ //If don't have any cached node, we have to get a new list of free nodes from the pool while(!m_cached_nodes.empty() && count--){ - void *ret = m_cached_nodes.pop_front(); + void *ret = detail::get_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); chain.push_back(ret); + ++allocated; } - if(chain.size() != n){ - mp_node_pool->allocate_nodes(chain, n - chain.size()); + if(allocated != n){ + multiallocation_chain chain2(mp_node_pool->allocate_nodes(n - allocated)); + chain.splice_after(chain.last(), chain2, chain2.before_begin(), chain2.last(), n - allocated); } - assert(chain.size() == n); - chain.splice_back(m_cached_nodes); - return multiallocation_iterator(chain.get_it()); + return boost::interprocess::move(chain); } BOOST_CATCH(...){ - this->cached_deallocation(multiallocation_iterator(chain.get_it())); + this->cached_deallocation(boost::interprocess::move(chain)); BOOST_RETHROW } BOOST_CATCH_END @@ -192,15 +232,9 @@ class cache_impl m_cached_nodes.push_front(ptr); } - void cached_deallocation(multiallocation_iterator it) + void cached_deallocation(multiallocation_chain chain) { - multiallocation_iterator itend; - - while(it != itend){ - void *addr = &*it; - ++it; - m_cached_nodes.push_front(addr); - } + m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain); //Check if cache is full if(m_cached_nodes.size() >= m_max_cached_nodes){ @@ -225,7 +259,7 @@ class cache_impl void deallocate_all_cached_nodes() { if(m_cached_nodes.empty()) return; - mp_node_pool->deallocate_nodes(m_cached_nodes); + mp_node_pool->deallocate_nodes(boost::interprocess::move(m_cached_nodes)); } private: @@ -257,9 +291,9 @@ class array_allocation_impl typedef typename SegmentManager::void_pointer void_pointer; public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -268,12 +302,9 @@ class array_allocation_impl ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; + public: //!Returns maximum the number of objects the previously allocated memory @@ -285,7 +316,7 @@ class array_allocation_impl } std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) @@ -300,19 +331,17 @@ class array_allocation_impl //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements) + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements) { - return multiallocation_iterator - (this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements)); + return this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements); } //!Allocates n_elements elements, each one of size elem_sizes[i]in a //!contiguous block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements) { - return multiallocation_iterator - (this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T))); + return this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T)); } //!Allocates many elements of size elem_size in a contiguous block @@ -321,8 +350,8 @@ class array_allocation_impl //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it) - { return this->derived()->get_segment_manager()->deallocate_many(it.base()); } + void deallocate_many(multiallocation_chain chain) + { return this->derived()->get_segment_manager()->deallocate_many(boost::interprocess::move(chain)); } //!Returns the number of elements that could be //!allocated. Never throws @@ -369,13 +398,13 @@ class node_pool_allocation_impl { return static_cast(this); } typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type cvoid_pointer; public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -384,12 +413,9 @@ class node_pool_allocation_impl ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; + template struct node_pool @@ -445,11 +471,11 @@ class node_pool_allocation_impl //!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) + multiallocation_chain allocate_individual(std::size_t 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)); + return multiallocation_chain(pool->allocate_nodes(num_elements)); } //!Deallocates memory previously allocated with allocate_one(). @@ -468,8 +494,11 @@ class node_pool_allocation_impl //!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) - { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } + void deallocate_individual(multiallocation_chain chain) + { + node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes + (chain.extract_multiallocation_chain()); + } //!Deallocates all free blocks of the pool void deallocate_free_blocks() @@ -497,11 +526,10 @@ class cached_allocator_impl typedef NodePool node_pool_t; typedef typename NodePool::segment_manager segment_manager; typedef typename segment_manager::void_pointer void_pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type cvoid_pointer; typedef typename base_t::pointer pointer; typedef typename base_t::size_type size_type; - typedef typename base_t::multiallocation_iterator multiallocation_iterator; typedef typename base_t::multiallocation_chain multiallocation_chain; typedef typename base_t::value_type value_type; @@ -587,8 +615,8 @@ class cached_allocator_impl //!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->m_cache.cached_allocation(num_elements)); } + multiallocation_chain allocate_individual(std::size_t num_elements) + { return multiallocation_chain(this->m_cache.cached_allocation(num_elements)); } //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -602,8 +630,12 @@ class cached_allocator_impl //!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) - { m_cache.cached_deallocation(it.base()); } + void deallocate_individual(multiallocation_chain chain) + { + typename node_pool_t::multiallocation_chain mem + (chain.extract_multiallocation_chain()); + m_cache.cached_deallocation(boost::interprocess::move(mem)); + } //!Deallocates all free blocks of the pool void deallocate_free_blocks() @@ -655,11 +687,10 @@ class shared_pool_impl { public: //!Segment manager typedef - typedef typename private_node_allocator_t::segment_manager segment_manager; typedef typename private_node_allocator_t:: - multiallocation_iterator multiallocation_iterator; + segment_manager segment_manager; typedef typename private_node_allocator_t:: - multiallocation_chain multiallocation_chain; + multiallocation_chain multiallocation_chain; private: typedef typename segment_manager::mutex_family::mutex_type mutex_type; @@ -691,7 +722,7 @@ class shared_pool_impl //----------------------- private_node_allocator_t::deallocate_node(ptr); } - +/* //!Allocates a singly linked list of n nodes ending in null pointer. //!can throw boost::interprocess::bad_alloc void allocate_nodes(multiallocation_chain &nodes, std::size_t n) @@ -701,10 +732,10 @@ class shared_pool_impl //----------------------- return private_node_allocator_t::allocate_nodes(nodes, n); } - - //!Allocates n nodes, pointed by the multiallocation_iterator. +*/ + //!Allocates n nodes. //!Can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) + multiallocation_chain allocate_nodes(const std::size_t n) { //----------------------- boost::interprocess::scoped_lock guard(m_header); @@ -721,22 +752,13 @@ class shared_pool_impl private_node_allocator_t::deallocate_nodes(nodes, num); } - //!Deallocates a linked list of nodes ending in null pointer. Never throws - void deallocate_nodes(multiallocation_chain &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes); - } - //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) + void deallocate_nodes(multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::deallocate_nodes(it); + private_node_allocator_t::deallocate_nodes(boost::interprocess::move(chain)); } //!Deallocates all the free blocks of memory. Never throws @@ -814,4 +836,4 @@ class shared_pool_impl #include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP +#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index bf6c758..7d7631b 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -18,14 +18,17 @@ #include #include +#include +#include +#include + #include #include #include -#include -#include #include #include #include +#include #include #include #include @@ -53,7 +56,6 @@ class private_node_pool_impl typedef typename node_slist::slist_hook_t slist_hook_t; typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: @@ -112,25 +114,9 @@ class private_node_pool_impl --m_allocated; } - //!Allocates a singly linked list of n nodes ending in null pointer and pushes them in the chain. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) - { - std::size_t i = 0; - try{ - for(; i < n; ++i){ - nodes.push_front(this->allocate_node()); - } - } - catch(...){ - this->deallocate_nodes(nodes, i); - throw; - } - } - //!Allocates a singly linked list of n nodes ending in null pointer //!can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) + multiallocation_chain allocate_nodes(const std::size_t n) { multiallocation_chain nodes; std::size_t i = 0; @@ -143,32 +129,26 @@ class private_node_pool_impl this->deallocate_nodes(nodes, i); throw; } - return nodes.get_it(); - } - - //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes) - { - this->deallocate_nodes(nodes.get_it()); - nodes.reset(); + return boost::interprocess::move(nodes); } //!Deallocates the first n nodes of a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) + void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) { - assert(nodes.size() >= num); - for(std::size_t i = 0; i < num; ++i){ - deallocate_node(nodes.pop_front()); + for(std::size_t i = 0; i < n; ++i){ + void *p = detail::get_pointer(nodes.front()); + assert(p); + nodes.pop_front(); + this->deallocate_node(p); } } //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) + void deallocate_nodes(multiallocation_chain chain) { - multiallocation_iterator itend; - while(it != itend){ - void *addr = &*it; - ++it; + while(!chain.empty()){ + void *addr = detail::get_pointer(chain.front()); + chain.pop_front(); deallocate_node(addr); } } @@ -347,7 +327,7 @@ class private_node_pool_impl } private: - typedef typename pointer_to_other + typedef typename boost::pointer_to_other ::type segment_mngr_base_ptr_t; const std::size_t m_nodes_per_block; diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index 0ee43c3..49bb201 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -77,9 +79,9 @@ class node_allocator_base public: //------- - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -89,13 +91,9 @@ class node_allocator_base typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef boost::interprocess::version_type version; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator_base from //!node_allocator_base @@ -251,7 +249,7 @@ class node_allocator typedef detail::node_allocator_base < 2, T, SegmentManager, NodesPerBlock> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -373,7 +371,7 @@ class node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -384,12 +382,12 @@ class node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain 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 block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements); //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, @@ -397,7 +395,7 @@ class node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -410,7 +408,7 @@ class node_allocator //!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); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -423,7 +421,7 @@ class node_allocator //!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); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index c9b4e18..d958fdb 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -78,9 +80,9 @@ class private_adaptive_pool_base /// @endcond public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -89,14 +91,10 @@ class private_adaptive_pool_base ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type + typedef boost::interprocess::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator from other node_allocator template @@ -264,7 +262,7 @@ class private_adaptive_pool typedef detail::private_adaptive_pool_base < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -388,7 +386,7 @@ class private_adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -399,12 +397,12 @@ class private_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain 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 block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements); //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, @@ -412,7 +410,7 @@ class private_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -425,7 +423,7 @@ class private_adaptive_pool //!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); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -438,7 +436,7 @@ class private_adaptive_pool //!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); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index a7320f1..e8c3c5e 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -72,9 +74,9 @@ class private_node_allocator_base /// @endcond public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -83,14 +85,10 @@ class private_node_allocator_base ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type + typedef boost::interprocess::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator from other node_allocator template @@ -240,7 +238,7 @@ class private_node_allocator typedef detail::private_node_allocator_base < 2, T, SegmentManager, NodesPerBlock> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -364,7 +362,7 @@ class private_node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -375,12 +373,12 @@ class private_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + multiallocation_chain 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 block //!of memory. The elements must be deallocated - multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements); //!Allocates many elements of size elem_size in a contiguous block //!of memory. The minimum number to be allocated is min_elements, @@ -388,7 +386,7 @@ class private_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -401,7 +399,7 @@ class private_node_allocator //!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); + multiallocation_chain allocate_individual(std::size_t num_elements); //!Deallocates memory previously allocated with allocate_one(). //!You should never use deallocate_one to deallocate memory allocated @@ -414,7 +412,7 @@ class private_node_allocator //!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); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp index e933e3c..0c19a35 100644 --- a/include/boost/interprocess/anonymous_shared_memory.hpp +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -19,7 +19,7 @@ #include #include -#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) # include //open, O_CREAT, O_*... # include //mmap # include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, @@ -42,12 +42,7 @@ namespace detail{ class raw_mapped_region_creator { public: - static - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - mapped_region - #else - move_return - #endif + static mapped_region create_posix_mapped_region(void *address, offset_t offset, std::size_t size) { mapped_region region; @@ -67,14 +62,10 @@ namespace detail{ //!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 +//static mapped_region +static mapped_region anonymous_shared_memory(std::size_t size, void *address = 0) -#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) { int flags; int fd = -1; @@ -115,8 +106,7 @@ anonymous_shared_memory(std::size_t size, void *address = 0) #else { windows_shared_memory anonymous_mapping(create_only, 0, read_write, size); - mapped_region region(anonymous_mapping, read_write, 0, size, address); - return region; + return mapped_region(anonymous_mapping, read_write, 0, size, address); } #endif diff --git a/include/boost/interprocess/containers/allocation_type.hpp b/include/boost/interprocess/containers/allocation_type.hpp new file mode 100644 index 0000000..a22425f --- /dev/null +++ b/include/boost/interprocess/containers/allocation_type.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +/// @cond +typedef int allocation_type; +/// @endcond +static const allocation_type allocate_new = boost::interprocess_container::allocate_new; +static const allocation_type expand_fwd = boost::interprocess_container::expand_fwd; +static const allocation_type expand_bwd = boost::interprocess_container::expand_bwd; +static const allocation_type shrink_in_place = boost::interprocess_container::shrink_in_place; +static const allocation_type try_shrink_in_place= boost::interprocess_container::try_shrink_in_place; +static const allocation_type nothrow_allocation = boost::interprocess_container::nothrow_allocation; +static const allocation_type zero_memory = boost::interprocess_container::zero_memory; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/containers_fwd.hpp b/include/boost/interprocess/containers/container/containers_fwd.hpp new file mode 100644 index 0000000..3e2eb21 --- /dev/null +++ b/include/boost/interprocess/containers/container/containers_fwd.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP +#define BOOST_CONTAINERS_CONTAINERS_FWD_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +/// @cond + +namespace boost{ +namespace intrusive{ + //Create namespace to avoid compilation errors +}} + +namespace boost{ namespace interprocess_container{ namespace containers_detail{ + +namespace bi = boost::intrusive; + +}}} + +namespace std { + +template +class allocator; + +template +struct less; + +template +struct pair; + +template +struct char_traits; + +} //namespace std { + +/// @endcond + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +//vector class +template > +class vector; + +//vector class +template > +class deque; + +//list class +template > +class list; + +//slist class +template > +class slist; + +//set class +template + ,class Alloc = std::allocator > +class set; + +//multiset class +template + ,class Alloc = std::allocator > +class multiset; + +//map class +template + ,class Alloc = std::allocator > > +class map; + +//multimap class +template + ,class Alloc = std::allocator > > +class multimap; + +//flat_set class +template + ,class Alloc = std::allocator > +class flat_set; + +//flat_multiset class +template + ,class Alloc = std::allocator > +class flat_multiset; + +//flat_map class +template + ,class Alloc = std::allocator > > +class flat_map; + +//flat_multimap class +template + ,class Alloc = std::allocator > > +class flat_multimap; + +//basic_string class +template + ,class Alloc = std::allocator > +class basic_string; + +//string class +typedef basic_string + + ,std::allocator > +string; + +}} //namespace boost { namespace interprocess_container { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP + diff --git a/include/boost/interprocess/containers/container/deque.hpp b/include/boost/interprocess/containers/container/deque.hpp new file mode 100644 index 0000000..0963e18 --- /dev/null +++ b/include/boost/interprocess/containers/container/deque.hpp @@ -0,0 +1,1482 @@ +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_deque.h and stl_uninitialized.h files. +// Modified by Ion Gaztanaga 2005. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DEQUE_HPP +#define BOOST_CONTAINERS_DEQUE_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 +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +template +class deque; + +template +struct deque_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + boost::interprocess::has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::value; + +}; + +// Note: this function is simply a kludge to work around several compilers' +// bugs in handling constant expressions. +inline std::size_t deque_buf_size(std::size_t size) + { return size < 512 ? std::size_t(512 / size) : std::size_t(1); } + +// Deque base class. It has two purposes. First, its constructor +// and destructor allocate (but don't initialize) storage. This makes +// exception safety easier. +template +class deque_base +{ + public: + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename Alloc::value_type val_alloc_diff; + typedef typename Alloc::template rebind + ::other ptr_alloc_t; + typedef typename ptr_alloc_t::value_type ptr_alloc_val; + typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; + typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc_t::reference ptr_alloc_ref; + typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; + typedef typename Alloc::template + rebind::other allocator_type; + typedef allocator_type stored_allocator_type; + + protected: + + typedef deque_value_traits traits_t; + typedef typename Alloc::template + rebind::other map_allocator_type; + + static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); } + + val_alloc_ptr priv_allocate_node() + { return this->alloc().allocate(s_buffer_size()); } + + void priv_deallocate_node(val_alloc_ptr p) + { this->alloc().deallocate(p, s_buffer_size()); } + + ptr_alloc_ptr priv_allocate_map(std::size_t n) + { return this->ptr_alloc().allocate(n); } + + void priv_deallocate_map(ptr_alloc_ptr p, std::size_t n) + { this->ptr_alloc().deallocate(p, n); } + + public: + // Class invariants: + // For any nonsingular iterator i: + // i.node is the address of an element in the map array. The + // contents of i.node is a pointer to the beginning of a node. + // i.first == //(i.node) + // i.last == i.first + node_size + // i.cur is a pointer in the range [i.first, i.last). NOTE: + // the implication of this is that i.cur is always a dereferenceable + // pointer, even if i is a past-the-end iterator. + // Start and Finish are always nonsingular iterators. NOTE: this means + // that an empty deque must have one node, and that a deque + // with N elements, where N is the buffer size, must have two nodes. + // For every node other than start.node and finish.node, every element + // in the node is an initialized object. If start.node == finish.node, + // then [start.cur, finish.cur) are initialized objects, and + // the elements outside that range are uninitialized storage. Otherwise, + // [start.cur, start.last) and [finish.first, finish.cur) are initialized + // objects, and [start.first, start.cur) and [finish.cur, finish.last) + // are uninitialized storage. + // [map, map + map_size) is a valid, non-empty range. + // [start.node, finish.node] is a valid range contained within + // [map, map + map_size). + // A pointer in the range [map, map + map_size) points to an allocated node + // if and only if the pointer is in the range [start.node, finish.node]. + class const_iterator + : public std::iterator + { + public: + static std::size_t s_buffer_size() { return deque_base::s_buffer_size(); } + + typedef std::random_access_iterator_tag iterator_category; + typedef val_alloc_val value_type; + typedef val_alloc_cptr pointer; + typedef val_alloc_cref reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef ptr_alloc_ptr index_pointer; + typedef const_iterator self_t; + + friend class deque; + friend class deque_base; + + protected: + val_alloc_ptr m_cur; + val_alloc_ptr m_first; + val_alloc_ptr m_last; + index_pointer m_node; + + public: + const_iterator(val_alloc_ptr x, index_pointer y) + : m_cur(x), m_first(*y), + m_last(*y + s_buffer_size()), m_node(y) {} + + const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} + + const_iterator(const const_iterator& x) + : m_cur(x.m_cur), m_first(x.m_first), + m_last(x.m_last), m_node(x.m_node) {} + + reference operator*() const + { return *this->m_cur; } + + pointer operator->() const + { return this->m_cur; } + + difference_type operator-(const self_t& x) const + { + if(!this->m_cur && !x.m_cur){ + return 0; + } + return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + + (this->m_cur - this->m_first) + (x.m_last - x.m_cur); + } + + self_t& operator++() + { + ++this->m_cur; + if (this->m_cur == this->m_last) { + this->priv_set_node(this->m_node + 1); + this->m_cur = this->m_first; + } + return *this; + } + + self_t operator++(int) + { + self_t tmp = *this; + ++*this; + return tmp; + } + + self_t& operator--() + { + if (this->m_cur == this->m_first) { + this->priv_set_node(this->m_node - 1); + this->m_cur = this->m_last; + } + --this->m_cur; + return *this; + } + + self_t operator--(int) + { + self_t tmp = *this; + --*this; + return tmp; + } + + self_t& operator+=(difference_type n) + { + difference_type offset = n + (this->m_cur - this->m_first); + if (offset >= 0 && offset < difference_type(this->s_buffer_size())) + this->m_cur += n; + else { + difference_type node_offset = + offset > 0 ? offset / difference_type(this->s_buffer_size()) + : -difference_type((-offset - 1) / this->s_buffer_size()) - 1; + this->priv_set_node(this->m_node + node_offset); + this->m_cur = this->m_first + + (offset - node_offset * difference_type(this->s_buffer_size())); + } + return *this; + } + + self_t operator+(difference_type n) const + { self_t tmp = *this; return tmp += n; } + + self_t& operator-=(difference_type n) + { return *this += -n; } + + self_t operator-(difference_type n) const + { self_t tmp = *this; return tmp -= n; } + + reference operator[](difference_type n) const + { return *(*this + n); } + + bool operator==(const self_t& x) const + { return this->m_cur == x.m_cur; } + + bool operator!=(const self_t& x) const + { return !(*this == x); } + + bool operator<(const self_t& x) const + { + return (this->m_node == x.m_node) ? + (this->m_cur < x.m_cur) : (this->m_node < x.m_node); + } + + bool operator>(const self_t& x) const + { return x < *this; } + + bool operator<=(const self_t& x) const + { return !(x < *this); } + + bool operator>=(const self_t& x) const + { return !(*this < x); } + + void priv_set_node(index_pointer new_node) + { + this->m_node = new_node; + this->m_first = *new_node; + this->m_last = this->m_first + difference_type(this->s_buffer_size()); + } + + friend const_iterator operator+(std::ptrdiff_t n, const const_iterator& x) + { return x + n; } + }; + + //Deque iterator + class iterator : public const_iterator + { + public: + typedef std::random_access_iterator_tag iterator_category; + typedef val_alloc_val value_type; + typedef val_alloc_ptr pointer; + typedef val_alloc_ref reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef ptr_alloc_ptr index_pointer; + typedef const_iterator self_t; + + friend class deque; + friend class deque_base; + + private: + explicit iterator(const const_iterator& x) : const_iterator(x){} + + public: + //Constructors + iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} + iterator() : const_iterator(){} + //iterator(const const_iterator &cit) : const_iterator(cit){} + iterator(const iterator& x) : const_iterator(x){} + + //Pointer like operators + reference operator*() const { return *this->m_cur; } + pointer operator->() const { return this->m_cur; } + + reference operator[](difference_type n) const { return *(*this + n); } + + //Increment / Decrement + iterator& operator++() + { this->const_iterator::operator++(); return *this; } + + iterator operator++(int) + { iterator tmp = *this; ++*this; return tmp; } + + iterator& operator--() + { this->const_iterator::operator--(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + + // Arithmetic + iterator& operator+=(difference_type off) + { this->const_iterator::operator+=(off); return *this; } + + iterator operator+(difference_type off) const + { return iterator(this->const_iterator::operator+(off)); } + + friend iterator operator+(difference_type off, const iterator& right) + { return iterator(off+static_cast(right)); } + + iterator& operator-=(difference_type off) + { this->const_iterator::operator-=(off); return *this; } + + iterator operator-(difference_type off) const + { return iterator(this->const_iterator::operator-(off)); } + + difference_type operator-(const const_iterator& right) const + { return static_cast(*this) - right; } + }; + + deque_base(const allocator_type& a, std::size_t num_elements) + : members_(a) + { this->priv_initialize_map(num_elements); } + + deque_base(const allocator_type& a) + : members_(a) + {} + + ~deque_base() + { + if (this->members_.m_map) { + this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + } + } + + private: + deque_base(const deque_base&); + + protected: + + void priv_initialize_map(std::size_t num_elements) + { +// if(num_elements){ + std::size_t num_nodes = num_elements / s_buffer_size() + 1; + + this->members_.m_map_size = containers_detail::max_value((std::size_t) InitialMapSize, num_nodes + 2); + this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size); + + ptr_alloc_ptr nstart = this->members_.m_map + (this->members_.m_map_size - num_nodes) / 2; + ptr_alloc_ptr nfinish = nstart + num_nodes; + + BOOST_TRY { + this->priv_create_nodes(nstart, nfinish); + } + BOOST_CATCH(...){ + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->members_.m_map = 0; + this->members_.m_map_size = 0; + BOOST_RETHROW + } + BOOST_CATCH_END + + this->members_.m_start.priv_set_node(nstart); + this->members_.m_finish.priv_set_node(nfinish - 1); + this->members_.m_start.m_cur = this->members_.m_start.m_first; + this->members_.m_finish.m_cur = this->members_.m_finish.m_first + + num_elements % s_buffer_size(); +// } + } + + void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + ptr_alloc_ptr cur; + BOOST_TRY { + for (cur = nstart; cur < nfinish; ++cur) + *cur = this->priv_allocate_node(); + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(nstart, cur); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) + this->priv_deallocate_node(*n); + } + + enum { InitialMapSize = 8 }; + + protected: + struct members_holder + : public ptr_alloc_t + , public allocator_type + { + members_holder(const allocator_type &a) + : map_allocator_type(a), allocator_type(a) + , m_map(0), m_map_size(0) + , m_start(), m_finish(m_start) + {} + + ptr_alloc_ptr m_map; + std::size_t m_map_size; + iterator m_start; + iterator m_finish; + } members_; + + ptr_alloc_t &ptr_alloc() + { return members_; } + + const ptr_alloc_t &ptr_alloc() const + { return members_; } + + allocator_type &alloc() + { return members_; } + + const allocator_type &alloc() const + { return members_; } +}; +/// @endcond + +//! Deque class +//! +template +class deque : protected deque_base +{ + /// @cond + typedef deque_base Base; + + public: // Basic types + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename Alloc::template + rebind::other ptr_alloc_t; + typedef typename ptr_alloc_t::value_type ptr_alloc_val; + typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; + typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc_t::reference ptr_alloc_ref; + typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; + /// @endcond + + typedef T value_type; + typedef val_alloc_ptr pointer; + typedef val_alloc_cptr const_pointer; + typedef val_alloc_ref reference; + typedef val_alloc_cref const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef typename Base::allocator_type allocator_type; + + public: // Iterators + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + + /// @cond + private: // Internal typedefs + typedef ptr_alloc_ptr index_pointer; + static std::size_t s_buffer_size() + { return Base::s_buffer_size(); } + typedef containers_detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef repeat_iterator r_iterator; + typedef boost::interprocess::move_iterator move_it; + + /// @endcond + + allocator_type get_allocator() const { return Base::alloc(); } + + public: // Basic accessors + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(deque) + + iterator begin() + { return this->members_.m_start; } + + iterator end() + { return this->members_.m_finish; } + + const_iterator begin() const + { return this->members_.m_start; } + + const_iterator end() const + { return this->members_.m_finish; } + + reverse_iterator rbegin() + { return reverse_iterator(this->members_.m_finish); } + + reverse_iterator rend() + { return reverse_iterator(this->members_.m_start); } + + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->members_.m_finish); } + + const_reverse_iterator rend() const + { return const_reverse_iterator(this->members_.m_start); } + + const_iterator cbegin() const + { return this->members_.m_start; } + + const_iterator cend() const + { return this->members_.m_finish; } + + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->members_.m_finish); } + + const_reverse_iterator crend() const + { return const_reverse_iterator(this->members_.m_start); } + + reference operator[](size_type n) + { return this->members_.m_start[difference_type(n)]; } + + const_reference operator[](size_type n) const + { return this->members_.m_start[difference_type(n)]; } + + void priv_range_check(size_type n) const + { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } + + reference at(size_type n) + { this->priv_range_check(n); return (*this)[n]; } + + const_reference at(size_type n) const + { this->priv_range_check(n); return (*this)[n]; } + + reference front() { return *this->members_.m_start; } + + reference back() { return *(end()-1); } + + const_reference front() const + { return *this->members_.m_start; } + + const_reference back() const { return *(cend()-1); } + + size_type size() const + { return this->members_.m_finish - this->members_.m_start; } + + size_type max_size() const + { return this->alloc().max_size(); } + + bool empty() const + { return this->members_.m_finish == this->members_.m_start; } + + explicit deque(const allocator_type& a = allocator_type()) + : Base(a) + {} + + deque(const deque& x) + : Base(x.alloc()) + { + if(x.size()){ + this->priv_initialize_map(x.size()); + std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start); + } + } + + deque(BOOST_INTERPROCESS_RV_REF(deque) mx) + : Base(mx.alloc()) + { this->swap(mx); } + + deque(size_type n, const value_type& value, + const allocator_type& a = allocator_type()) : Base(a, n) + { this->priv_fill_initialize(value); } + + explicit deque(size_type n) : Base(allocator_type(), n) + { this->resize(n); } + + // Check whether it's an integral type. If so, it's not an iterator. + template + deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) + : Base(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_initialize_dispatch(first, last, Result()); + } + + ~deque() + { + priv_destroy_range(this->members_.m_start, this->members_.m_finish); + } + + deque& operator= (const deque& x) + { + const size_type len = size(); + if (&x != this) { + if (len >= x.size()) + this->erase(std::copy(x.begin(), x.end(), this->members_.m_start), this->members_.m_finish); + else { + const_iterator mid = x.begin() + difference_type(len); + std::copy(x.begin(), mid, this->members_.m_start); + this->insert(this->members_.m_finish, mid, x.end()); + } + } + return *this; + } + + deque& operator= (BOOST_INTERPROCESS_RV_REF(deque) x) + { + this->clear(); + this->swap(x); + return *this; + } + + void swap(deque &x) + { + std::swap(this->members_.m_start, x.members_.m_start); + std::swap(this->members_.m_finish, x.members_.m_finish); + std::swap(this->members_.m_map, x.members_.m_map); + std::swap(this->members_.m_map_size, x.members_.m_map_size); + } + + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + template + void assign(InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + void push_back(const value_type& t) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(t); + this->priv_push_back_simple_commit(); + } + else{ + this->priv_insert_aux(cend(), size_type(1), t); + } + } + + void push_back(BOOST_INTERPROCESS_RV_REF(value_type) t) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(boost::interprocess::move(t)); + this->priv_push_back_simple_commit(); + } + else{ + this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + } + } + + void push_front(const value_type& t) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(t); + this->priv_push_front_simple_commit(); + } + else{ + this->priv_insert_aux(cbegin(), size_type(1), t); + } + } + + void push_front(BOOST_INTERPROCESS_RV_REF(value_type) t) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(boost::interprocess::move(t)); + this->priv_push_front_simple_commit(); + } + else{ + this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); + } + } + + void pop_back() + { + if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { + --this->members_.m_finish.m_cur; + containers_detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); + } + else + this->priv_pop_back_aux(); + } + + void pop_front() + { + if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { + containers_detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); + ++this->members_.m_start.m_cur; + } + else + this->priv_pop_front_aux(); + } + + iterator insert(const_iterator position, const value_type& x) + { + if (position == cbegin()){ + this->push_front(x); + return begin(); + } + else if (position == cend()){ + this->push_back(x); + return (end()-1); + } + else { + size_type n = position - cbegin(); + this->priv_insert_aux(position, size_type(1), x); + return iterator(this->begin() + n); + } + } + + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) mx) + { + if (position == cbegin()) { + this->push_front(boost::interprocess::move(mx)); + return begin(); + } + else if (position == cend()) { + this->push_back(boost::interprocess::move(mx)); + return(end()-1); + } + else { + //Just call more general insert(pos, size, value) and return iterator + size_type n = position - begin(); + this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); + return iterator(this->begin() + n); + } + } + + void insert(const_iterator pos, size_type n, const value_type& x) + { this->priv_fill_insert(pos, n, x); } + + // Check whether it's an integral type. If so, it's not an iterator. + template + void insert(const_iterator pos, InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + void emplace_back(Args&&... args) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(boost::interprocess::forward(args)...); + this->priv_push_back_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(this->cend(), 1, proxy); + } + } + + template + void emplace_front(Args&&... args) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(boost::interprocess::forward(args)...); + this->priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(this->cbegin(), 1, proxy); + } + } + + template + iterator emplace(const_iterator p, Args&&... args) + { + if(p == this->cbegin()){ + this->emplace_front(boost::interprocess::forward(args)...); + return this->begin(); + } + else if(p == this->cend()){ + this->emplace_back(boost::interprocess::forward(args)...); + return (this->end()-1); + } + else{ + size_type n = p - this->cbegin(); + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(p, 1, proxy); + return iterator(this->begin() + n); + } + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //0 args + void emplace_back() + { + if(priv_push_front_simple_available()){ + new(priv_push_front_simple_pos())value_type(); + priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_insert_aux_impl(cend(), 1, proxy); + } + } + + void emplace_front() + { + if(priv_push_front_simple_available()){ + new(priv_push_front_simple_pos())value_type(); + priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_insert_aux_impl(cbegin(), 1, proxy); + } + } + + iterator emplace(const_iterator p) + { + if(p == cbegin()){ + emplace_front(); + return begin(); + } + else if(p == cend()){ + emplace_back(); + return (end()-1); + } + else{ + size_type n = p - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy; + priv_insert_aux_impl(p, 1, proxy); + return iterator(this->begin() + n); + } + } + + //advanced_insert_int.hpp includes all necessary preprocessor machinery... + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_back_simple_available()){ \ + new(priv_push_back_simple_pos())value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_push_back_simple_commit(); \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cend(), 1, proxy); \ + } \ + } \ + \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_front_simple_available()){ \ + new(priv_push_front_simple_pos())value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_push_front_simple_commit(); \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cbegin(), 1, proxy); \ + } \ + } \ + \ + template \ + iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(p == this->cbegin()){ \ + this->emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + return this->begin(); \ + } \ + else if(p == cend()){ \ + this->emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + return (this->end()-1); \ + } \ + else{ \ + size_type pos_num = p - this->cbegin(); \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + this->priv_insert_aux_impl(p, 1, proxy); \ + return iterator(this->begin() + pos_num); \ + } \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + void resize(size_type new_size, const value_type& x) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->members_.m_start + new_size, this->members_.m_finish); + else + this->insert(this->members_.m_finish, new_size - len, x); + } + + void resize(size_type new_size) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->members_.m_start + new_size, this->members_.m_finish); + else{ + size_type n = new_size - this->size(); + containers_detail::default_construct_aux_proxy proxy(n); + priv_insert_aux_impl(this->cend(), n, proxy); + } + } + + iterator erase(const_iterator pos) + { + const_iterator next = pos; + ++next; + difference_type index = pos - this->members_.m_start; + if (size_type(index) < (this->size() >> 1)) { + boost::interprocess::move_backward(begin(), iterator(pos), iterator(next)); + pop_front(); + } + else { + boost::interprocess::move(iterator(next), end(), iterator(pos)); + pop_back(); + } + return this->members_.m_start + index; + } + + iterator erase(const_iterator first, const_iterator last) + { + if (first == this->members_.m_start && last == this->members_.m_finish) { + this->clear(); + return this->members_.m_finish; + } + else { + difference_type n = last - first; + difference_type elems_before = first - this->members_.m_start; + if (elems_before < static_cast(this->size() - n) - elems_before) { + boost::interprocess::move_backward(begin(), iterator(first), iterator(last)); + iterator new_start = this->members_.m_start + n; + if(!Base::traits_t::trivial_dctr_after_move) + this->priv_destroy_range(this->members_.m_start, new_start); + this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); + this->members_.m_start = new_start; + } + else { + boost::interprocess::move(iterator(last), end(), iterator(first)); + iterator new_finish = this->members_.m_finish - n; + if(!Base::traits_t::trivial_dctr_after_move) + this->priv_destroy_range(new_finish, this->members_.m_finish); + this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); + this->members_.m_finish = new_finish; + } + return this->members_.m_start + elems_before; + } + } + + void clear() + { + for (index_pointer node = this->members_.m_start.m_node + 1; + node < this->members_.m_finish.m_node; + ++node) { + this->priv_destroy_range(*node, *node + this->s_buffer_size()); + this->priv_deallocate_node(*node); + } + + if (this->members_.m_start.m_node != this->members_.m_finish.m_node) { + this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.m_last); + this->priv_destroy_range(this->members_.m_finish.m_first, this->members_.m_finish.m_cur); + this->priv_deallocate_node(this->members_.m_finish.m_first); + } + else + this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur); + + this->members_.m_finish = this->members_.m_start; + } + + /// @cond + private: + + bool priv_push_back_simple_available() const + { + return this->members_.m_map && + (this->members_.m_finish.m_cur != (this->members_.m_finish.m_last - 1)); + } + + void *priv_push_back_simple_pos() const + { + return static_cast(containers_detail::get_pointer(this->members_.m_finish.m_cur)); + } + + void priv_push_back_simple_commit() + { + ++this->members_.m_finish.m_cur; + } + + bool priv_push_front_simple_available() const + { + return this->members_.m_map && + (this->members_.m_start.m_cur != this->members_.m_start.m_first); + } + + void *priv_push_front_simple_pos() const + { return static_cast(containers_detail::get_pointer(this->members_.m_start.m_cur) - 1); } + + void priv_push_front_simple_commit() + { --this->members_.m_start.m_cur; } + + template + void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, boost::interprocess::move(value_type(*first))); + } + } + + template + void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) + { this->priv_insert_aux(pos, first, last); } + + // assign(), a generalized assignment member function. Two + // versions: one that takes a count, and one that takes a range. + // The range version is a member template, so we dispatch on whether + // or not the type is an integer. + void priv_fill_assign(size_type n, const T& val) + { + if (n > size()) { + std::fill(begin(), end(), val); + this->insert(cend(), n - size(), val); + } + else { + this->erase(cbegin() + n, cend()); + std::fill(begin(), end(), val); + } + } + + template + void priv_initialize_dispatch(Integer n, Integer x, containers_detail::true_) + { + this->priv_initialize_map(n); + this->priv_fill_initialize(x); + } + + template + void priv_initialize_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_initialize(first, last, ItCat()); + } + + void priv_destroy_range(iterator p, iterator p2) + { + for(;p != p2; ++p) + containers_detail::get_pointer(&*p)->~value_type(); + } + + void priv_destroy_range(pointer p, pointer p2) + { + for(;p != p2; ++p) + containers_detail::get_pointer(&*p)->~value_type(); + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) + { + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first) + *cur = *first; + if (first == last) + this->erase(cur, cend()); + else + this->insert(cend(), first, last); + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type len = std::distance(first, last); + if (len > size()) { + FwdIt mid = first; + std::advance(mid, size()); + std::copy(first, mid, begin()); + this->insert(cend(), mid, last); + } + else + this->erase(std::copy(first, last, begin()), cend()); + } + + template + void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, containers_detail::true_) + { this->priv_fill_insert(pos, (size_type) n, (value_type) x); } + + template + void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_insert_aux(pos, first, last, ItCat()); + } + + void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + this->priv_insert_aux(pos, c_it(x, n), c_it()); + } + + //Just forward all operations to priv_insert_aux_impl + template + void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) + { + containers_detail::advanced_insert_aux_proxy proxy(first, last); + priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); + } + + void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) + { + iterator pos(p); + if(!this->members_.m_map){ + this->priv_initialize_map(0); + pos = this->begin(); + } + + const difference_type elemsbefore = pos - this->members_.m_start; + size_type length = this->size(); + if (elemsbefore < static_cast(length / 2)) { + iterator new_start = this->priv_reserve_elements_at_front(n); + iterator old_start = this->members_.m_start; + pos = this->members_.m_start + elemsbefore; + if (elemsbefore >= difference_type(n)) { + iterator start_n = this->members_.m_start + difference_type(n); + boost::interprocess::uninitialized_move(this->members_.m_start, start_n, new_start); + this->members_.m_start = new_start; + boost::interprocess::move(start_n, pos, old_start); + interf.copy_all_to(pos - difference_type(n)); + } + else { + difference_type mid_count = (difference_type(n) - elemsbefore); + iterator mid_start = old_start - mid_count; + interf.uninitialized_copy_some_and_update(mid_start, mid_count, true); + this->members_.m_start = mid_start; + boost::interprocess::uninitialized_move(old_start, pos, new_start); + this->members_.m_start = new_start; + interf.copy_all_to(old_start); + } + } + else { + iterator new_finish = this->priv_reserve_elements_at_back(n); + iterator old_finish = this->members_.m_finish; + const difference_type elemsafter = + difference_type(length) - elemsbefore; + pos = this->members_.m_finish - elemsafter; + if (elemsafter >= difference_type(n)) { + iterator finish_n = this->members_.m_finish - difference_type(n); + boost::interprocess::uninitialized_move(finish_n, this->members_.m_finish, this->members_.m_finish); + this->members_.m_finish = new_finish; + boost::interprocess::move_backward(pos, finish_n, old_finish); + interf.copy_all_to(pos); + } + else { + interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); + this->members_.m_finish += n-elemsafter; + boost::interprocess::uninitialized_move(pos, old_finish, this->members_.m_finish); + this->members_.m_finish = new_finish; + interf.copy_all_to(pos); + } + } + } + + void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + this->insert(pos, c_it(x, n), c_it()); + } + + // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, + // but none of the deque's elements have yet been constructed. + void priv_fill_initialize(const value_type& value) + { + index_pointer cur; + BOOST_TRY { + for (cur = this->members_.m_start.m_node; cur < this->members_.m_finish.m_node; ++cur){ + std::uninitialized_fill(*cur, *cur + this->s_buffer_size(), value); + } + std::uninitialized_fill(this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) + { + this->priv_initialize_map(0); + BOOST_TRY { + for ( ; first != last; ++first) + this->push_back(*first); + } + BOOST_CATCH(...){ + this->clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = 0; + n = std::distance(first, last); + this->priv_initialize_map(n); + + index_pointer cur_node; + BOOST_TRY { + for (cur_node = this->members_.m_start.m_node; + cur_node < this->members_.m_finish.m_node; + ++cur_node) { + FwdIt mid = first; + std::advance(mid, this->s_buffer_size()); + boost::interprocess::uninitialized_copy_or_move(first, mid, *cur_node); + first = mid; + } + boost::interprocess::uninitialized_copy_or_move(first, last, this->members_.m_finish.m_first); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first. + void priv_pop_back_aux() + { + this->priv_deallocate_node(this->members_.m_finish.m_first); + 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_last - 1; + containers_detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); + } + + // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_last - 1. Note that + // if the deque has at least one element (a precondition for this member + // function), and if this->members_.m_start.m_cur == this->members_.m_start.m_last, then the deque + // must have at least two nodes. + void priv_pop_front_aux() + { + containers_detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); + this->priv_deallocate_node(this->members_.m_start.m_first); + 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_first; + } + + iterator priv_reserve_elements_at_front(size_type n) + { + size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first; + if (n > vacancies){ + size_type new_elems = n-vacancies; + size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / + this->s_buffer_size(); + size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map); + if (new_nodes > s){ + this->priv_reallocate_map(new_nodes, true); + } + size_type i = 1; + BOOST_TRY { + for (; i <= new_nodes; ++i) + *(this->members_.m_start.m_node - i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->members_.m_start.m_node - j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + return this->members_.m_start - difference_type(n); + } + + iterator priv_reserve_elements_at_back(size_type n) + { + size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1; + if (n > vacancies){ + size_type new_elems = n - vacancies; + size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size(); + size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)); + if (new_nodes + 1 > s){ + this->priv_reallocate_map(new_nodes, false); + } + size_type i; + BOOST_TRY { + for (i = 1; i <= new_nodes; ++i) + *(this->members_.m_finish.m_node + i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->members_.m_finish.m_node + j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + return this->members_.m_finish + difference_type(n); + } + + void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) + { + size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1; + size_type new_num_nodes = old_num_nodes + nodes_to_add; + + index_pointer new_nstart; + if (this->members_.m_map_size > 2 * new_num_nodes) { + new_nstart = this->members_.m_map + (this->members_.m_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + if (new_nstart < this->members_.m_start.m_node) + boost::interprocess::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + else + boost::interprocess::move_backward + (this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart + old_num_nodes); + } + else { + size_type new_map_size = + this->members_.m_map_size + containers_detail::max_value(this->members_.m_map_size, nodes_to_add) + 2; + + index_pointer new_map = this->priv_allocate_map(new_map_size); + new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + boost::interprocess::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + + this->members_.m_map = new_map; + this->members_.m_map_size = new_map_size; + } + + this->members_.m_start.priv_set_node(new_nstart); + this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); + } + /// @endcond +}; + +// Nonmember functions. +template +inline bool operator==(const deque& x, + const deque& y) +{ + return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool operator<(const deque& x, + const deque& y) +{ + return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const deque& x, + const deque& y) + { return !(x == y); } + +template +inline bool operator>(const deque& x, + const deque& y) + { return y < x; } + +template +inline bool operator<=(const deque& x, + const deque& y) + { return !(y < x); } + +template +inline bool operator>=(const deque& x, + const deque& y) + { return !(x < y); } + + +template +inline void swap(deque& x, deque& y) +{ x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + enum { value = has_trivial_destructor::value }; +}; + +}} + +/// @endcond + +#include + +#endif // #ifndef BOOST_CONTAINERS_DEQUE_HPP diff --git a/include/boost/interprocess/detail/advanced_insert_int.hpp b/include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp similarity index 77% rename from include/boost/interprocess/detail/advanced_insert_int.hpp rename to include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp index 42b2f31..35ed645 100644 --- a/include/boost/interprocess/detail/advanced_insert_int.hpp +++ b/include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp @@ -4,26 +4,26 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP -#define BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP +#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP +#define BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include #include #include //std::iterator_traits #include //std::copy, std::uninitialized_copy #include //placement new #include -namespace boost { namespace interprocess { namespace detail { +namespace boost { namespace interprocess_container { namespace containers_detail { //This class will be interface for operations dependent on FwdIt types used advanced_insert_aux_impl template @@ -51,21 +51,21 @@ struct advanced_insert_aux_proxy {} virtual void copy_all_to(Iterator p) - { *std::copy(first_, last_, p); } + { std::copy(first_, last_, p); } virtual void uninitialized_copy_all_to(Iterator p) - { std::uninitialized_copy(first_, last_, p); } + { boost::interprocess::uninitialized_copy_or_move(first_, last_, p); } virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n) { FwdIt mid = first_; std::advance(mid, division_count); if(first_n){ - std::uninitialized_copy(first_, mid, pos); + boost::interprocess::uninitialized_copy_or_move(first_, mid, pos); first_ = mid; } else{ - std::uninitialized_copy(mid, last_, pos); + boost::interprocess::uninitialized_copy_or_move(mid, last_, pos); last_ = mid; } } @@ -104,12 +104,12 @@ struct default_construct_aux_proxy SizeType i = 0; try{ for(; i < n; ++i, ++p){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); } } catch(...){ while(i--){ - detail::get_pointer(&*orig_p++)->~T(); + containers_detail::get_pointer(&*orig_p++)->~T(); } throw; } @@ -159,18 +159,18 @@ struct default_construct_aux_proxy SizeType count_; }; -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include #include #include //#include //For debugging purposes namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { //This class template will adapt each FwIt types to advanced_insert_aux_int template @@ -204,8 +204,8 @@ struct advanced_insert_aux_emplace void priv_copy_all_to(const index_tuple&, Iterator p) { if(!used_){ - T object(detail::forward_impl(get(args_))...); - *p = detail::move_impl(object); + T object(boost::interprocess::forward(get(args_))...); + *p = boost::interprocess::move(object); used_ = true; } } @@ -214,7 +214,7 @@ struct advanced_insert_aux_emplace void priv_uninitialized_copy_all_to(const index_tuple&, Iterator p) { if(!used_){ - new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward(get(args_))...); used_ = true; } } @@ -225,7 +225,7 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward(get(args_))...); used_ = true; } } @@ -237,8 +237,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - T object(detail::forward_impl(get(args_))...); - *p = detail::move_impl(object); + T object(boost::interprocess::forward(get(args_))...); + *p = boost::interprocess::move(object); used_ = true; } } @@ -247,25 +247,16 @@ struct advanced_insert_aux_emplace bool used_; }; -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include +#include namespace boost { -namespace interprocess { -namespace detail { - -template -struct value_init_helper -{ - value_init_helper() - : m_t() - {} - - T m_t; -}; +namespace interprocess_container { +namespace containers_detail { //This class template will adapt each FwIt types to advanced_insert_aux_int template @@ -283,8 +274,8 @@ struct advanced_insert_aux_emplace virtual void copy_all_to(Iterator p) { if(!used_){ - value_init_helperv; - *p = detail::move_impl(v.m_t); + value_initv; + *p = boost::interprocess::move(v.m_t); used_ = true; } } @@ -292,7 +283,7 @@ struct advanced_insert_aux_emplace virtual void uninitialized_copy_all_to(Iterator p) { if(!used_){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); used_ = true; } } @@ -302,7 +293,7 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); used_ = true; } } @@ -313,8 +304,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - value_init_helperv; - *p = detail::move_impl(v.m_t); + value_initv; + *p = boost::interprocess::move(v.m_t); used_ = true; } } @@ -331,14 +322,14 @@ struct advanced_insert_aux_emplace typedef typename advanced_insert_aux_int::difference_type difference_type; \ \ BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - ( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _) ) \ - : used_(false), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INIT, _) {} \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \ + : used_(false), BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \ \ virtual void copy_all_to(Iterator p) \ { \ if(!used_){ \ - T v(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ - *p = detail::move_impl(v); \ + T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + *p = boost::interprocess::move(v); \ used_ = true; \ } \ } \ @@ -346,8 +337,8 @@ struct advanced_insert_aux_emplace virtual void uninitialized_copy_all_to(Iterator p) \ { \ if(!used_){ \ - new(detail::get_pointer(&*p))T \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + new(containers_detail::get_pointer(&*p))T \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ used_ = true; \ } \ } \ @@ -358,8 +349,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); \ if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \ if(!used_){ \ - new(detail::get_pointer(&*p))T \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + new(containers_detail::get_pointer(&*p))T \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ used_ = true; \ } \ } \ @@ -371,25 +362,25 @@ struct advanced_insert_aux_emplace assert(division_count <=1); \ if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \ if(!used_){ \ - T v(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ - *p = detail::move_impl(v); \ + T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + *p = boost::interprocess::move(v); \ used_ = true; \ } \ } \ } \ \ bool used_; \ - BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ + BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \ }; \ //! -#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP +#endif //#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/containers/container/detail/algorithms.hpp similarity index 70% rename from include/boost/interprocess/detail/algorithms.hpp rename to include/boost/interprocess/containers/container/detail/algorithms.hpp index 534dfef..d3baff3 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/containers/container/detail/algorithms.hpp @@ -6,59 +6,63 @@ // (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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP -#define BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP +#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP +#define BOOST_CONTAINERS_DETAIL_ALGORITHMS_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 namespace boost { -namespace interprocess { - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) +namespace interprocess_container { +#if !defined(BOOST_HAS_RVALUE_REFS) template struct has_own_construct_from_it { static const bool value = false; }; -namespace detail { +namespace containers_detail { template -inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_) +inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::true_) { T::construct(dest, *source); } template -inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_) +inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::false_) { new((void*)dest)T(*source); } -} //namespace detail { +} //namespace containers_detail { template inline void construct_in_place(T* dest, InpIt source) { - typedef detail::bool_::value> boolean_t; - detail::construct_in_place_impl(dest, source, boolean_t()); + typedef containers_detail::bool_::value> boolean_t; + containers_detail::construct_in_place_impl(dest, source, boolean_t()); } #else @@ -73,6 +77,12 @@ inline void construct_in_place(T *dest, default_construct_iterator) new((void*)dest)T(); } +template +inline void construct_in_place(T *dest, emplace_iterator ei) +{ + ei.construct_in_place(dest); +} + template struct optimize_assign { @@ -108,7 +118,7 @@ struct optimize_copy {}; template inline -OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, detail::bool_) +OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, containers_detail::bool_) { for (; length--; ++dest, ++first) *dest = *first; @@ -116,7 +126,7 @@ OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::differenc } template inline -T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, containers_detail::bool_) { std::size_t size = length*sizeof(T); return (static_cast(std::memmove(dest, first, size))) + size; @@ -126,14 +136,14 @@ 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_()); + return copy_n_dispatch(first, length, dest, containers_detail::bool_()); } template inline FwdIt uninitialized_copy_n_dispatch (InIt first, typename std::iterator_traits::difference_type count, - FwdIt dest, detail::bool_) + FwdIt dest, containers_detail::bool_) { typedef typename std::iterator_traits::value_type value_type; //Save initial destination position @@ -143,14 +153,14 @@ FwdIt uninitialized_copy_n_dispatch BOOST_TRY{ //Try to build objects for (; --new_count; ++dest, ++first){ - construct_in_place(detail::get_pointer(&*dest), first); + construct_in_place(containers_detail::get_pointer(&*dest), first); } } BOOST_CATCH(...){ //Call destructors new_count = count - new_count; for (; new_count--; ++dest_init){ - detail::get_pointer(&*dest_init)->~value_type(); + containers_detail::get_pointer(&*dest_init)->~value_type(); } BOOST_RETHROW } @@ -158,7 +168,7 @@ FwdIt uninitialized_copy_n_dispatch return dest; } template inline -T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, containers_detail::bool_) { std::size_t size = length*sizeof(T); return (static_cast(std::memmove(dest, first, size))) + size; @@ -171,7 +181,7 @@ FwdIt uninitialized_copy_n FwdIt dest) { const bool do_optimized_copy = optimize_copy::value; - return uninitialized_copy_n_dispatch(first, count, dest, detail::bool_()); + return uninitialized_copy_n_dispatch(first, count, dest, containers_detail::bool_()); } // uninitialized_copy_copy @@ -189,17 +199,17 @@ FwdIt uninitialized_copy_copy } BOOST_CATCH(...){ for(;result != mid; ++result){ - detail::get_pointer(&*result)->~value_type(); + containers_detail::get_pointer(&*result)->~value_type(); } BOOST_RETHROW } BOOST_CATCH_END } -} //namespace interprocess { +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP +#endif //#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP diff --git a/include/boost/interprocess/allocators/allocation_type.hpp b/include/boost/interprocess/containers/container/detail/allocation_type.hpp similarity index 75% rename from include/boost/interprocess/allocators/allocation_type.hpp rename to include/boost/interprocess/containers/container/detail/allocation_type.hpp index 1894d11..7cbffb3 100644 --- a/include/boost/interprocess/allocators/allocation_type.hpp +++ b/include/boost/interprocess/containers/container/detail/allocation_type.hpp @@ -4,22 +4,22 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // /////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_TYPE_COMMAND_HPP -#define BOOST_INTERPROCESS_TYPE_COMMAND_HPP +#ifndef BOOST_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_CONTAINERS_ALLOCATION_TYPE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include namespace boost { -namespace interprocess { +namespace interprocess_container { /// @cond enum allocation_type_v @@ -46,10 +46,9 @@ static const allocation_type try_shrink_in_place= (allocation_type)try_shrink_in static const allocation_type nothrow_allocation = (allocation_type)nothrow_allocation_v; static const allocation_type zero_memory = (allocation_type)zero_memory_v; -} //namespace interprocess { +} //namespace interprocess_container { } //namespace boost { -#include - -#endif //BOOST_INTERPROCESS_TYPE_COMMAND_HPP +#include +#endif //BOOST_CONTAINERS_ALLOCATION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/detail/config_begin.hpp b/include/boost/interprocess/containers/container/detail/config_begin.hpp new file mode 100644 index 0000000..814b00c --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/config_begin.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED +#define BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED +#include +#endif + +#ifdef BOOST_MSVC + #ifndef _CRT_SECURE_NO_DEPRECATE + #define BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE + #endif + #pragma warning (push) + #pragma warning (disable : 4702) // unreachable code + #pragma warning (disable : 4706) // assignment within conditional expression + #pragma warning (disable : 4127) // conditional expression is constant + #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" + #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data + #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" + #pragma warning (disable : 4355) // "this" : used in base member initializer list + #pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated + #pragma warning (disable : 4511) // copy constructor could not be generated + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4514) // unreferenced inline removed + #pragma warning (disable : 4521) // Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) // "class" : multiple assignment operators specified + #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter + #pragma warning (disable : 4710) // function not inlined + #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 + #pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception' + // with /GR-; unpredictable behavior may result + #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site + #pragma warning (disable : 4671) // the copy constructor is inaccessible +#endif diff --git a/include/boost/interprocess/containers/container/detail/config_end.hpp b/include/boost/interprocess/containers/container/detail/config_end.hpp new file mode 100644 index 0000000..a6c46ef --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/config_end.hpp @@ -0,0 +1,17 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) + #ifdef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #undef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #undef _CRT_SECURE_NO_DEPRECATE + #endif +#endif + diff --git a/include/boost/interprocess/containers/container/detail/destroyers.hpp b/include/boost/interprocess/containers/container/detail/destroyers.hpp new file mode 100644 index 0000000..c16139b --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/destroyers.hpp @@ -0,0 +1,154 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DESTROYERS_HPP +#define BOOST_CONTAINERS_DESTROYERS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an array of objects using a STL allocator. +template +struct scoped_array_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::size_type size_type; + + scoped_array_deallocator(pointer p, Allocator& a, size_type length) + : m_ptr(p), m_alloc(a), m_length(length) {} + + ~scoped_array_deallocator() + { if (m_ptr) m_alloc.deallocate(m_ptr, m_length); } + + void release() + { m_ptr = 0; } + + private: + pointer m_ptr; + Allocator& m_alloc; + size_type m_length; +}; + +template +struct null_scoped_array_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::size_type size_type; + + null_scoped_array_deallocator(pointer, Allocator&, size_type) + {} + + void release() + {} +}; + + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct scoped_destructor_n +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::value_type value_type; + typedef typename Allocator::size_type size_type; + + pointer m_p; + size_type m_n; + + scoped_destructor_n(pointer p, size_type n) + : m_p(p), m_n(n) + {} + + void release() + { m_p = 0; } + + void increment_size(size_type inc) + { m_n += inc; } + + ~scoped_destructor_n() + { + if(!m_p) return; + value_type *raw_ptr = containers_detail::get_pointer(m_p); + for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr) + raw_ptr->~value_type(); + } +}; + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct null_scoped_destructor_n +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::size_type size_type; + + null_scoped_destructor_n(pointer, size_type) + {} + + void increment_size(size_type) + {} + + void release() + {} +}; + +template +class allocator_destroyer +{ + typedef typename A::value_type value_type; + typedef containers_detail::integral_constant::value> alloc_version; + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + + private: + A & a_; + + private: + void priv_deallocate(const typename A::pointer &p, allocator_v1) + { a_.deallocate(p, 1); } + + void priv_deallocate(const typename A::pointer &p, allocator_v2) + { a_.deallocate_one(p); } + + public: + allocator_destroyer(A &a) + : a_(a) + {} + + void operator()(const typename A::pointer &p) + { + containers_detail::get_pointer(p)->~value_type(); + priv_deallocate(p, alloc_version()); + } +}; + + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DESTROYERS_HPP diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/container/detail/flat_tree.hpp similarity index 80% rename from include/boost/interprocess/containers/detail/flat_tree.hpp rename to include/boost/interprocess/containers/container/detail/flat_tree.hpp index c2ebfc1..438fa75 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/container/detail/flat_tree.hpp @@ -4,7 +4,7 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // //////////////////////////////////////////////////////////////////////////////// // The Loki Library @@ -25,35 +25,40 @@ // //////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_TREE_HPP -#define BOOST_INTERPROCESS_FLAT_TREE_HPP +#ifndef BOOST_CONTAINERS_FLAT_TREE_HPP +#define BOOST_CONTAINERS_FLAT_TREE_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 +#include + namespace boost { -namespace interprocess { +namespace interprocess_container { -namespace detail { +namespace containers_detail { template class flat_tree { - typedef boost::interprocess::vector vector_t; + typedef boost::interprocess_container::vector vector_t; typedef Alloc allocator_t; public: @@ -105,6 +110,7 @@ class flat_tree Data m_data; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_tree) typedef typename vector_t::value_type value_type; typedef typename vector_t::pointer pointer; @@ -133,15 +139,9 @@ class flat_tree : m_data(x.m_data, x.m_data.m_vect) { } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree(detail::moved_object x) - : m_data(detail::move_impl(x.get().m_data)) + flat_tree(BOOST_INTERPROCESS_RV_REF(flat_tree) x) + : m_data(boost::interprocess::move(x.m_data)) { } - #else - flat_tree(flat_tree &&x) - : m_data(detail::move_impl(x.m_data)) - { } - #endif ~flat_tree() { } @@ -149,13 +149,8 @@ class flat_tree flat_tree& operator=(const flat_tree& x) { m_data = x.m_data; return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree& operator=(detail::moved_object mx) - { m_data = detail::move_impl(mx.get().m_data); return *this; } - #else - flat_tree& operator=(flat_tree &&mx) - { m_data = detail::move_impl(mx.m_data); return *this; } - #endif + flat_tree& operator=(BOOST_INTERPROCESS_RV_REF(flat_tree) mx) + { m_data = boost::interprocess::move(mx.m_data); return *this; } public: // accessors: @@ -220,20 +215,12 @@ class flat_tree { value_compare& mycomp = this->m_data; value_compare& othercomp = other.m_data; - detail::do_swap(mycomp, othercomp); + containers_detail::do_swap(mycomp, othercomp); vector_t & myvect = this->m_data.m_vect; vector_t & othervect = other.m_data.m_vect; myvect.swap(othervect); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object other) - { this->swap(other.get()); } - #else - void swap(flat_tree &&other) - { this->swap(other); } - #endif - public: // insert/erase std::pair insert_unique(const value_type& val) @@ -246,18 +233,12 @@ class flat_tree return ret; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert_unique(detail::moved_object mval) + std::pair insert_unique(BOOST_INTERPROCESS_RV_REF(value_type) val) { - value_type &val = mval.get(); - #else - std::pair insert_unique(value_type && val) - { - #endif insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret; } @@ -270,21 +251,12 @@ class flat_tree return i; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(detail::moved_object mval) - { - iterator i = this->upper_bound(KeyOfValue()(mval.get())); - i = this->m_data.m_vect.insert(i, mval); - return i; - } - #else - iterator insert_equal(value_type && mval) + iterator insert_equal(BOOST_INTERPROCESS_RV_REF(value_type) mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, detail::move_impl(mval)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(mval)); return i; } - #endif iterator insert_unique(const_iterator pos, const value_type& val) { @@ -296,27 +268,15 @@ class flat_tree return ret.first; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_unique(const_iterator pos, detail::moved_object mval) - { - insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(pos, mval.get(), data); - if(ret.second){ - ret.first = priv_insert_commit(data, mval); - } - return ret.first; - } - #else - iterator insert_unique(const_iterator pos, value_type&&mval) + iterator insert_unique(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval) { insert_commit_data data; std::pair ret = priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(mval)); + ret.first = priv_insert_commit(data, boost::interprocess::move(mval)); } return ret.first; } - #endif iterator insert_equal(const_iterator pos, const value_type& val) { @@ -325,21 +285,12 @@ class flat_tree return priv_insert_commit(data, val); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(const_iterator pos, detail::moved_object mval) - { - insert_commit_data data; - priv_insert_equal_prepare(pos, mval.get(), data); - return priv_insert_commit(data, mval); - } - #else - iterator insert_equal(const_iterator pos, value_type && mval) + iterator insert_equal(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval) { insert_commit_data data; priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, detail::move_impl(mval)); + return priv_insert_commit(data, boost::interprocess::move(mval)); } - #endif template void insert_unique(InIt first, InIt last) @@ -356,17 +307,17 @@ class flat_tree priv_insert_equal(first, last, ItCat()); } - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template iterator emplace_unique(Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } @@ -374,11 +325,11 @@ class flat_tree template iterator emplace_hint_unique(const_iterator hint, Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; std::pair ret = priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } @@ -386,115 +337,115 @@ class flat_tree template iterator emplace_equal(Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); return i; } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; priv_insert_equal_prepare(hint, val, data); - return priv_insert_commit(data, detail::move_impl(val)); + return priv_insert_commit(data, boost::interprocess::move(val)); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator emplace_unique() { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } iterator emplace_hint_unique(const_iterator hint) { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; std::pair ret = priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } iterator emplace_equal() { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); return i; } iterator emplace_hint_equal(const_iterator hint) { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; priv_insert_equal_prepare(hint, val, data); - return priv_insert_commit(data, detail::move_impl(val)); + return priv_insert_commit(data, boost::interprocess::move(val)); } #define BOOST_PP_LOCAL_MACRO(n) \ template \ - iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ std::pair ret = priv_insert_unique_prepare(val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); \ } \ return ret.first; \ } \ \ template \ iterator emplace_hint_unique(const_iterator hint, \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ std::pair ret = priv_insert_unique_prepare(hint, val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); \ } \ return ret.first; \ } \ \ template \ - iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ iterator i = this->upper_bound(KeyOfValue()(val)); \ - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); \ + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); \ return i; \ } \ \ template \ iterator emplace_hint_equal(const_iterator hint, \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ priv_insert_equal_prepare(hint, val, data); \ - return priv_insert_commit(data, detail::move_impl(val)); \ + return priv_insert_commit(data, boost::interprocess::move(val)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator erase(const_iterator position) { return this->m_data.m_vect.erase(position); } @@ -682,17 +633,14 @@ class flat_tree } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator priv_insert_commit - (insert_commit_data &commit_data, const Convertible &convertible) - { return this->m_data.m_vect.insert(commit_data.position, convertible); } - #else - template - iterator priv_insert_commit - (insert_commit_data &commit_data, Convertible &&convertible) - { return this->m_data.m_vect.insert(commit_data.position, detail::forward_impl(convertible)); } - #endif + (insert_commit_data &commit_data, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible) + { + return this->m_data.m_vect.insert + ( commit_data.position + , boost::interprocess::forward(convertible)); + } template RanIt priv_lower_bound(RanIt first, RanIt last, @@ -865,23 +813,25 @@ swap(flat_tree& x, flat_tree& y) { x.swap(y); } -} //namespace detail { +} //namespace containers_detail { + +} //namespace interprocess_container { + +namespace interprocess { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class C, class A> +struct has_trivial_destructor_after_move > { - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; }; } //namespace interprocess { } //namespace boost { -#include +#include -#endif // BOOST_INTERPROCESS_FLAT_TREE_HPP +#endif // BOOST_CONTAINERS_FLAT_TREE_HPP diff --git a/include/boost/interprocess/detail/iterators.hpp b/include/boost/interprocess/containers/container/detail/iterators.hpp similarity index 65% rename from include/boost/interprocess/detail/iterators.hpp rename to include/boost/interprocess/containers/container/detail/iterators.hpp index c566159..64841b1 100644 --- a/include/boost/interprocess/detail/iterators.hpp +++ b/include/boost/interprocess/containers/container/detail/iterators.hpp @@ -7,27 +7,31 @@ // (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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP -#define BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP +#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP +#define BOOST_CONTAINERS_DETAIL_ITERATORS_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include +#include -#include +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#else +#include +#endif #include -#include namespace boost { -namespace interprocess { +namespace interprocess_container { template class constant_iterator @@ -324,152 +328,165 @@ class repeat_iterator { return m_num - other.m_num; } }; -template -struct operator_arrow_proxy +template +class emplace_iterator + : public std::iterator + { - operator_arrow_proxy(const PseudoReference &px) - : m_value(px) - {} + typedef emplace_iterator this_type; - PseudoReference* operator->() const { return &m_value; } - // This function is needed for MWCW and BCC, which won't call operator-> - // again automatically per 13.3.1.2 para 8 -// operator T*() const { return &m_value; } - mutable PseudoReference m_value; -}; - -template -struct operator_arrow_proxy -{ - operator_arrow_proxy(T &px) - : m_value(px) - {} - - T* operator->() const { return &m_value; } - // This function is needed for MWCW and BCC, which won't call operator-> - // again automatically per 13.3.1.2 para 8 -// operator T*() const { return &m_value; } - mutable T &m_value; -}; - -template -class transform_iterator - : public UnaryFunction - , public std::iterator - < typename Iterator::iterator_category - , typename detail::remove_reference::type - , typename Iterator::difference_type - , operator_arrow_proxy - , typename UnaryFunction::result_type> -{ public: - explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) - : UnaryFunction(f), m_it(it) - {} + explicit emplace_iterator(E&e) + : m_num(1), m_pe(&e){} - explicit transform_iterator() - : UnaryFunction(), m_it() - {} + emplace_iterator() + : m_num(0), m_pe(0){} - //Constructors - transform_iterator& operator++() + this_type& operator++() { increment(); return *this; } - - transform_iterator operator++(int) + + this_type operator++(int) { - transform_iterator result (*this); + this_type result (*this); increment(); return result; } - friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + friend bool operator== (const this_type& i, const this_type& i2) { return i.equal(i2); } - friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator!= (const this_type& i, const this_type& i2) { return !(i == i2); } -/* - friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + friend bool operator< (const this_type& i, const this_type& i2) + { return i.less(i2); } + + friend bool operator> (const this_type& i, const this_type& i2) { return i2 < i; } - friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator<= (const this_type& i, const this_type& i2) { return !(i > i2); } - friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator>= (const this_type& i, const this_type& i2) { return !(i < i2); } -*/ - friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + + friend std::ptrdiff_t operator- (const this_type& i, const this_type& i2) { return i2.distance_to(i); } //Arithmetic - transform_iterator& operator+=(typename Iterator::difference_type off) + this_type& operator+=(std::ptrdiff_t off) { this->advance(off); return *this; } - transform_iterator operator+(typename Iterator::difference_type off) const + this_type operator+(std::ptrdiff_t off) const { - transform_iterator other(*this); + this_type other(*this); other.advance(off); return other; } - friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + friend this_type operator+(std::ptrdiff_t off, const this_type& right) { return right + off; } - transform_iterator& operator-=(typename Iterator::difference_type off) + this_type& operator-=(std::ptrdiff_t off) { this->advance(-off); return *this; } - transform_iterator operator-(typename Iterator::difference_type off) const + this_type operator-(std::ptrdiff_t off) const { return *this + (-off); } - typename UnaryFunction::result_type operator*() const + const T& operator*() const { return dereference(); } - operator_arrow_proxy - operator->() const - { return operator_arrow_proxy(dereference()); } + const T* operator->() const + { return &(dereference()); } - Iterator & base() - { return m_it; } - - const Iterator & base() const - { return m_it; } + void construct_in_place(T* ptr) + { (*m_pe)(ptr); } private: - Iterator m_it; + std::ptrdiff_t m_num; + E * m_pe; void increment() - { ++m_it; } + { --m_num; } void decrement() - { --m_it; } + { ++m_num; } - bool equal(const transform_iterator &other) const - { return m_it == other.m_it; } + bool equal(const this_type &other) const + { return m_num == other.m_num; } - bool less(const transform_iterator &other) const - { return other.m_it < m_it; } + bool less(const this_type &other) const + { return other.m_num < m_num; } - typename UnaryFunction::result_type dereference() const - { return UnaryFunction::operator()(*m_it); } + const T & dereference() const + { + static T dummy; + return dummy; + } - void advance(typename Iterator::difference_type n) - { std::advance(m_it, n); } + void advance(std::ptrdiff_t n) + { m_num -= n; } - typename Iterator::difference_type distance_to(const transform_iterator &other)const - { return std::distance(other.m_it, m_it); } + std::ptrdiff_t distance_to(const this_type &other)const + { return m_num - other.m_num; } }; -template -transform_iterator -make_transform_iterator(Iterator it, UnaryFunc fun) -{ - return transform_iterator(it, fun); -} +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -} //namespace interprocess { +template +struct emplace_functor +{ + typedef typename containers_detail::build_number_seq::type index_tuple_t; + + emplace_functor(Args&&... args) + : args_(args...) + {} + + void operator()(T *ptr) + { emplace_functor::inplace_impl(ptr, index_tuple_t()); } + + template + void inplace_impl(T* ptr, const containers_detail::index_tuple&) + { ::new(ptr) T(boost::interprocess::forward(containers_detail::get(args_))...); } + + containers_detail::tuple args_; +}; + +#else + +template +struct emplace_functor +{ + emplace_functor() + {} + void operator()(T *ptr) + { new(ptr) T(); } +}; + +#define BOOST_PP_LOCAL_MACRO(n) \ + template \ + struct BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + { \ + BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \ + : BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \ + \ + void operator()(T *ptr) \ + { \ + new(ptr)T (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + } \ + BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \ + }; \ + //! +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +#endif + +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP +#endif //#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP diff --git a/include/boost/interprocess/containers/container/detail/mpl.hpp b/include/boost/interprocess/containers/container/detail/mpl.hpp new file mode 100644 index 0000000..fbdcb44 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/mpl.hpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP +#define BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct integral_constant +{ + static const T value = val; + typedef integral_constant type; +}; + +template< bool C_ > +struct bool_ : integral_constant +{ + static const bool value = C_; +}; + +typedef bool_ true_; +typedef bool_ false_; + +typedef true_ true_type; +typedef false_ false_type; + +typedef char yes_type; +struct no_type +{ + char padding[8]; +}; + +template +struct enable_if_c { + typedef T type; +}; + +template +struct enable_if_c {}; + +template +struct enable_if : public enable_if_c {}; + +template +struct disable_if : public enable_if_c {}; + +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; +}; + +template< + bool C + , typename T1 + , typename T2 + > +struct if_c +{ + typedef T1 type; +}; + +template< + typename T1 + , typename T2 + > +struct if_c +{ + typedef T2 type; +}; + +template< + typename T1 + , typename T2 + , typename T3 + > +struct if_ +{ + typedef typename if_c<0 != T1::value, T2, T3>::type type; +}; + + +template +struct select1st +// : public std::unary_function +{ + template + const typename Pair::first_type& operator()(const OtherPair& x) const + { return x.first; } + + const typename Pair::first_type& operator()(const typename Pair::first_type& x) const + { return x; } +}; + +// identity is an extension: it is not part of the standard. +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 containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP + diff --git a/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp b/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp new file mode 100644 index 0000000..1f3f2c5 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp @@ -0,0 +1,554 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP +#define BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +class basic_multiallocation_slist +{ +public: + typedef VoidPointer void_pointer; + +private: + static VoidPointer &priv_get_ref(const VoidPointer &p) + { return *static_cast(containers_detail::get_pointer(p)); } + + basic_multiallocation_slist(basic_multiallocation_slist &); + basic_multiallocation_slist &operator=(basic_multiallocation_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist) + + //!This iterator is returned by "allocate_many" functions so that + //!the user can access the multiple buffers allocated in a single call + class iterator + : public std::iterator + { + friend class basic_multiallocation_slist; + void unspecified_bool_type_func() const {} + typedef void (iterator::*unspecified_bool_type)() const; + + iterator(void_pointer node_range) + : next_node_(node_range) + {} + + public: + typedef char value_type; + typedef value_type & reference; + typedef value_type * pointer; + + iterator() + : next_node_(0) + {} + + iterator &operator=(const iterator &other) + { next_node_ = other.next_node_; return *this; } + + public: + iterator& operator++() + { + next_node_ = *static_cast(containers_detail::get_pointer(next_node_)); + return *this; + } + + iterator operator++(int) + { + iterator result(*this); + ++*this; + return result; + } + + bool operator== (const iterator& other) const + { return next_node_ == other.next_node_; } + + bool operator!= (const iterator& other) const + { return !operator== (other); } + + reference operator*() const + { return *static_cast(containers_detail::get_pointer(next_node_)); } + + operator unspecified_bool_type() const + { return next_node_? &iterator::unspecified_bool_type_func : 0; } + + pointer operator->() const + { return &(*(*this)); } + + private: + void_pointer next_node_; + }; + +private: + iterator it_; + +public: + basic_multiallocation_slist() + : it_(iterator()) + {} + + basic_multiallocation_slist(void_pointer p) + : it_(p ? iterator_to(p) : iterator()) + {} + + basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + : it_(iterator()) + { this->swap(other); } + + basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + { + basic_multiallocation_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return !it_; } + + iterator before_begin() const + { return iterator(void_pointer(const_cast(static_cast(&it_.next_node_)))); } + + iterator begin() const + { return it_; } + + iterator end() const + { return iterator(); } + + void clear() + { this->it_.next_node_ = void_pointer(0); } + + iterator insert_after(iterator it, void_pointer m) + { + priv_get_ref(m) = priv_get_ref(it.next_node_); + priv_get_ref(it.next_node_) = m; + return iterator(m); + } + + void push_front(void_pointer m) + { + priv_get_ref(m) = this->it_.next_node_; + this->it_.next_node_ = m; + } + + void pop_front() + { ++it_; } + + void *front() const + { return containers_detail::get_pointer(it_.next_node_); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if (after_this != before_begin && after_this != before_end && before_begin != before_end) { + void_pointer next_b = priv_get_ref(before_begin.next_node_); + void_pointer next_e = priv_get_ref(before_end.next_node_); + void_pointer next_p = priv_get_ref(after_this.next_node_); + priv_get_ref(before_begin.next_node_) = next_e; + priv_get_ref(before_end.next_node_) = next_p; + priv_get_ref(after_this.next_node_) = next_b; + } + } + + void swap(basic_multiallocation_slist &other_chain) + { + std::swap(this->it_, other_chain.it_); + } + + static iterator iterator_to(void_pointer p) + { return iterator(p); } + + void_pointer extract_data() + { + void_pointer ret = empty() ? void_pointer(0) : void_pointer(&*it_); + it_ = iterator(); + return ret; + } +}; + +template +class basic_multiallocation_cached_slist +{ +private: + basic_multiallocation_slist slist_; + typename basic_multiallocation_slist::iterator last_; + + basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &); + basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist) + + typedef typename basic_multiallocation_slist::void_pointer void_pointer; + typedef typename basic_multiallocation_slist::iterator iterator; + + basic_multiallocation_cached_slist() + : slist_(), last_(slist_.before_begin()) + {} + /* + basic_multiallocation_cached_slist(iterator first_node) + : slist_(first_node), last_(slist_.before_begin()) + { + iterator end; + while(first_node != end){ + ++last_; + } + }*/ + + basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2) + : slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin()) + {} + + basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + : slist_(), last_(slist_.before_begin()) + { this->swap(other); } + + basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + { + basic_multiallocation_cached_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return slist_.empty(); } + + iterator before_begin() const + { return slist_.before_begin(); } + + iterator begin() const + { return slist_.begin(); } + + iterator end() const + { return slist_.end(); } + + iterator last() const + { return last_; } + + void clear() + { + slist_.clear(); + last_ = slist_.before_begin(); + } + + iterator insert_after(iterator it, void_pointer m) + { + slist_.insert_after(it, m); + if(it == last_){ + last_ = slist_.iterator_to(m); + } + return iterator_to(m); + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(last_, m); } + + void pop_front() + { + if(last_ == slist_.begin()){ + last_ = slist_.before_begin(); + } + slist_.pop_front(); + } + + void *front() const + { return slist_.front(); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if(before_begin == before_end) + return; + if(after_this == last_){ + last_ = before_end; + } + slist_.splice_after(after_this, before_begin, before_end); + } + + void swap(basic_multiallocation_cached_slist &x) + { + slist_.swap(x.slist_); + using std::swap; + swap(last_, x.last_); + if(last_ == x.before_begin()){ + last_ = this->before_begin(); + } + if(x.last_ == this->before_begin()){ + x.last_ = x.before_begin(); + } + } + + static iterator iterator_to(void_pointer p) + { return basic_multiallocation_slist::iterator_to(p); } + + std::pair extract_data() + { + if(this->empty()){ + return std::pair(void_pointer(0), void_pointer(0)); + } + else{ + void_pointer p1 = slist_.extract_data(); + void_pointer p2 = void_pointer(&*last_); + last_ = iterator(); + return std::pair(p1, p2); + } + } +}; + +template +class basic_multiallocation_cached_counted_slist +{ +private: + MultiallocatorCachedSlist cached_slist_; + std::size_t size_; + + basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &); + basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist) + + typedef typename MultiallocatorCachedSlist::void_pointer void_pointer; + typedef typename MultiallocatorCachedSlist::iterator iterator; + + basic_multiallocation_cached_counted_slist() + : cached_slist_(), size_(0) + {} + + basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n) + : cached_slist_(p1, p2), size_(n) + {} + + basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + : cached_slist_(), size_(0) + { this->swap(other); } + + basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + { + basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n) + : cached_slist_(boost::interprocess::move(mem)), size_(n) + {} + + bool empty() const + { return cached_slist_.empty(); } + + std::size_t size() const + { return size_; } + + iterator before_begin() const + { return cached_slist_.before_begin(); } + + iterator begin() const + { return cached_slist_.begin(); } + + iterator end() const + { return cached_slist_.end(); } + + iterator last() const + { return cached_slist_.last(); } + + void clear() + { + cached_slist_.clear(); + size_ = 0; + } + + iterator insert_after(iterator it, void_pointer m) + { + iterator ret = cached_slist_.insert_after(it, m); + ++size_; + return ret; + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void pop_front() + { + cached_slist_.pop_front(); + --size_; + } + + void *front() const + { return cached_slist_.front(); } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end) + { + std::size_t n = static_cast(std::distance(before_begin, before_end)); + this->splice_after(after_this, x, before_begin, before_end, n); + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end, std::size_t n) + { + cached_slist_.splice_after(after_this, before_begin, before_end); + size_ += n; + x.size_ -= n; + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.splice_after(after_this, x.before_begin(), x.last()); + size_ += x.size_; + x.size_ = 0; + } + + void swap(basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.swap(x.cached_slist_); + using std::swap; + swap(size_, x.size_); + } + + static iterator iterator_to(void_pointer p) + { return MultiallocatorCachedSlist::iterator_to(p); } + + std::pair extract_data() + { + size_ = 0; + return cached_slist_.extract_data(); + } +}; + +template +struct cast_functor +{ + typedef typename containers_detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + + +template +class transform_multiallocation_chain +{ +private: + + MultiallocationChain holder_; + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::pointer_to_other + ::type pointer; + + transform_multiallocation_chain(transform_multiallocation_chain &); + transform_multiallocation_chain &operator=(transform_multiallocation_chain &); + + static pointer cast(void_pointer p) + { + return pointer(static_cast(containers_detail::get_pointer(p))); + } + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain) + + typedef transform_iterator + < typename MultiallocationChain::iterator + , containers_detail::cast_functor > iterator; + + transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n) + : holder_(p1, p2, n) + {} + + transform_multiallocation_chain() + : holder_() + {} + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + : holder_() + { this->swap(other); } + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other) + : holder_(boost::interprocess::move(other)) + {} + + transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + { + transform_multiallocation_chain tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + void push_front(pointer mem) + { holder_.push_front(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + /* + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); } + */ + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n) + { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } + + void pop_front() + { holder_.pop_front(); } + + pointer front() const + { return cast(holder_.front()); } + + bool empty() const + { return holder_.empty(); } + + iterator before_begin() const + { return iterator(holder_.before_begin()); } + + iterator begin() const + { return iterator(holder_.begin()); } + + iterator end() const + { return iterator(holder_.end()); } + + iterator last() const + { return iterator(holder_.last()); } + + std::size_t size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } + + iterator insert_after(iterator it, pointer m) + { return iterator(holder_.insert_after(it.base(), m)); } + + static iterator iterator_to(pointer p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { return holder_.extract_data(); } + + MultiallocationChain extract_multiallocation_chain() + { + return MultiallocationChain(boost::interprocess::move(holder_)); + } +}; + +}}} + +// namespace containers_detail { +// namespace interprocess_container { +// namespace boost { + +#include + +#endif //BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp similarity index 58% rename from include/boost/interprocess/containers/detail/node_alloc_holder.hpp rename to include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp index 6e88903..6a5160d 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp @@ -4,36 +4,137 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ -#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ +#ifndef BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ +#define BOOST_CONTAINERS_DETAIL_NODE_ALLOC_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 +#include +#include +#include +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +#include + namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef containers_detail::integral_constant::value> alloc_version; + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + + private: + void priv_deallocate(allocator_v1) + { m_alloc.deallocate(m_ptr, 1); } + + void priv_deallocate(allocator_v2) + { m_alloc.deallocate_one(m_ptr); } + + scoped_deallocator(scoped_deallocator &); + scoped_deallocator& operator=(scoped_deallocator &); + + public: + + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_deallocator) + + pointer m_ptr; + Allocator& m_alloc; + + scoped_deallocator(pointer p, Allocator& a) + : m_ptr(p), m_alloc(a) + {} + + ~scoped_deallocator() + { if (m_ptr)priv_deallocate(alloc_version()); } + + scoped_deallocator(BOOST_INTERPROCESS_RV_REF(scoped_deallocator) o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { o.release(); } + + pointer get() const + { return m_ptr; } + + void release() + { m_ptr = 0; } +}; + +template +class allocator_destroyer_and_chain_builder +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + + A & a_; + multiallocation_chain &c_; + + public: + allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) + : a_(a), c_(c) + {} + + void operator()(const typename A::pointer &p) + { + value_type *vp = containers_detail::get_pointer(p); + vp->~value_type(); + c_.push_front(vp); + } +}; + +template +class allocator_multialloc_chain_node_deallocator +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_node_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_node_deallocator() + { + if(!c_.empty()) + a_.deallocate_individual(boost::interprocess::move(c_)); + } +}; + template struct node_compare @@ -66,18 +167,25 @@ struct node_alloc_holder typedef typename A::template rebind::other NodeAlloc; typedef A ValAlloc; typedef typename NodeAlloc::pointer NodePtr; - typedef detail::scoped_deallocator Deallocator; + typedef containers_detail::scoped_deallocator Deallocator; typedef typename NodeAlloc::size_type size_type; typedef typename NodeAlloc::difference_type difference_type; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; typedef typename ICont::iterator icont_iterator; typedef typename ICont::const_iterator icont_citerator; typedef allocator_destroyer Destroyer; + private: + node_alloc_holder(node_alloc_holder&); + node_alloc_holder & operator=(node_alloc_holder&); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(node_alloc_holder) + node_alloc_holder(const ValAlloc &a) : members_(a) {} @@ -86,32 +194,19 @@ struct node_alloc_holder : members_(other.node_alloc()) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - node_alloc_holder(detail::moved_object other) - : members_(detail::move_impl(other.get().node_alloc())) - { this->swap(other.get()); } - #else - node_alloc_holder(node_alloc_holder &&other) - : members_(detail::move_impl(other.node_alloc())) + node_alloc_holder(BOOST_INTERPROCESS_RV_REF(node_alloc_holder) other) + : members_(boost::interprocess::move(other.node_alloc())) { this->swap(other); } - #endif template node_alloc_holder(const ValAlloc &a, const Pred &c) : members_(a, typename ICont::value_compare(c)) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - node_alloc_holder(detail::moved_object a, const Pred &c) - : members_(a.get(), typename ICont::value_compare(c)) - {} - #else - template - node_alloc_holder(ValAlloc &&a, const Pred &c) + node_alloc_holder(BOOST_INTERPROCESS_RV_REF(ValAlloc) a, const Pred &c) : members_(a, typename ICont::value_compare(c)) {} - #endif template node_alloc_holder(const node_alloc_holder &other, const Pred &c) @@ -142,46 +237,27 @@ struct node_alloc_holder void deallocate_one(NodePtr p, allocator_v2) { this->node_alloc().deallocate_one(p); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - static void construct(const NodePtr &ptr, detail::moved_object > value) - { - typedef typename Node::hook_type hook_type; - typedef typename Node::value_type::first_type first_type; - typedef typename Node::value_type::second_type second_type; - Node *nodeptr = detail::get_pointer(ptr); - - //Hook constructor does not throw - new(static_cast(nodeptr))hook_type(); - //Now construct pair members_holder - value_type *valueptr = &nodeptr->get_data(); - new((void*)&valueptr->first) first_type(detail::move_impl(value.get().first)); - BOOST_TRY{ - new((void*)&valueptr->second) second_type(detail::move_impl(value.get().second)); - } - BOOST_CATCH(...){ - valueptr->first.~first_type(); - static_cast(nodeptr)->~hook_type(); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #else - template - static void construct(const NodePtr &ptr, std::pair &&value) + static void construct(const NodePtr &ptr, + #ifdef BOOST_HAS_RVALUE_REFS + std::pair && + #else + boost::interprocess::rv > & + #endif + value) { typedef typename Node::hook_type hook_type; typedef typename Node::value_type::first_type first_type; typedef typename Node::value_type::second_type second_type; - Node *nodeptr = detail::get_pointer(ptr); + Node *nodeptr = containers_detail::get_pointer(ptr); //Hook constructor does not throw new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->get_data(); - new((void*)&valueptr->first) first_type(detail::move_impl(value.first)); + new((void*)&valueptr->first) first_type(boost::interprocess::move(value.first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(detail::move_impl(value.second)); + new((void*)&valueptr->second) second_type(boost::interprocess::move(value.second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -190,44 +266,35 @@ struct node_alloc_holder } BOOST_CATCH_END } - #endif static void destroy(const NodePtr &ptr) - { detail::get_pointer(ptr)->~Node(); } + { containers_detail::get_pointer(ptr)->~Node(); } - - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - Deallocator - #else - move_return - #endif - create_node_and_deallocator() + Deallocator create_node_and_deallocator() { - NodePtr p = this->allocate_one(); - Deallocator node_deallocator(p, this->node_alloc()); - return node_deallocator; + return Deallocator(this->allocate_one(), this->node_alloc()); } - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template static void construct(const NodePtr &ptr, Args &&...args) - { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(args)...); } + { new((void*)containers_detail::get_pointer(ptr)) Node(boost::interprocess::forward(args)...); } template NodePtr create_node(Args &&...args) { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, detail::forward_impl(args)...); + self_t::construct(p, boost::interprocess::forward(args)...); node_deallocator.release(); return (p); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING static void construct(const NodePtr &ptr) - { new((void*)detail::get_pointer(ptr)) Node(); } + { new((void*)containers_detail::get_pointer(ptr)) Node(); } NodePtr create_node() { @@ -240,37 +307,37 @@ struct node_alloc_holder #define BOOST_PP_LOCAL_MACRO(n) \ template \ - void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - new((void*)detail::get_pointer(ptr)) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + new((void*)containers_detail::get_pointer(ptr)) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #define BOOST_PP_LOCAL_MACRO(n) \ template \ - NodePtr create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ NodePtr p = this->allocate_one(); \ Deallocator node_deallocator(p, this->node_alloc()); \ - self_t::construct(p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + self_t::construct(p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ node_deallocator.release(); \ return (p); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template NodePtr create_node_from_it(It it) { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - ::boost::interprocess::construct_in_place(detail::get_pointer(p), it); + ::boost::interprocess_container::construct_in_place(containers_detail::get_pointer(p), it); node_deallocator.release(); return (p); } @@ -287,7 +354,7 @@ struct node_alloc_holder NodeAlloc& other_alloc = x.node_alloc(); if (this_alloc != other_alloc){ - detail::do_swap(this_alloc, other_alloc); + containers_detail::do_swap(this_alloc, other_alloc); } this->icont().swap(x.icont()); @@ -298,19 +365,19 @@ struct node_alloc_holder (FwdIterator beg, difference_type n, Inserter inserter) { if(n){ - typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; + typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; //Try to allocate memory in a single block - multiallocation_iterator itbeg = - this->node_alloc().allocate_individual(n), itend, itold; + multiallocation_chain mem(this->node_alloc().allocate_individual(n)); int constructed = 0; Node *p = 0; BOOST_TRY{ for(difference_type i = 0; i < n; ++i, ++beg, --constructed){ - p = &*itbeg; - ++itbeg; + p = containers_detail::get_pointer(mem.front()); + mem.pop_front(); //This can throw - boost::interprocess::construct_in_place(p, beg); + constructed = 0; + boost::interprocess_container::construct_in_place(p, beg); ++constructed; //This can throw in some containers (predicate might throw) inserter(*p); @@ -320,7 +387,7 @@ struct node_alloc_holder if(constructed){ this->destroy(p); } - this->node_alloc().deallocate_many(itbeg); + this->node_alloc().deallocate_individual(boost::interprocess::move(mem)); BOOST_RETHROW } BOOST_CATCH_END @@ -334,8 +401,12 @@ struct node_alloc_holder void clear(allocator_v2) { - allocator_multialloc_chain_node_deallocator chain_holder(this->node_alloc()); - this->icont().clear_and_dispose(chain_holder.get_chain_builder()); + typename NodeAlloc::multiallocation_chain chain; + allocator_destroyer_and_chain_builder builder(this->node_alloc(), chain); + this->icont().clear_and_dispose(builder); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + if(!chain.empty()) + this->node_alloc().deallocate_individual(boost::interprocess::move(chain)); } icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v1) @@ -419,10 +490,10 @@ struct node_alloc_holder { return static_cast(this->members_); } }; -} //namespace detail { -} //namespace interprocess { +} //namespace containers_detail { +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif // BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ +#endif // BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ diff --git a/include/boost/interprocess/containers/container/detail/pair.hpp b/include/boost/interprocess/containers/container/detail/pair.hpp new file mode 100644 index 0000000..72f4ab0 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/pair.hpp @@ -0,0 +1,189 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP +#define BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include + +#include //std::pair + +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct pair +{ + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(pair) + + typedef T1 first_type; + typedef T2 second_type; + + T1 first; + T2 second; + + //std::pair compatibility + template + pair(const std::pair& p) + : first(p.first), second(p.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the previous constructor + pair(std::pair& x) + : first(x.first), second(x.second) + {} + + template + pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + pair() + : first(), second() + {} + + pair(const pair& x) + : first(x.first), second(x.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the copy constructor + pair(pair& x) + : first(x.first), second(x.second) + {} + + pair(BOOST_INTERPROCESS_RV_REF(pair) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + template + pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(pair, D, S) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + pair(U &&u, Args &&... args) + : first(boost::interprocess::forward(u)) + , second(boost::interprocess::forward(args)...) + {} + + #else + + template + pair( BOOST_CONTAINERS_PARAM(U, u) + #ifndef BOOST_HAS_RVALUE_REFS + , typename containers_detail::disable_if + < containers_detail::is_same > >::type* = 0 + #endif + ) + : first(boost::interprocess::forward(const_cast(u))) + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + pair(BOOST_CONTAINERS_PARAM(U, u) \ + ,BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : first(boost::interprocess::forward(const_cast(u))) \ + , second(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + #endif + + pair& operator=(BOOST_INTERPROCESS_RV_REF(pair) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, T1, T2) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + template + pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + void swap(pair& p) + { std::swap(*this, p); } +}; + +template +inline bool operator==(const pair& x, const pair& y) +{ return static_cast(x.first == y.first && x.second == y.second); } + +template +inline bool operator< (const pair& x, const pair& y) +{ return static_cast(x.first < y.first || + (!(y.first < x.first) && x.second < y.second)); } + +template +inline bool operator!=(const pair& x, const pair& y) +{ return static_cast(!(x == y)); } + +template +inline bool operator> (const pair& x, const pair& y) +{ return y < x; } + +template +inline bool operator>=(const pair& x, const pair& y) +{ return static_cast(!(x < y)); } + +template +inline bool operator<=(const pair& x, const pair& y) +{ return static_cast(!(y < x)); } + +template +inline pair make_pair(T1 x, T2 y) +{ return pair(x, y); } + +template +inline void swap(pair& x, pair& y) +{ + swap(x.first, y.first); + swap(x.second, y.second); +} + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_PAIR_HPP diff --git a/include/boost/interprocess/containers/container/detail/preprocessor.hpp b/include/boost/interprocess/containers/container/detail/preprocessor.hpp new file mode 100644 index 0000000..ecd143d --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/preprocessor.hpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP +#define BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif + +#include +#include +#include +#include +#include + +#define BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS 10 + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind rvalues with non-const references, we have to be ugly +#ifdef BOOST_HAS_RVALUE_REFS + #define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ + //! +#else + #define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \ + const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ + //! +#endif + +#ifdef BOOST_HAS_RVALUE_REFS + #define BOOST_CONTAINERS_PARAM(U, u) \ + U && u \ + //! +#else + #define BOOST_CONTAINERS_PARAM(U, u) \ + const U & u \ + //! +#endif + +#ifdef BOOST_HAS_RVALUE_REFS +#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ +//! +#else +#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (const_cast(BOOST_PP_CAT(p, n))) \ +//! +#endif + +#define BOOST_CONTAINERS_AUX_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ +//! + +#ifdef BOOST_HAS_RVALUE_REFS +#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ +//! +#else +#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ +//! +#endif + +#define BOOST_CONTAINERS_PP_PARAM_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! + +#define BOOST_CONTAINERS_PP_MEMBER_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! + +#define BOOST_CONTAINERS_PP_MEMBER_IT_FORWARD(z, n, data) \ +BOOST_PP_CAT(*m_p, n) \ +//! + +#include + +#else +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif +#endif //#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP diff --git a/include/boost/interprocess/containers/container/detail/transform_iterator.hpp b/include/boost/interprocess/containers/container/detail/transform_iterator.hpp new file mode 100644 index 0000000..8610dcc --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/transform_iterator.hpp @@ -0,0 +1,176 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename containers_detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + +/* + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } +*/ + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/container/detail/tree.hpp similarity index 80% rename from include/boost/interprocess/containers/detail/tree.hpp rename to include/boost/interprocess/containers/container/detail/tree.hpp index 408ce3d..77e77eb 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/container/detail/tree.hpp @@ -4,7 +4,7 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// // @@ -39,21 +39,25 @@ * purpose. It is provided "as is" without express or implied warranty. * */ -#ifndef BOOST_INTERPROCESS_TREE_HPP -#define BOOST_INTERPROCESS_TREE_HPP +#ifndef BOOST_CONTAINERS_TREE_HPP +#define BOOST_CONTAINERS_TREE_HPP -#include -#include +#include +#include #include -#include -#include +#include #include #include -#include #include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include + +#include +#include +#include +#include +#include +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include #endif #include //std::pair @@ -61,8 +65,8 @@ #include namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { template struct value_compare_impl @@ -91,10 +95,10 @@ struct value_compare_impl template struct rbtree_hook { - typedef typename bi::make_set_base_hook - < bi::void_pointer - , bi::link_mode - , bi::optimize_size + typedef typename containers_detail::bi::make_set_base_hook + < containers_detail::bi::void_pointer + , containers_detail::bi::link_mode + , containers_detail::bi::optimize_size >::type type; }; @@ -107,7 +111,7 @@ struct rbtree_type template struct rbtree_type< std::pair > { - typedef detail::pair type; + typedef pair type; }; template @@ -121,28 +125,32 @@ struct rbtree_node typedef rbtree_node node_type; - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING rbtree_node() : m_data() {} + rbtree_node(const rbtree_node &other) + : m_data(other.m_data) + {} + #define BOOST_PP_LOCAL_MACRO(n) \ template \ - rbtree_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ + rbtree_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ {} \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING template rbtree_node(Args &&...args) - : m_data(detail::forward_impl(args)...) + : m_data(boost::interprocess::forward(args)...) {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING rbtree_node &operator=(const rbtree_node &other) { do_assign(other.m_data); return *this; } @@ -170,7 +178,7 @@ struct rbtree_node } template - void do_assign(const detail::pair &p) + void do_assign(const pair &p) { const_cast(m_data.first) = p.first; m_data.second = p.second; @@ -182,64 +190,58 @@ struct rbtree_node public: template - - static void construct(node_type *ptr - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) - , const Convertible &value) - #else - , Convertible &&value) - #endif - { new(ptr) node_type(detail::forward_impl(value)); } + static void construct(node_type *ptr, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible) + { new(ptr) node_type(boost::interprocess::forward(convertible)); } }; -}//namespace detail { -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) +}//namespace containers_detail { +#if !defined(BOOST_HAS_RVALUE_REFS) template struct has_own_construct_from_it - < boost::interprocess::detail::rbtree_node > + < boost::interprocess_container::containers_detail::rbtree_node > { static const bool value = true; }; #endif -namespace detail { +namespace containers_detail { template struct intrusive_rbtree_type { typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type void_pointer; - typedef typename detail::rbtree_node + typedef typename containers_detail::rbtree_node node_type; typedef node_compare node_compare_type; - typedef typename bi::make_rbtree + typedef typename containers_detail::bi::make_rbtree - ,bi::base_hook::type> - ,bi::constant_time_size - ,bi::size_type + ,containers_detail::bi::compare + ,containers_detail::bi::base_hook::type> + ,containers_detail::bi::constant_time_size + ,containers_detail::bi::size_type >::type container_type; typedef container_type type ; }; -} //namespace detail { +} //namespace containers_detail { -namespace detail { +namespace containers_detail { template class rbtree - : protected detail::node_alloc_holder - >::type > { - typedef typename detail::intrusive_rbtree_type + typedef typename containers_detail::intrusive_rbtree_type >::type Icont; - typedef detail::node_alloc_holder AllocHolder; + typedef containers_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; typedef rbtree < Key, Value, KeyOfValue , KeyCompare, A> ThisType; @@ -248,7 +250,7 @@ class rbtree typedef typename AllocHolder::Node Node; typedef typename Icont::iterator iiterator; typedef typename Icont::const_iterator iconst_iterator; - typedef detail::allocator_destroyer Destroyer; + typedef containers_detail::allocator_destroyer Destroyer; typedef typename AllocHolder::allocator_v1 allocator_v1; typedef typename AllocHolder::allocator_v2 allocator_v2; typedef typename AllocHolder::alloc_version alloc_version; @@ -293,6 +295,8 @@ class rbtree }; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(rbtree) + typedef Key key_type; typedef Value value_type; typedef A allocator_type; @@ -450,15 +454,9 @@ class rbtree (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree(detail::moved_object x) - : AllocHolder(x.get(), x.get().key_comp()) - { this->swap(x.get()); } - #else - rbtree(rbtree &&x) + rbtree(BOOST_INTERPROCESS_RV_REF(rbtree) x) : AllocHolder(x, x.key_comp()) { this->swap(x); } - #endif ~rbtree() {} //AllocHolder clears the tree @@ -488,13 +486,8 @@ class rbtree return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree& operator=(detail::moved_object mx) - { this->clear(); this->swap(mx.get()); return *this; } - #else - rbtree& operator=(rbtree &&mx) + rbtree& operator=(BOOST_INTERPROCESS_RV_REF(rbtree) mx) { this->clear(); this->swap(mx); return *this; } - #endif public: // accessors: @@ -583,14 +576,6 @@ class rbtree void swap(ThisType& x) { AllocHolder::swap(x); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object mt) - { this->swap(mt.get()); } - #else - void swap(rbtree &&mt) - { this->swap(mt); } - #endif - public: typedef typename Icont::insert_commit_data insert_commit_data; @@ -619,25 +604,14 @@ class rbtree return iterator(it); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator insert_unique_commit - (detail::moved_object mv, insert_commit_data &data) + (BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv, insert_commit_data &data) { - NodePtr tmp = AllocHolder::create_node(mv); + NodePtr tmp = AllocHolder::create_node(boost::interprocess::forward(mv)); iiterator it(this->icont().insert_unique_commit(*tmp, data)); return iterator(it); } - #else - template - iterator insert_unique_commit - (MovableConvertible && mv, insert_commit_data &data) - { - NodePtr tmp = AllocHolder::create_node(detail::forward_impl(mv)); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); - } - #endif std::pair insert_unique(const value_type& v) { @@ -650,21 +624,8 @@ class rbtree (this->insert_unique_commit(v, data), true); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - std::pair insert_unique(detail::moved_object mv) - { - insert_commit_data data; - std::pair ret = - this->insert_unique_check(KeyOfValue()(mv.get()), data); - if(!ret.second) - return ret; - return std::pair - (this->insert_unique_commit(mv, data), true); - } - #else - template - std::pair insert_unique(MovableConvertible &&mv) + std::pair insert_unique(BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { insert_commit_data data; std::pair ret = @@ -672,9 +633,8 @@ class rbtree if(!ret.second) return ret; return std::pair - (this->insert_unique_commit(detail::forward_impl(mv), data), true); + (this->insert_unique_commit(boost::interprocess::forward(mv), data), true); } - #endif private: iterator emplace_unique_impl(NodePtr p) @@ -705,31 +665,31 @@ class rbtree public: - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template iterator emplace_unique(Args&&... args) - { return this->emplace_unique_impl(AllocHolder::create_node(detail::forward_impl(args)...)); } + { return this->emplace_unique_impl(AllocHolder::create_node(boost::interprocess::forward(args)...)); } template iterator emplace_hint_unique(const_iterator hint, Args&&... args) - { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(detail::forward_impl(args)...)); } + { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::interprocess::forward(args)...)); } template iterator emplace_equal(Args&&... args) { - NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(args)...)); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(args)...)); return iterator(this->icont().insert_equal(hint.get(), *p)); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator emplace_unique() { return this->emplace_unique_impl(AllocHolder::create_node()); } @@ -751,37 +711,37 @@ class rbtree #define BOOST_PP_LOCAL_MACRO(n) \ template \ - iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ return this->emplace_unique_impl \ - (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ } \ \ template \ - iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ return this->emplace_unique_hint_impl \ - (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ } \ \ template \ - iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ return iterator(this->icont().insert_equal(this->icont().end(), *p)); \ } \ \ template \ - iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ return iterator(this->icont().insert_equal(hint.get(), *p)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator insert_unique(const_iterator hint, const value_type& v) { @@ -793,30 +753,16 @@ class rbtree return this->insert_unique_commit(v, data); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_unique(const_iterator hint, detail::moved_object mv) - { - insert_commit_data data; - std::pair ret = - this->insert_unique_check(hint, KeyOfValue()(mv.get()), data); - if(!ret.second) - return ret.first; - return this->insert_unique_commit(mv, data); - } - #else - template - iterator insert_unique - (const_iterator hint, MovableConvertible &&mv) + iterator insert_unique(const_iterator hint, BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { insert_commit_data data; std::pair ret = this->insert_unique_check(hint, KeyOfValue()(mv), data); if(!ret.second) return ret.first; - return this->insert_unique_commit(detail::forward_impl(mv), data); + return this->insert_unique_commit(boost::interprocess::forward(mv), data); } - #endif template void insert_unique(InputIterator first, InputIterator last) @@ -840,21 +786,12 @@ class rbtree return iterator(this->icont().insert_equal(this->icont().end(), *p)); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(detail::moved_object mv) + iterator insert_equal(BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(mv)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(mv))); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } - #else - template - iterator insert_equal(MovableConvertible &&mv) - { - NodePtr p(AllocHolder::create_node(detail::forward_impl(mv))); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); - } - #endif iterator insert_equal(const_iterator hint, const value_type& v) { @@ -862,21 +799,12 @@ class rbtree return iterator(this->icont().insert_equal(hint.get(), *p)); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(const_iterator hint, detail::moved_object mv) + iterator insert_equal(const_iterator hint, BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(mv)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(mv))); return iterator(this->icont().insert_equal(hint.get(), *p)); } - #else - template - iterator insert_equal(const_iterator hint, MovableConvertible &&mv) - { - NodePtr p(AllocHolder::create_node(detail::move_impl(mv))); - return iterator(this->icont().insert_equal(hint.get(), *p)); - } - #endif template void insert_equal(InputIterator first, InputIterator last) @@ -1066,46 +994,25 @@ swap(rbtree& x, x.swap(y); } -} //namespace detail { +} //namespace containers_detail { +} //namespace interprocess_container { -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -/* -template -struct is_movable > -{ - enum { value = true }; -}; -*/ +namespace interprocess { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class C, class A> +struct has_trivial_destructor_after_move + > { - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; }; +} //namespace interprocess { -} //namespace interprocess { } //namespace boost { -#include +#include -#endif //BOOST_INTERPROCESS_TREE_HPP +#endif //BOOST_CONTAINERS_TREE_HPP diff --git a/include/boost/interprocess/containers/container/detail/type_traits.hpp b/include/boost/interprocess/containers/container/detail/type_traits.hpp new file mode 100644 index 0000000..cb103d9 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/type_traits.hpp @@ -0,0 +1,166 @@ +////////////////////////////////////////////////////////////////////////////// +// (C) Copyright John Maddock 2000. +// (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/container for documentation. +// +// The alignment_of implementation comes from John Maddock's boost::alignment_of code +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP +#define BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +struct nat{}; + +//boost::alignment_of yields to 10K lines of preprocessed code, so we +//need an alternative +template struct alignment_of; + +template +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template +struct alignment_logic +{ + enum{ value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum{ value = alignment_logic + < sizeof(alignment_of_hack) - sizeof(T) + , sizeof(T)>::value }; +}; + +//This is not standard, but should work with all compilers +union max_align +{ + char char_; + short short_; + int int_; + long long_; + #ifdef BOOST_HAS_LONG_LONG + long long long_long_; + #endif + float float_; + double double_; + long double long_double_; + void * void_ptr_; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct is_reference +{ + enum { value = false }; +}; + +template +struct is_reference +{ + enum { value = true }; +}; + +template +struct is_pointer +{ + enum { value = false }; +}; + +template +struct is_pointer +{ + enum { value = true }; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template<> +struct add_reference +{ + typedef nat &type; +}; + +template<> +struct add_reference +{ + typedef const nat &type; +}; + +template +struct add_const_reference +{ typedef const T &type; }; + +template +struct add_const_reference +{ typedef T& type; }; + +template +struct is_same +{ + typedef char yes_type; + struct no_type + { + char padding[8]; + }; + + template + static yes_type is_same_tester(V*, V*); + static no_type is_same_tester(...); + + static T *t; + static U *u; + + static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u)); +}; + +} // namespace containers_detail +} //namespace interprocess_container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP + +#include + diff --git a/include/boost/interprocess/containers/container/detail/utilities.hpp b/include/boost/interprocess/containers/container/detail/utilities.hpp new file mode 100644 index 0000000..5dad0dc --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/utilities.hpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP +#define BOOST_CONTAINERS_DETAIL_UTILITIES_HPP + +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +SizeType + get_next_capacity(const SizeType max_size + ,const SizeType capacity + ,const SizeType n) +{ +// if (n > max_size - capacity) +// throw std::length_error("get_next_capacity"); + + const SizeType m3 = max_size/3; + + if (capacity < m3) + return capacity + max_value(3*(capacity+1)/5, n); + + if (capacity < m3*2) + return capacity + max_value((capacity+1)/2, n); + + return max_size; +} + +template +const T &max_value(const T &a, const T &b) +{ return a > b ? a : b; } + +template +const T &min_value(const T &a, const T &b) +{ return a < b ? a : b; } + +template +struct smart_ptr_type +{ + typedef typename SmartPtr::value_type value_type; + typedef value_type *pointer; + static pointer get (const SmartPtr &smartptr) + { return smartptr.get();} +}; + +template +struct smart_ptr_type +{ + typedef T value_type; + typedef value_type *pointer; + static pointer get (pointer ptr) + { return ptr;} +}; + +//!Overload for smart pointers to avoid ADL problems with get_pointer +template +inline typename smart_ptr_type::pointer +get_pointer(const Ptr &ptr) +{ return smart_ptr_type::get(ptr); } + +//!To avoid ADL problems with swap +template +inline void do_swap(T& x, T& y) +{ + using std::swap; + swap(x, y); +} + +template +struct ct_rounded_size +{ + enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP diff --git a/include/boost/interprocess/containers/container/detail/value_init.hpp b/include/boost/interprocess/containers/container/detail/value_init.hpp new file mode 100644 index 0000000..4918379 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/value_init.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP +#define BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct value_init +{ + value_init() + : m_t() + {} + + T m_t; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP diff --git a/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp b/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp new file mode 100644 index 0000000..ba46e85 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include //std::size_t + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::get(t); } + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/include/boost/interprocess/detail/version_type.hpp b/include/boost/interprocess/containers/container/detail/version_type.hpp similarity index 66% rename from include/boost/interprocess/detail/version_type.hpp rename to include/boost/interprocess/containers/container/detail/version_type.hpp index ed43623..f7075dd 100644 --- a/include/boost/interprocess/detail/version_type.hpp +++ b/include/boost/interprocess/containers/container/detail/version_type.hpp @@ -4,7 +4,7 @@ // 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. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// // @@ -13,22 +13,22 @@ ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP -#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP +#ifndef BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP +#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP -#include -#include +#include +#include namespace boost{ -namespace interprocess{ -namespace detail{ +namespace interprocess_container { +namespace containers_detail { //using namespace boost; template struct version_type - : public detail::integral_constant + : public containers_detail::integral_constant { typedef T type; @@ -38,7 +38,7 @@ struct version_type namespace impl{ template , typename T::version>::value> + bool = containers_detail::is_convertible, typename T::version>::value> struct extract_version { static const unsigned value = 1; @@ -78,12 +78,12 @@ struct version template struct version - : public detail::integral_constant::value> + : public containers_detail::integral_constant::value> { }; -} //namespace detail{ -} //namespace interprocess{ +} //namespace containers_detail { +} //namespace interprocess_container { } //namespace boost{ -#endif //#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP +#endif //#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/detail/workaround.hpp b/include/boost/interprocess/containers/container/detail/workaround.hpp new file mode 100644 index 0000000..60abf6c --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/workaround.hpp @@ -0,0 +1,24 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP +#define BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP + +#include + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) +#define BOOST_CONTAINERS_PERFECT_FORWARDING + +#endif + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP diff --git a/include/boost/interprocess/containers/container/flat_map.hpp b/include/boost/interprocess/containers/container/flat_map.hpp new file mode 100644 index 0000000..b3b9b79 --- /dev/null +++ b/include/boost/interprocess/containers/container/flat_map.hpp @@ -0,0 +1,1390 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_FLAT_MAP_HPP +#define BOOST_CONTAINERS_FLAT_MAP_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +class flat_map; + +template +inline bool operator==(const flat_map& x, + const flat_map& y); + +template +inline bool operator<(const flat_map& x, + const flat_map& y); +/// @endcond + +//! A flat_map is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of values of another +//! type T based on the keys. The flat_map class supports random-access iterators. +//! +//! A flat_map satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. A flat_map also provides +//! most operations described for unique keys. For a +//! flat_map the key_type is Key and the value_type is std::pair +//! (unlike std::map which value_type is std::pair<const Key, T>). +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair >). +//! +//! flat_map is similar to std::map but it's implemented like an ordered vector. +//! This means that inserting a new element into a flat_map invalidates +//! previous iterators and references +//! +//! Erasing an element of a flat_map invalidates iterators and references +//! pointing to elements that come after (their keys are bigger) the erased element. +template +class flat_map +{ + /// @cond + private: + //This is the tree that we should store if pair was movable + typedef containers_detail::flat_tree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + + //This is the real tree stored here. It's based on a movable pair + typedef containers_detail::flat_tree, + containers_detail::select1st >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + + typedef typename impl_tree_t::value_type impl_value_type; + typedef typename impl_tree_t::pointer impl_pointer; + typedef typename impl_tree_t::const_pointer impl_const_pointer; + typedef typename impl_tree_t::reference impl_reference; + typedef typename impl_tree_t::const_reference impl_const_reference; + typedef typename impl_tree_t::value_compare impl_value_compare; + typedef typename impl_tree_t::iterator impl_iterator; + typedef typename impl_tree_t::const_iterator impl_const_iterator; + typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; + typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; + typedef typename impl_tree_t::allocator_type impl_allocator_type; + + template + static D &force(const S &s) + { return *const_cast(reinterpret_cast(&s)); } + + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } + + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_map) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::value_compare value_compare; + typedef T mapped_type; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! Complexity: Constant. + explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) {} + + //! Effects: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) + { m_flat_tree.insert_unique(first, last); } + + //! Effects: Copy constructs a flat_map. + //! + //! Complexity: Linear in x.size(). + flat_map(const flat_map& x) + : m_flat_tree(x.m_flat_tree) {} + + //! Effects: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_map(BOOST_INTERPROCESS_RV_REF(flat_map) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_map& operator=(const flat_map& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_map& operator=(BOOST_INTERPROCESS_RV_REF(flat_map) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return force(m_flat_tree.key_comp()); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(force(m_flat_tree.key_comp())); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return force(m_flat_tree.get_allocator()); } + + const stored_allocator_type &get_stored_allocator() const + { return force(m_flat_tree.get_stored_allocator()); } + + stored_allocator_type &get_stored_allocator() + { return force(m_flat_tree.get_stored_allocator()); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return force_copy(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return force(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return force(m_flat_tree.cbegin()); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return force_copy(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return force(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return force(m_flat_tree.cend()); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return force(m_flat_tree.crbegin()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return force(m_flat_tree.crend()); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: If there is no key equivalent to x in the flat_map, inserts + //! value_type(x, T()) into the flat_map. + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T &operator[](const key_type& k) + { + 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, T())); + return (*i).second; + } + + //! 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) + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T &operator[](BOOST_INTERPROCESS_RV_REF(key_type) mk) + { + key_type &k = mk; + 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(boost::interprocess::move(k), boost::interprocess::move(T()))); + return (*i).second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + T& at(const key_type& k) + { + iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + const T& at(const key_type& k) const + { + const_iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_map& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(const value_type& x) + { return force >( + m_flat_tree.insert_unique(force(x))); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force >( + m_flat_tree.insert_unique(boost::interprocess::move(force(x)))); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force > + (m_flat_tree.insert_unique(boost::interprocess::move(x))); + } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return force_copy( + m_flat_tree.insert_unique(force(position), force(x))); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force_copy( + m_flat_tree.insert_unique(force(position), boost::interprocess::move(force(x)))); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force_copy( + m_flat_tree.insert_unique(force(position), boost::interprocess::move(x))); + } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_unique(boost::interprocess::forward(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), boost::interprocess::forward(args)...)); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_unique()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_unique \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_unique \ + (force(hint), \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return force_copy(m_flat_tree.erase(force(position))); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return force_copy(m_flat_tree.erase(force(first), force(last))); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return force_copy(m_flat_tree.find(x)); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return force(m_flat_tree.find(x)); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return force_copy(m_flat_tree.lower_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return force(m_flat_tree.lower_bound(x)); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return force_copy(m_flat_tree.upper_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return force(m_flat_tree.upper_bound(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return force >(m_flat_tree.equal_range(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return force >(m_flat_tree.equal_range(x)); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_map&, + const flat_map&); + template + friend bool operator< (const flat_map&, + const flat_map&); + /// @endcond +}; + +template +inline bool operator==(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_map& x, + const flat_map& y) + { return !(x == y); } + +template +inline bool operator>(const flat_map& x, + const flat_map& y) + { return y < x; } + +template +inline bool operator<=(const flat_map& x, + const flat_map& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_map& x, + const flat_map& y) + { return !(x < y); } + +template +inline void swap(flat_map& x, + flat_map& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. +template +class flat_multimap; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y); + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y); +/// @endcond + +//! A flat_multimap is a kind of associative container that supports equivalent keys +//! (possibly containing multiple copies of the same key value) and provides for +//! fast retrieval of values of another type T based on the keys. The flat_multimap +//! class supports random-access iterators. +//! +//! A flat_multimap satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! flat_multimap the key_type is Key and the value_type is std::pair +//! (unlike std::multimap which value_type is std::pair<const Key, T>). +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair >). +template +class flat_multimap +{ + /// @cond + private: + typedef containers_detail::flat_tree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + //This is the real tree stored here. It's based on a movable pair + typedef containers_detail::flat_tree, + containers_detail::select1st >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + + typedef typename impl_tree_t::value_type impl_value_type; + typedef typename impl_tree_t::pointer impl_pointer; + typedef typename impl_tree_t::const_pointer impl_const_pointer; + typedef typename impl_tree_t::reference impl_reference; + typedef typename impl_tree_t::const_reference impl_const_reference; + typedef typename impl_tree_t::value_compare impl_value_compare; + typedef typename impl_tree_t::iterator impl_iterator; + typedef typename impl_tree_t::const_iterator impl_const_iterator; + typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; + typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; + typedef typename impl_tree_t::allocator_type impl_allocator_type; + + template + static D &force(const S &s) + { return *const_cast((reinterpret_cast(&s))); } + + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_multimap) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::value_compare value_compare; + typedef T mapped_type; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty flat_multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit flat_multimap(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) { } + + //! Effects: Constructs an empty flat_multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_multimap(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) + { m_flat_tree.insert_equal(first, last); } + + //! Effects: Copy constructs a flat_multimap. + //! + //! Complexity: Linear in x.size(). + flat_multimap(const flat_multimap& x) + : m_flat_tree(x.m_flat_tree) { } + + //! Effects: Move constructs a flat_multimap. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_multimap(BOOST_INTERPROCESS_RV_REF(flat_multimap) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + { } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_multimap& operator=(const flat_multimap& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + flat_multimap& operator=(BOOST_INTERPROCESS_RV_REF(flat_multimap) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return force(m_flat_tree.key_comp()); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(force(m_flat_tree.key_comp())); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return force(m_flat_tree.get_allocator()); } + + const stored_allocator_type &get_stored_allocator() const + { return force(m_flat_tree.get_stored_allocator()); } + + stored_allocator_type &get_stored_allocator() + { return force(m_flat_tree.get_stored_allocator()); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return force_copy(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return force(m_flat_tree.begin()); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return force_copy(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return force(m_flat_tree.end()); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return force(m_flat_tree.rend()); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_multimap& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(x))); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force_copy(m_flat_tree.insert_equal(boost::interprocess::move(x))); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { return force_copy(m_flat_tree.insert_equal(boost::interprocess::move(x))); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { + return force_copy + (m_flat_tree.insert_equal(force(position) + , boost::interprocess::move(x))); + } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force_copy( + m_flat_tree.insert_equal(force(position), boost::interprocess::move(x))); + } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_equal(boost::interprocess::forward(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { + return force_copy(m_flat_tree.emplace_hint_equal + (force(hint), boost::interprocess::forward(args)...)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_equal()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_equal \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_equal \ + (force(hint), \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return force_copy(m_flat_tree.erase(force(position))); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return force_copy(m_flat_tree.erase(force(first), force(last))); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return force_copy(m_flat_tree.find(x)); } + + //! Returns: An const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return force(m_flat_tree.find(x)); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return force_copy(m_flat_tree.lower_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key + //! not less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return force(m_flat_tree.lower_bound(x)); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + {return force_copy(m_flat_tree.upper_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key + //! not less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return force(m_flat_tree.upper_bound(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return force_copy >(m_flat_tree.equal_range(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return force_copy >(m_flat_tree.equal_range(x)); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_multimap& x, + const flat_multimap& y); + + template + friend bool operator< (const flat_multimap& x, + const flat_multimap& y); + /// @endcond +}; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multimap& x, + const flat_multimap& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multimap& x, + const flat_multimap& y) + { return y < x; } + +template +inline bool operator<=(const flat_multimap& x, + const flat_multimap& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multimap& x, + const flat_multimap& y) + { return !(x < y); } + +template +inline void swap(flat_multimap& x, flat_multimap& y) + { x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move< boost::interprocess_container::flat_multimap > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { +} //namespace boost { + +/// @endcond + +#include + +#endif /* BOOST_CONTAINERS_FLAT_MAP_HPP */ diff --git a/include/boost/interprocess/containers/container/flat_set.hpp b/include/boost/interprocess/containers/container/flat_set.hpp new file mode 100644 index 0000000..2c00cb7 --- /dev/null +++ b/include/boost/interprocess/containers/container/flat_set.hpp @@ -0,0 +1,1172 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_FLAT_SET_HPP +#define BOOST_CONTAINERS_FLAT_SET_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators < and ==, needed for friend declaration. + +template +class flat_set; + +template +inline bool operator==(const flat_set& x, + const flat_set& y); + +template +inline bool operator<(const flat_set& x, + const flat_set& y); +/// @endcond + +//! flat_set is a Sorted Associative Container that stores objects of type Key. +//! flat_set is a Simple Associative Container, meaning that its value type, +//! as well as its key type, is Key. It is also a Unique Associative Container, +//! meaning that no two elements are the same. +//! +//! flat_set is similar to std::set but it's implemented like an ordered vector. +//! This means that inserting a new element into a flat_set invalidates +//! previous iterators and references +//! +//! Erasing an element of a flat_set invalidates iterators and references +//! pointing to elements that come after (their keys are bigger) the erased element. +template +class flat_set +{ + /// @cond + private: + typedef containers_detail::flat_tree, Pred, Alloc> tree_t; + tree_t m_flat_tree; // flat tree representing flat_set + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_set) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::value_compare value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! Complexity: Constant. + explicit flat_set(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + {} + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_set(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + { m_flat_tree.insert_unique(first, last); } + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + flat_set(const flat_set& x) + : m_flat_tree(x.m_flat_tree) {} + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_set(BOOST_INTERPROCESS_RV_REF(flat_set) mx) + : m_flat_tree(boost::interprocess::move(mx.m_flat_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_set& operator=(const flat_set& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_set& operator=(BOOST_INTERPROCESS_RV_REF(flat_set) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_flat_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_flat_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_flat_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_set& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(const value_type& x) + { return m_flat_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return m_flat_tree.insert_unique(position, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_flat_tree.emplace_unique(); } + + iterator emplace_hint(const_iterator hint) + { return m_flat_tree.emplace_hint_unique(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return m_flat_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return m_flat_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_flat_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return m_flat_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_flat_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_flat_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_flat_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_flat_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_set&, const flat_set&); + + template + friend bool operator< (const flat_set&, const flat_set&); + /// @endcond +}; + +template +inline bool operator==(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_set& x, + const flat_set& y) + { return !(x == y); } + +template +inline bool operator>(const flat_set& x, + const flat_set& y) + { return y < x; } + +template +inline bool operator<=(const flat_set& x, + const flat_set& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_set& x, + const flat_set& y) + { return !(x < y); } + +template +inline void swap(flat_set& x, flat_set& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value &&has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +class flat_multiset; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y); + +template +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 +{ + /// @cond + private: + typedef containers_detail::flat_tree, Pred, Alloc> tree_t; + tree_t m_flat_tree; // flat tree representing flat_multiset + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_multiset) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef typename tree_t::key_compare key_compare; + typedef typename tree_t::value_compare value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + // allocation/deallocation + explicit flat_multiset(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) {} + + template + flat_multiset(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + { m_flat_tree.insert_equal(first, last); } + + flat_multiset(const flat_multiset& x) + : m_flat_tree(x.m_flat_tree) {} + + flat_multiset(BOOST_INTERPROCESS_RV_REF(flat_multiset) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + {} + + flat_multiset& operator=(const flat_multiset& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + flat_multiset& operator=(BOOST_INTERPROCESS_RV_REF(flat_multiset) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_flat_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_flat_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_flat_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_multiset& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const value_type& x) + { return m_flat_tree.insert_equal(x); } + + //! Effects: Inserts a new value_type move constructed from x + //! and returns the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return m_flat_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_flat_tree.emplace_equal(); } + + iterator emplace_hint(const_iterator hint) + { return m_flat_tree.emplace_hint_equal(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return m_flat_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return m_flat_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_flat_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return m_flat_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_flat_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_flat_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_flat_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_flat_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: If capacity() is less than "count", iterators and references to + //! to values might be invalidated. + void reserve(size_type count) + { m_flat_tree.reserve(count); } + + /// @cond + template + friend bool operator== (const flat_multiset&, + const flat_multiset&); + template + friend bool operator< (const flat_multiset&, + const flat_multiset&); + /// @endcond +}; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multiset& x, + const flat_multiset& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multiset& x, + const flat_multiset& y) + { return y < x; } + +template +inline bool operator<=(const flat_multiset& x, + const flat_multiset& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multiset& x, + const flat_multiset& y) +{ return !(x < y); } + +template +inline void swap(flat_multiset& x, flat_multiset& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_FLAT_SET_HPP */ diff --git a/include/boost/interprocess/containers/container/list.hpp b/include/boost/interprocess/containers/container/list.hpp new file mode 100644 index 0000000..e7d0f89 --- /dev/null +++ b/include/boost/interprocess/containers/container/list.hpp @@ -0,0 +1,1372 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_list.h file. Modified by Ion Gaztanaga 2004 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_LIST_HPP_ +#define BOOST_CONTAINERS_LIST_HPP_ + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +namespace containers_detail { + +template +struct list_hook +{ + typedef typename containers_detail::bi::make_list_base_hook + , containers_detail::bi::link_mode >::type type; +}; + +template +struct list_node + : public list_hook::type +{ + + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + list_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + list_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + list_node(Args &&...args) + : m_data(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + T m_data; +}; + +template +struct intrusive_list_type +{ + typedef typename A::value_type value_type; + typedef typename boost::pointer_to_other + ::type void_pointer; + typedef typename containers_detail::list_node + node_type; + typedef typename containers_detail::bi::make_list + < node_type + , containers_detail::bi::base_hook::type> + , containers_detail::bi::constant_time_size + , containers_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace containers_detail { +/// @endcond + +//! A list is a doubly linked list. That is, it is a Sequence that supports both +//! forward and backward traversal, and (amortized) constant time insertion and +//! removal of elements at the beginning or the end, or in the middle. Lists have +//! the important property that insertion and splicing do not invalidate iterators +//! to list elements, and that even removal invalidates only the iterators that point +//! to the elements that are removed. The ordering of iterators may be changed +//! (that is, list::iterator might have a different predecessor or successor +//! after a list operation than it did before), but the iterators themselves will +//! not be invalidated or made to point to different elements unless that invalidation +//! or mutation is explicit. +template +class list + : protected containers_detail::node_alloc_holder + ::type> +{ + /// @cond + typedef typename + containers_detail::intrusive_list_type::type Icont; + typedef list ThisType; + typedef containers_detail::node_alloc_holder AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef containers_detail::allocator_destroyer Destroyer; + typedef typename AllocHolder::allocator_v1 allocator_v1; + typedef typename AllocHolder::allocator_v2 allocator_v2; + typedef typename AllocHolder::alloc_version alloc_version; + + class equal_to_value + { + typedef typename AllocHolder::value_type value_type; + const value_type &t_; + + public: + equal_to_value(const value_type &t) + : t_(t) + {} + + bool operator()(const value_type &t)const + { return t_ == t; } + }; + + template + struct ValueCompareToNodeCompare + : Pred + { + ValueCompareToNodeCompare(Pred pred) + : Pred(pred) + {} + + bool operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.m_data, b.m_data); } + + bool operator()(const Node &a) const + { return static_cast(*this)(a.m_data); } + }; + /// @endcond + + public: + //! The type of object, T, stored in the list + typedef T value_type; + //! Pointer to T + typedef typename A::pointer pointer; + //! Const pointer to T + typedef typename A::const_pointer const_pointer; + //! Reference to T + typedef typename A::reference reference; + //! Const reference to T + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! The allocator type + typedef A allocator_type; + //! The stored allocator type + typedef NodeAlloc stored_allocator_type; + + /// @cond + private: + typedef difference_type list_difference_type; + typedef pointer list_pointer; + typedef const_pointer list_const_pointer; + typedef reference list_reference; + typedef const_reference list_const_reference; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(list) + + //! Const iterator used to iterate through a list. + class const_iterator + /// @cond + : public std::iterator + { + + protected: + typename Icont::iterator m_it; + explicit const_iterator(typename Icont::iterator it) : m_it(it){} + void prot_incr() { ++m_it; } + void prot_decr() { --m_it; } + + private: + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class list; + typedef list_difference_type difference_type; + + //Constructors + const_iterator() + : m_it() + {} + + //Pointer like operators + const_reference operator*() const + { return m_it->m_data; } + + const_pointer operator->() const + { return const_pointer(&m_it->m_data); } + + //Increment / Decrement + const_iterator& operator++() + { prot_incr(); return *this; } + + const_iterator operator++(int) + { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } + + const_iterator& operator--() + { prot_decr(); return *this; } + + const_iterator operator--(int) + { typename Icont::iterator tmp = m_it; --*this; return const_iterator(tmp); } + + //Comparison operators + bool operator== (const const_iterator& r) const + { return m_it == r.m_it; } + + bool operator!= (const const_iterator& r) const + { return m_it != r.m_it; } + } + /// @endcond + ; + + //! Iterator used to iterate through a list + class iterator + /// @cond + : public const_iterator + { + + private: + explicit iterator(typename Icont::iterator it) + : const_iterator(it) + {} + + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class list; + typedef list_pointer pointer; + typedef list_reference reference; + + //Constructors + iterator(){} + + //Pointer like operators + reference operator*() const { return this->m_it->m_data; } + pointer operator->() const { return pointer(&this->m_it->m_data); } + + //Increment / Decrement + iterator& operator++() + { this->prot_incr(); return *this; } + + iterator operator++(int) + { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } + + iterator& operator--() + { this->prot_decr(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + }; + /// @endcond + + //! Iterator used to iterate backwards through a list. + typedef std::reverse_iterator reverse_iterator; + //! Const iterator used to iterate backwards through a list. + typedef std::reverse_iterator const_reverse_iterator; + + //! Effects: Constructs a list taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit list(const allocator_type &a = A()) + : AllocHolder(a) + {} + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + list(size_type n) + : AllocHolder(A()) + { this->resize(n); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + list(size_type n, const T& value, const A& a = A()) + : AllocHolder(a) + { this->insert(this->cbegin(), n, value); } + + //! Effects: Copy constructs a list. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + list(const list& x) + : AllocHolder(x) + { this->insert(this->cbegin(), x.begin(), x.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + list(BOOST_INTERPROCESS_RV_REF(list) x) + : AllocHolder(boost::interprocess::move((AllocHolder&)x)) + {} + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the list. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + list(InpIt first, InpIt last, const A &a = A()) + : AllocHolder(a) + { this->insert(this->cbegin(), first, last); } + + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~list() + {} //AllocHolder clears the list + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return allocator_type(this->node_alloc()); } + + const stored_allocator_type &get_stored_allocator() const + { return this->node_alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->node_alloc(); } + + //! Effects: Erases all the elements of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the list. + void clear() + { AllocHolder::clear(alloc_version()); } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->icont().begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->icont().end()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->cend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->cbegin()); } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->size(); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->icont().size(); } + + //! Effects: Returns the largest possible size of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return AllocHolder::max_size(); } + + //! Effects: Inserts a copy of t in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const T& x) + { this->insert(this->cbegin(), x); } + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of t to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(BOOST_INTERPROCESS_RV_REF(T) x) + { this->insert(this->cbegin(), boost::interprocess::move(x)); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void push_back (const T& x) + { this->insert(this->cend(), x); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void push_back (BOOST_INTERPROCESS_RV_REF(T) x) + { this->insert(this->cend(), boost::interprocess::move(x)); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->erase(this->cbegin()); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_back() + { const_iterator tmp = this->cend(); this->erase(--tmp); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return *(--this->end()); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return *(--this->end()); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + const_iterator iend = this->cend(); + size_type len = this->size(); + + if(len > new_size){ + size_type to_erase = len - new_size; + while(to_erase--){ + --iend; + } + this->erase(iend, this->cend()); + } + else{ + this->priv_create_and_insert_nodes(iend, new_size - len, x); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + const_iterator iend = this->end(); + size_type len = this->size(); + + if(len > new_size){ + size_type to_erase = len - new_size; + const_iterator ifirst; + if(to_erase < len/2u){ + ifirst = iend; + while(to_erase--){ + --ifirst; + } + } + 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->cend(), new_size - len); + } + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(ThisType& x) + { AllocHolder::swap(x); } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + ThisType& operator=(const ThisType& x) + { + if (this != &x) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + ThisType& operator=(BOOST_INTERPROCESS_RV_REF(ThisType) mx) + { + this->clear(); + this->swap(mx); + return *this; + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void insert(const_iterator p, size_type n, const T& x) + { this->priv_create_and_insert_nodes(p, n, x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + void insert(const_iterator p, InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator p, const T& x) + { + NodePtr tmp = AllocHolder::create_node(x); + return iterator(this->icont().insert(p.get(), *tmp)); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(T) x) + { + NodePtr tmp = AllocHolder::create_node(boost::interprocess::move(x)); + return iterator(this->icont().insert(p.get(), *tmp)); + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_back(Args&&... args) + { + this->emplace(this->cend(), boost::interprocess::forward(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_front(Args&&... args) + { + this->emplace(this->cbegin(), boost::interprocess::forward(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace(const_iterator p, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(boost::interprocess::forward(args)...); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert(p.get(), *node)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //0 args + void emplace_back() + { this->emplace(this->cend()); } + + void emplace_front() + { this->emplace(this->cbegin()); } + + iterator emplace(const_iterator p) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert(p.get(), *node)); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + this->emplace(this->cend(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { this->emplace(this->cbegin(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));} \ + \ + template \ + iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ + new ((void*)containers_detail::get_pointer(d.get())) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + NodePtr node = d.get(); \ + d.release(); \ + return iterator(this->icont().insert(p.get(), *node)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + iterator erase(const_iterator p) + { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last. + iterator erase(const_iterator first, const_iterator last) + { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(iterator p, ThisType& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType &x, const_iterator i) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont(), i.get()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of elements transferred. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont(), first.get(), last.get()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! n == std::distance(first, last) + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + + //! Effects: Removes all the elements that compare equal to value. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void remove(const T& value) + { remove_if(equal_to_value(value)); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void unique() + { this->unique(value_equal()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(BinaryPredicate binary_pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc())); + } + + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(list& x) + { this->merge(x, value_less()); } + + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(list &x, StrictWeakOrdering comp) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().merge(x.icont(), + ValueCompareToNodeCompare(comp)); + } + else{ + throw std::runtime_error("list::merge called with unequal allocators"); + } + } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { this->sort(value_less()); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(StrictWeakOrdering comp) + { + // nothing if the list has length 0 or 1. + if (this->size() < 2) + return; + this->icont().sort(ValueCompareToNodeCompare(comp)); + } + + /// @cond + private: + + //Iterator range version + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end) + { + typedef typename std::iterator_traits::iterator_category ItCat; + priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); + } + + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) + { + for (; beg != end; ++beg){ + this->icont().insert(pos.get(), *this->create_node_from_it(beg)); + } + } + + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) + { //Just forward to the default one + priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag()); + } + + class insertion_functor; + friend class insertion_functor; + + class insertion_functor + { + Icont &icont_; + typename Icont::const_iterator pos_; + + public: + insertion_functor(Icont &icont, typename Icont::const_iterator pos) + : icont_(icont), pos_(pos) + {} + + void operator()(Node &n) + { this->icont_.insert(pos_, n); } + }; + + + template + void priv_create_and_insert_nodes + (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) + { + if(beg != end){ + //Optimized allocation and construction + this->allocate_many_and_construct + (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get())); + } + } + + //Default constructed version + void priv_create_and_insert_nodes(const_iterator pos, size_type n) + { + typedef default_construct_iterator default_iterator; + this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator()); + } + + //Copy constructed version + void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x) + { + typedef constant_iterator cvalue_iterator; + this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); + } + + //Dispatch to detect iterator range or integer overloads + template + void priv_insert_dispatch(const_iterator p, + InputIter first, InputIter last, + containers_detail::false_) + { this->priv_create_and_insert_nodes(p, first, last); } + + template + void priv_insert_dispatch(const_iterator p, Integer n, Integer x, containers_detail::true_) + { this->insert(p, (size_type)n, x); } + + void priv_fill_assign(size_type n, const T& val) + { + iterator i = this->begin(), iend = this->end(); + + for ( ; i != iend && n > 0; ++i, --n) + *i = val; + if (n > 0){ + this->priv_create_and_insert_nodes(this->cend(), n, val); + } + else{ + this->erase(i, cend()); + } + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InputIter first2, InputIter last2, containers_detail::false_) + { + iterator first1 = this->begin(); + iterator last1 = this->end(); + for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) + *first1 = *first2; + if (first2 == last2) + this->erase(first1, last1); + else{ + this->priv_create_and_insert_nodes(last1, first2, last2); + } + } + + //Functors for member algorithm defaults + struct value_less + { + bool operator()(const value_type &a, const value_type &b) const + { return a < b; } + }; + + struct value_equal + { + bool operator()(const value_type &a, const value_type &b) const + { return a == b; } + }; + /// @endcond + +}; + +template +inline bool operator==(const list& x, const list& y) +{ + if(x.size() != y.size()){ + return false; + } + typedef typename list::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; +} + +template +inline bool operator<(const list& x, + const list& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const list& x, const list& y) +{ + return !(x == y); +} + +template +inline bool operator>(const list& x, const list& y) +{ + return y < x; +} + +template +inline bool operator<=(const list& x, const list& y) +{ + return !(y < x); +} + +template +inline bool operator>=(const list& x, const list& y) +{ + return !(x < y); +} + +template +inline void swap(list& x, list& y) +{ + x.swap(y); +} + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif // BOOST_CONTAINERS_LIST_HPP_ diff --git a/include/boost/interprocess/containers/container/map.hpp b/include/boost/interprocess/containers/container/map.hpp new file mode 100644 index 0000000..c0033c7 --- /dev/null +++ b/include/boost/interprocess/containers/container/map.hpp @@ -0,0 +1,1266 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_MAP_HPP +#define BOOST_CONTAINERS_MAP_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 + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +inline bool operator==(const map& x, + const map& y); + +template +inline bool operator<(const map& x, + const map& y); +/// @endcond + +//! A map is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of values of another +//! type T based on the keys. The map class supports bidirectional iterators. +//! +//! A map satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! map the key_type is Key and the value_type is std::pair. +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair > ). +template +class map +{ + /// @cond + private: + typedef containers_detail::rbtree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(map) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef T mapped_type; + typedef Pred key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + typedef std::pair nonconst_value_type; + typedef containers_detail::pair + nonconst_impl_value_type; + + /// @cond + class value_compare_impl + : public Pred, + public std::binary_function + { + friend class map; + protected : + value_compare_impl(const Pred &c) : Pred(c) {} + public: + bool operator()(const value_type& x, const value_type& y) const { + return Pred::operator()(x.first, y.first); + } + }; + /// @endcond + typedef value_compare_impl value_compare; + + //! Effects: Constructs an empty map using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit map(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + map(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, true) + {} + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + map(const map& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + map(BOOST_INTERPROCESS_RV_REF(map) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + map& operator=(const map& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + map& operator=(BOOST_INTERPROCESS_RV_REF(map) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(x, T()) into the map. + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T& operator[](const key_type& k) + { + //we can optimize this + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + containers_detail::value_init v; + value_type val(k, boost::interprocess::move(v.m_t)); + i = insert(i, boost::interprocess::move(val)); + } + return (*i).second; + } + + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(boost::interprocess::move(x), T()) into the map (the key is move-constructed) + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + T& operator[](BOOST_INTERPROCESS_RV_REF(key_type) mk) + { + key_type &k = mk; + //we can optimize this + 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(boost::interprocess::move(k), boost::interprocess::move(T())); + i = insert(i, boost::interprocess::move(val)); + } + return (*i).second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + T& at(const key_type& k) + { + iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! Throws: An exception object of type out_of_range if no such element is present. + //! Complexity: logarithmic. + const T& at(const key_type& k) const + { + const_iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(map& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type created from the pair if and only if + //! there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(const nonconst_value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(iterator position, const nonconst_value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with an equivalent key. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with an equivalent key. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_unique(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_unique(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));}\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const map&, + const map&); + template + friend bool operator< (const map&, + const map&); + /// @endcond +}; + +template +inline bool operator==(const map& x, + const map& y) + { return x.m_tree == y.m_tree; } + +template +inline bool operator<(const map& x, + const map& y) + { return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const map& x, + const map& y) + { return !(x == y); } + +template +inline bool operator>(const map& x, + const map& y) + { return y < x; } + +template +inline bool operator<=(const map& x, + const map& y) + { return !(y < x); } + +template +inline bool operator>=(const map& x, + const map& y) + { return !(x < y); } + +template +inline void swap(map& x, map& y) + { x.swap(y); } + +/// @cond + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multimap& x, + const multimap& y); + +template +inline bool operator<(const multimap& x, + const multimap& y); + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +//! A multimap is a kind of associative container that supports equivalent keys +//! (possibly containing multiple copies of the same key value) and provides for +//! fast retrieval of values of another type T based on the keys. The multimap class +//! supports bidirectional iterators. +//! +//! A multimap satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! map the key_type is Key and the value_type is std::pair. +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//!(e.g. allocator< std::pair<const Key, T> >). +template +class multimap +{ + /// @cond + private: + typedef containers_detail::rbtree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(multimap) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef T mapped_type; + typedef Pred key_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + typedef std::pair nonconst_value_type; + typedef containers_detail::pair + nonconst_impl_value_type; + + /// @cond + class value_compare_impl + : public Pred, + public std::binary_function + { + friend class multimap; + protected : + value_compare_impl(const Pred &c) : Pred(c) {} + public: + bool operator()(const value_type& x, const value_type& y) const { + return Pred::operator()(x.first, y.first); + } + }; + /// @endcond + typedef value_compare_impl value_compare; + + //! Effects: Constructs an empty multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multimap(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multimap(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, false) + {} + + //! Effects: Copy constructs a multimap. + //! + //! Complexity: Linear in x.size(). + multimap(const multimap& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a multimap. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + multimap(BOOST_INTERPROCESS_RV_REF(multimap) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multimap& operator=(const multimap& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multimap& operator=(BOOST_INTERPROCESS_RV_REF(multimap) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multimap& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const nonconst_value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const nonconst_value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_equal(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_equal(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multimap& x, + const multimap& y); + + template + friend bool operator< (const multimap& x, + const multimap& y); + /// @endcond +}; + +template +inline bool operator==(const multimap& x, + const multimap& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multimap& x, + const multimap& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multimap& x, + const multimap& y) +{ return !(x == y); } + +template +inline bool operator>(const multimap& x, + const multimap& y) +{ return y < x; } + +template +inline bool operator<=(const multimap& x, + const multimap& y) +{ return !(y < x); } + +template +inline bool operator>=(const multimap& x, + const multimap& y) +{ return !(x < y); } + +template +inline void swap(multimap& x, multimap& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_MAP_HPP */ + diff --git a/include/boost/interprocess/containers/container/set.hpp b/include/boost/interprocess/containers/container/set.hpp new file mode 100644 index 0000000..bf5234a --- /dev/null +++ b/include/boost/interprocess/containers/container/set.hpp @@ -0,0 +1,1112 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztanaga 2004. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_SET_HPP +#define BOOST_CONTAINERS_SET_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators < and ==, needed for friend declaration. +template +inline bool operator==(const set& x, + const set& y); + +template +inline bool operator<(const set& x, + const set& y); +/// @endcond + +//! A set is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of the keys themselves. +//! Class set supports bidirectional iterators. +//! +//! A set satisfies all of the requirements of a container and of a reversible container +//! , and of an associative container. A set also provides most operations described in +//! for unique keys. +template +class set +{ + /// @cond + private: + typedef containers_detail::rbtree, Pred, Alloc> tree_t; + tree_t m_tree; // red-black tree representing set + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(set) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef Pred key_compare; + typedef Pred value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty set using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit set(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty set using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + set(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, true) + {} + + //! Effects: Copy constructs a set. + //! + //! Complexity: Linear in x.size(). + set(const set& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a set. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + set(BOOST_INTERPROCESS_RV_REF(set) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + set& operator=(const set& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + set& operator=(BOOST_INTERPROCESS_RV_REF(set) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(set& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! + //! Returns: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, const value_type& x) + { return m_tree.insert_unique(p, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(p, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is + //! no element in the container with equivalent value. + //! and returns the iterator pointing to the + //! newly inserted element. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is + //! no element in the container with equivalent value. + //! p is a hint pointing to where the insert + //! should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_unique(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_unique(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));}\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by p. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator p) + { return m_tree.erase(p); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const set&, const set&); + + template + friend bool operator< (const set&, const set&); + /// @endcond +}; + +template +inline bool operator==(const set& x, + const set& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const set& x, + const set& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const set& x, + const set& y) +{ return !(x == y); } + +template +inline bool operator>(const set& x, + const set& y) +{ return y < x; } + +template +inline bool operator<=(const set& x, + const set& y) +{ return !(y < x); } + +template +inline bool operator>=(const set& x, + const set& y) +{ return !(x < y); } + +template +inline void swap(set& x, set& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multiset& x, + const multiset& y); + +template +inline bool operator<(const multiset& x, + const multiset& y); +/// @endcond + +//! A multiset is a kind of associative container that supports equivalent keys +//! (possibly contains multiple copies of the same key value) and provides for +//! fast retrieval of the keys themselves. Class multiset supports bidirectional iterators. +//! +//! A multiset satisfies all of the requirements of a container and of a reversible +//! container, and of an associative container). multiset also provides most operations +//! described for duplicate keys. +template +class multiset +{ + /// @cond + private: + typedef containers_detail::rbtree, Pred, Alloc> tree_t; + tree_t m_tree; // red-black tree representing multiset + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(multiset) + + // typedefs: + typedef typename tree_t::key_type key_type; + typedef typename tree_t::value_type value_type; + typedef typename tree_t::pointer pointer; + typedef typename tree_t::const_pointer const_pointer; + typedef typename tree_t::reference reference; + typedef typename tree_t::const_reference const_reference; + typedef Pred key_compare; + typedef Pred value_compare; + typedef typename tree_t::iterator iterator; + typedef typename tree_t::const_iterator const_iterator; + typedef typename tree_t::reverse_iterator reverse_iterator; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator; + typedef typename tree_t::size_type size_type; + typedef typename tree_t::difference_type difference_type; + typedef typename tree_t::allocator_type allocator_type; + typedef typename tree_t::stored_allocator_type stored_allocator_type; + + //! Effects: Constructs an empty multiset using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multiset(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty multiset using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multiset(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, false) + {} + + //! Effects: Copy constructs a multiset. + //! + //! Complexity: Linear in x.size(). + multiset(const multiset& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a multiset. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + multiset(BOOST_INTERPROCESS_RV_REF(multiset) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multiset& operator=(const multiset& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multiset& operator=(BOOST_INTERPROCESS_RV_REF(multiset) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return m_tree.get_allocator(); } + + const stored_allocator_type &get_stored_allocator() const + { return m_tree.get_stored_allocator(); } + + stored_allocator_type &get_stored_allocator() + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multiset& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a copy of x in the container. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, const value_type& x) + { return m_tree.insert_equal(p, x); } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_equal(p, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return m_tree.emplace_equal(); } + + iterator emplace_hint(const_iterator hint) + { return m_tree.emplace_hint_equal(hint); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by p. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator p) + { return m_tree.erase(p); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) + { return m_tree.erase(first, last); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multiset&, + const multiset&); + template + friend bool operator< (const multiset&, + const multiset&); + /// @endcond +}; + +template +inline bool operator==(const multiset& x, + const multiset& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multiset& x, + const multiset& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multiset& x, + const multiset& y) +{ return !(x == y); } + +template +inline bool operator>(const multiset& x, + const multiset& y) +{ return y < x; } + +template +inline bool operator<=(const multiset& x, + const multiset& y) +{ return !(y < x); } + +template +inline bool operator>=(const multiset& x, + const multiset& y) +{ return !(x < y); } + +template +inline void swap(multiset& x, multiset& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_SET_HPP */ + diff --git a/include/boost/interprocess/containers/container/slist.hpp b/include/boost/interprocess/containers/container/slist.hpp new file mode 100644 index 0000000..6e60ae1 --- /dev/null +++ b/include/boost/interprocess/containers/container/slist.hpp @@ -0,0 +1,1524 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_slist.h file. Modified by Ion Gaztanaga 2004-2008 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef BOOST_CONTAINERS_SLIST_HPP +#define BOOST_CONTAINERS_SLIST_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace containers_detail { + +template +struct slist_hook +{ + typedef typename containers_detail::bi::make_slist_base_hook + , containers_detail::bi::link_mode >::type type; +}; + +template +struct slist_node + : public slist_hook::type +{ + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + slist_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + slist_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + slist_node(Args &&...args) + : m_data(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + T m_data; +}; + +template +struct intrusive_slist_type +{ + typedef typename A::value_type value_type; + typedef typename boost::pointer_to_other + ::type void_pointer; + typedef typename containers_detail::slist_node + node_type; + + typedef typename containers_detail::bi::make_slist + ::type> + ,containers_detail::bi::constant_time_size + ,containers_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace containers_detail { + +/// @endcond + +//! An slist is a singly linked list: a list where each element is linked to the next +//! element, but not to the previous element. That is, it is a Sequence that +//! supports forward but not backward traversal, and (amortized) constant time +//! insertion and removal of elements. Slists, like lists, have the important +//! property that insertion and splicing do not invalidate iterators to list elements, +//! and that even removal invalidates only the iterators that point to the elements +//! that are removed. The ordering of iterators may be changed (that is, +//! slist::iterator might have a different predecessor or successor after a list +//! operation than it did before), but the iterators themselves will not be invalidated +//! or made to point to different elements unless that invalidation or mutation is explicit. +//! +//! The main difference between slist and list is that list's iterators are bidirectional +//! iterators, while slist's iterators are forward iterators. This means that slist is +//! less versatile than list; frequently, however, bidirectional iterators are +//! unnecessary. You should usually use slist unless you actually need the extra +//! functionality of list, because singly linked lists are smaller and faster than double +//! linked lists. +//! +//! Important performance note: like every other Sequence, slist defines the member +//! functions insert and erase. Using these member functions carelessly, however, can +//! result in disastrously slow programs. The problem is that insert's first argument is +//! an iterator p, and that it inserts the new element(s) before p. This means that +//! insert must find the iterator just before p; this is a constant-time operation +//! for list, since list has bidirectional iterators, but for slist it must find that +//! iterator by traversing the list from the beginning up to p. In other words: +//! insert and erase are slow operations anywhere but near the beginning of the slist. +//! +//! Slist provides the member functions insert_after and erase_after, which are constant +//! time operations: you should always use insert_after and erase_after whenever +//! possible. If you find that insert_after and erase_after aren't adequate for your +//! needs, and that you often need to use insert and erase in the middle of the list, +//! then you should probably use list instead of slist. +template +class slist + : protected containers_detail::node_alloc_holder + ::type> +{ + /// @cond + typedef typename + containers_detail::intrusive_slist_type::type Icont; + typedef containers_detail::node_alloc_holder AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef slist ThisType; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef containers_detail::allocator_destroyer Destroyer; + typedef typename AllocHolder::allocator_v1 allocator_v1; + typedef typename AllocHolder::allocator_v2 allocator_v2; + typedef typename AllocHolder::alloc_version alloc_version; + + class equal_to_value + { + typedef typename AllocHolder::value_type value_type; + const value_type &t_; + + public: + equal_to_value(const value_type &t) + : t_(t) + {} + + bool operator()(const value_type &t)const + { return t_ == t; } + }; + + template + struct ValueCompareToNodeCompare + : Pred + { + ValueCompareToNodeCompare(Pred pred) + : Pred(pred) + {} + + bool operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.m_data, b.m_data); } + + bool operator()(const Node &a) const + { return static_cast(*this)(a.m_data); } + }; + /// @endcond + public: + //! The type of object, T, stored in the list + typedef T value_type; + //! Pointer to T + typedef typename A::pointer pointer; + //! Const pointer to T + typedef typename A::const_pointer const_pointer; + //! Reference to T + typedef typename A::reference reference; + //! Const reference to T + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! The allocator type + typedef A allocator_type; + //! The stored allocator type + typedef NodeAlloc stored_allocator_type; + + /// @cond + private: + typedef difference_type list_difference_type; + typedef pointer list_pointer; + typedef const_pointer list_const_pointer; + typedef reference list_reference; + typedef const_reference list_const_reference; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(slist) + + //! Const iterator used to iterate through a list. + class const_iterator + /// @cond + : public std::iterator + { + + protected: + typename Icont::iterator m_it; + explicit const_iterator(typename Icont::iterator it) : m_it(it){} + void prot_incr(){ ++m_it; } + + private: + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class slist; + typedef list_difference_type difference_type; + + //Constructors + const_iterator() + : m_it() + {} + + //Pointer like operators + const_reference operator*() const + { return m_it->m_data; } + + const_pointer operator->() const + { return const_pointer(&m_it->m_data); } + + //Increment / Decrement + const_iterator& operator++() + { prot_incr(); return *this; } + + const_iterator operator++(int) + { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } + + //Comparison operators + bool operator== (const const_iterator& r) const + { return m_it == r.m_it; } + + bool operator!= (const const_iterator& r) const + { return m_it != r.m_it; } + } + /// @endcond + ; + + //! Iterator used to iterate through a list + class iterator + /// @cond + : public const_iterator + { + + private: + explicit iterator(typename Icont::iterator it) + : const_iterator(it) + {} + + typename Icont::iterator get() + { return this->m_it; } + + public: + friend class slist; + typedef list_pointer pointer; + typedef list_reference reference; + + //Constructors + iterator(){} + + //Pointer like operators + reference operator*() const { return this->m_it->m_data; } + pointer operator->() const { return pointer(&this->m_it->m_data); } + + //Increment / Decrement + iterator& operator++() + { this->prot_incr(); return *this; } + + iterator operator++(int) + { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } + } + /// @endcond + ; + + public: + //! Effects: Constructs a list taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit slist(const allocator_type& a = allocator_type()) + : AllocHolder(a) + {} + + explicit slist(size_type n) + : AllocHolder(allocator_type()) + { this->resize(n); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + explicit slist(size_type n, const value_type& x, const allocator_type& a = allocator_type()) + : AllocHolder(a) + { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the list. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + slist(InpIt first, InpIt last, + const allocator_type& a = allocator_type()) + : AllocHolder(a) + { this->insert_after(this->before_begin(), first, last); } + + //! Effects: Copy constructs a list. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + slist(const slist& x) + : AllocHolder(x) + { this->insert_after(this->before_begin(), x.begin(), x.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + slist(BOOST_INTERPROCESS_RV_REF(slist) x) + : AllocHolder(boost::interprocess::move((AllocHolder&)x)) + {} + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + slist& operator= (const slist& x) + { + if (&x != this){ + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + slist& operator= (BOOST_INTERPROCESS_RV_REF(slist) mx) + { + if (&mx != this){ + this->clear(); + this->swap(mx); + } + return *this; + } + + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~slist() + {} //AllocHolder clears the slist + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return allocator_type(this->node_alloc()); } + + const stored_allocator_type &get_stored_allocator() const + { return this->node_alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->node_alloc(); } + + public: + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + //! Effects: Assigns the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->icont().begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->icont().end()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a non-dereferenceable iterator that, + //! when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator before_begin() + { return iterator(end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator before_begin() const + { return this->cbefore_begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbefore_begin() const + { return const_iterator(end()); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->icont().size(); } + + //! Effects: Returns the largest possible size of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return AllocHolder::max_size(); } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements on *this and x. + void swap(slist& x) + { AllocHolder::swap(x); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->begin(); } + + //! Effects: Inserts a copy of t in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const value_type& x) + { this->icont().push_front(*this->create_node(x)); } + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of t to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(BOOST_INTERPROCESS_RV_REF(T) x) + { this->icont().push_front(*this->create_node(boost::interprocess::move(x))); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } + + //! Returns: The iterator to the element before i in the sequence. + //! Returns the end-iterator, if either i is the begin-iterator or the + //! sequence is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + iterator previous(iterator p) + { return iterator(this->icont().previous(p.get())); } + + //! Returns: The const_iterator to the element before i in the sequence. + //! Returns the end-const_iterator, if either i is the begin-const_iterator or + //! the sequence is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + const_iterator previous(const_iterator p) + { return const_iterator(this->icont().previous(p.get())); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts a copy of the value after the p pointed + //! by prev_p. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, const value_type& x) + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts a move constructed copy object from the value after the + //! p pointed by prev_pos. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(boost::interprocess::move(x)))); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x after prev_pos. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + void insert_after(const_iterator prev_pos, size_type n, const value_type& x) + { this->priv_create_and_insert_nodes(prev_pos, n, x); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts the range pointed by [first, last) + //! after the p prev_pos. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + template + void insert_after(const_iterator prev_pos, InIter first, InIter last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator p, const value_type& x) + { return this->insert_after(previous(p), x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return this->insert_after(previous(p), boost::interprocess::move(x)); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n plus linear to the elements before p. + void insert(const_iterator p, size_type n, const value_type& x) + { return this->insert_after(previous(p), n, x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last) plus + //! linear to the elements before p. + template + void insert(const_iterator p, InIter first, InIter last) + { return this->insert_after(previous(p), first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the front of the list + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_front(Args&&... args) + { this->emplace_after(this->cbefore_begin(), boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Linear to the elements before p + template + iterator emplace(const_iterator p, Args&&... args) + { return this->emplace_after(this->previous(p), boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... after prev + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace_after(const_iterator prev, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(boost::interprocess::forward(args)...); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert_after(prev.get(), *node)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //0 args + void emplace_front() + { this->emplace_after(this->cbefore_begin()); } + + iterator emplace(const_iterator p) + { return this->emplace_after(this->previous(p)); } + + iterator emplace_after(const_iterator prev) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert_after(prev.get(), *node)); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + this->emplace \ + (this->cbegin(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + iterator emplace \ + (const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return this->emplace_after \ + (this->previous(p), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + iterator emplace_after \ + (const_iterator prev, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ + new ((void*)containers_detail::get_pointer(d.get())) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + NodePtr node = d.get(); \ + d.release(); \ + return iterator(this->icont().insert_after(prev.get(), *node)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element after the element pointed by prev_pos + //! of the list. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not invalidate iterators or references to non erased elements. + iterator erase_after(const_iterator prev_pos) + { + return iterator(this->icont().erase_after_and_dispose(prev_pos.get(), Destroyer(this->node_alloc()))); + } + + //! Effects: Erases the range (before_first, last) from + //! the list. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of erased elements. + //! + //! Note: Does not invalidate iterators or references to non erased elements. + iterator erase_after(const_iterator before_first, const_iterator last) + { + return iterator(this->icont().erase_after_and_dispose(before_first.get(), last.get(), Destroyer(this->node_alloc()))); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before p. + iterator erase(const_iterator p) + { return iterator(this->erase_after(previous(p))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last plus + //! linear to the elements before first. + iterator erase(const_iterator first, const_iterator last) + { return iterator(this->erase_after(previous(first), last)); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; + while (++(cur_next = cur) != end_n && new_size > 0){ + --new_size; + cur = cur_next; + } + if (cur_next != end_n) + this->erase_after(const_iterator(cur), const_iterator(end_n)); + else + this->insert_after(const_iterator(cur), new_size, x); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; + size_type len = this->size(); + size_type left = new_size; + + while (++(cur_next = cur) != end_n && left > 0){ + --left; + cur = cur_next; + } + if (cur_next != end_n){ + this->erase_after(const_iterator(cur), const_iterator(end_n)); + } + else{ + this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); + } + } + + //! Effects: Erases all the elements of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the list. + void clear() + { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, after the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the elements in x. + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after(prev_pos.get(), x.icont()); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! after the element pointed by prev_pos. + //! If prev_pos == prev or prev_pos == ++prev, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! before_first and before_last must be valid iterators of x. + //! prev_pos must not be contained in [before_first, before_last) range. + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of transferred elements. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after + (prev_pos.get(), x.icont(), before_first.get(), before_last.get()); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! before_first and before_last must be valid iterators of x. + //! prev_pos must not be contained in [before_first, before_last) range. + //! n == std::distance(before_first, before_last) + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last, + size_type n) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice_after + (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n); + } + else{ + throw std::runtime_error("slist::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and linear in x.size(). + //! + //! Note: Iterators of values obtained from list x now point to elements of + //! this list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, ThisType& x) + { this->splice_after(this->previous(p), x); } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: Transfers the value pointed by i, from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! If p == i or p == ++i, this function is a null operation. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x, const_iterator i) + { this->splice_after(previous(p), x, i); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: Transfers the range pointed by first and last from list x to this list, + //! before the the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), + //! and in distance(first, last). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) + { this->splice_after(previous(p), x, previous(first), previous(last)); } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + + //! Effects: Removes all the elements that compare equal to value. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void remove(const T& value) + { remove_if(equal_to_value(value)); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void unique() + { this->unique(value_equal()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(slist & x) + { this->merge(x, value_less()); } + + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(slist& x, StrictWeakOrdering comp) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().merge(x.icont(), + ValueCompareToNodeCompare(comp)); + } + else{ + throw std::runtime_error("list::merge called with unequal allocators"); + } + } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { this->sort(value_less()); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(StrictWeakOrdering comp) + { + // nothing if the slist has length 0 or 1. + if (this->size() < 2) + return; + this->icont().sort(ValueCompareToNodeCompare(comp)); + } + + /// @cond + private: + + //Iterator range version + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end) + { + typedef typename std::iterator_traits::iterator_category ItCat; + priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); + } + + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) + { + for (; beg != end; ++beg){ + this->icont().insert_after(prev.get(), *this->create_node_from_it(beg)); + ++prev; + } + } + + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) + { //Just forward to the default one + priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag()); + } + + class insertion_functor; + friend class insertion_functor; + + class insertion_functor + { + Icont &icont_; + typename Icont::const_iterator prev_; + + public: + insertion_functor(Icont &icont, typename Icont::const_iterator prev) + : icont_(icont), prev_(prev) + {} + + void operator()(Node &n) + { prev_ = this->icont_.insert_after(prev_, n); } + }; + + template + void priv_create_and_insert_nodes + (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) + { + //Optimized allocation and construction + this->allocate_many_and_construct + (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get())); + } + + //Default constructed version + void priv_create_and_insert_nodes(const_iterator prev, size_type n) + { + typedef default_construct_iterator default_iterator; + this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator()); + } + + //Copy constructed version + void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x) + { + typedef constant_iterator cvalue_iterator; + this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); + } + + //Dispatch to detect iterator range or integer overloads + template + void priv_insert_dispatch(const_iterator prev, + InputIter first, InputIter last, + containers_detail::false_) + { this->priv_create_and_insert_nodes(prev, first, last); } + + template + void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, containers_detail::true_) + { this->priv_create_and_insert_nodes(prev, n, x); } + + void priv_fill_assign(size_type n, const T& val) + { + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); + for ( ; node != end_n && n > 0 ; --n){ + *node = val; + prev = node; + ++node; + } + if (n > 0) + this->priv_create_and_insert_nodes(prev, n, val); + else + this->erase_after(prev, end_n); + } + + template + void priv_assign_dispatch(Int n, Int val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T)val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); + while (node != end_n && first != last){ + *node = *first; + prev = node; + ++node; + ++first; + } + if (first != last) + this->priv_create_and_insert_nodes(prev, first, last); + else + this->erase_after(prev, end_n); + } + + template + void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, containers_detail::true_) + { this->priv_create_and_insert_nodes(prev_pos, n, x); } + + template + void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, containers_detail::false_) + { this->priv_create_and_insert_nodes(prev_pos, first, last); } + + //Functors for member algorithm defaults + struct value_less + { + bool operator()(const value_type &a, const value_type &b) const + { return a < b; } + }; + + struct value_equal + { + bool operator()(const value_type &a, const value_type &b) const + { return a == b; } + }; + + struct value_equal_to_this + { + explicit value_equal_to_this(const value_type &ref) + : m_ref(ref){} + + bool operator()(const value_type &val) const + { return m_ref == val; } + + const value_type &m_ref; + }; + /// @endcond +}; + +template +inline bool +operator==(const slist& x, const slist& y) +{ + if(x.size() != y.size()){ + return false; + } + typedef typename slist::const_iterator const_iterator; + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + while (i1 != end1 && *i1 == *i2){ + ++i1; + ++i2; + } + return i1 == end1; +} + +template +inline bool +operator<(const slist& sL1, const slist& sL2) +{ + return std::lexicographical_compare + (sL1.begin(), sL1.end(), sL2.begin(), sL2.end()); +} + +template +inline bool +operator!=(const slist& sL1, const slist& sL2) + { return !(sL1 == sL2); } + +template +inline bool +operator>(const slist& sL1, const slist& sL2) + { return sL2 < sL1; } + +template +inline bool +operator<=(const slist& sL1, const slist& sL2) + { return !(sL2 < sL1); } + +template +inline bool +operator>=(const slist& sL1, const slist& sL2) + { return !(sL1 < sL2); } + +template +inline void swap(slist& x, slist& y) + { x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} //namespace boost{ namespace interprocess_container { + +// Specialization of insert_iterator so that insertions will be constant +// time rather than linear time. + +///@cond + +//Ummm, I don't like to define things in namespace std, but +//there is no other way +namespace std { + +template +class insert_iterator > +{ + protected: + typedef boost::interprocess_container::slist Container; + Container* container; + typename Container::iterator iter; + public: + typedef Container container_type; + typedef output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + insert_iterator(Container& x, + typename Container::iterator i, + bool is_previous = false) + : container(&x), iter(is_previous ? i : x.previous(i)){ } + + insert_iterator& + operator=(const typename Container::value_type& value) + { + iter = container->insert_after(iter, value); + return *this; + } + insert_iterator& operator*(){ return *this; } + insert_iterator& operator++(){ return *this; } + insert_iterator& operator++(int){ return *this; } +}; + +} //namespace std; + +///@endcond + +#include + +#endif /* BOOST_CONTAINERS_SLIST_HPP */ diff --git a/include/boost/interprocess/containers/container/stable_vector.hpp b/include/boost/interprocess/containers/container/stable_vector.hpp new file mode 100644 index 0000000..3182dcd --- /dev/null +++ b/include/boost/interprocess/containers/container/stable_vector.hpp @@ -0,0 +1,1351 @@ +/* Stable vector. + * + * Copyright 2008 Joaquin M Lopez Munoz. + * 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) + */ + +#ifndef STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66 +#define STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STABLE_VECTOR_USE_CONTAINERS_VECTOR + +#if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR) +#include +#else +#include +#endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR + +//#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING + +#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) +#include +#endif + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace stable_vector_detail{ + +template +struct smart_ptr_type +{ + typedef typename SmartPtr::value_type value_type; + typedef value_type *pointer; + static pointer get (const SmartPtr &smartptr) + { return smartptr.get();} +}; + +template +struct smart_ptr_type +{ + typedef T value_type; + typedef value_type *pointer; + static pointer get (pointer ptr) + { return ptr;} +}; + +template +inline typename smart_ptr_type::pointer get_pointer(const Ptr &ptr) +{ return smart_ptr_type::get(ptr); } + +template +class clear_on_destroy +{ + public: + clear_on_destroy(C &c) + : c_(c), do_clear_(true) + {} + + void release() + { do_clear_ = false; } + + ~clear_on_destroy() + { + if(do_clear_){ + c_.clear(); + c_.clear_pool(); + } + } + + private: + C &c_; + bool do_clear_; +}; + +template +class constant_iterator + : public std::iterator + +{ + typedef constant_iterator this_type; + + public: + explicit constant_iterator(const T &ref, Difference range_size) + : m_ptr(&ref), m_num(range_size){} + + //Constructors + constant_iterator() + : m_ptr(0), m_num(0){} + + constant_iterator& operator++() + { increment(); return *this; } + + constant_iterator operator++(int) + { + constant_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const constant_iterator& i, const constant_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const constant_iterator& i, const constant_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const constant_iterator& i, const constant_iterator& i2) + { return i.less(i2); } + + friend bool operator> (const constant_iterator& i, const constant_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const constant_iterator& i, const constant_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const constant_iterator& i, const constant_iterator& i2) + { return !(i < i2); } + + friend Difference operator- (const constant_iterator& i, const constant_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + constant_iterator& operator+=(Difference off) + { this->advance(off); return *this; } + + constant_iterator operator+(Difference off) const + { + constant_iterator other(*this); + other.advance(off); + return other; + } + + friend constant_iterator operator+(Difference off, const constant_iterator& right) + { return right + off; } + + constant_iterator& operator-=(Difference off) + { this->advance(-off); return *this; } + + constant_iterator operator-(Difference off) const + { return *this + (-off); } + + const T& operator*() const + { return dereference(); } + + const T* operator->() const + { return &(dereference()); } + + private: + const T * m_ptr; + Difference m_num; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + const T & dereference() const + { return *m_ptr; } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + +template +struct node_type_base +{/* + node_type_base(VoidPtr p) + : up(p) + {}*/ + node_type_base() + {} + void set_pointer(VoidPtr p) + { up = p; } + + VoidPtr up; +}; + +template +struct node_type + : public node_type_base +{ + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + node_type() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + node_type(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : value(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + node_type(Args &&...args) + : value(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + void set_pointer(VoidPointer p) + { node_type_base::set_pointer(p); } + + T value; +}; + +template +class iterator + : public std::iterator< std::random_access_iterator_tag + , const typename std::iterator_traits::value_type + , typename std::iterator_traits::difference_type + , Pointer + , Value &> +{ + + typedef typename boost::pointer_to_other + ::type void_ptr; + typedef node_type node_type_t; + typedef typename boost::pointer_to_other + ::type node_type_ptr_t; + typedef typename boost::pointer_to_other + ::type void_ptr_ptr; + + friend class iterator::type>; + + public: + typedef std::random_access_iterator_tag iterator_category; + typedef Value value_type; + typedef typename std::iterator_traits + ::difference_type difference_type; + typedef Pointer pointer; + typedef Value & reference; + + iterator() + {} + + explicit iterator(node_type_ptr_t pn) + : pn(pn) + {} + + iterator(const iterator::type >& x) + : pn(x.pn) + {} + + private: + static node_type_ptr_t node_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return node_type_ptr_t(static_cast(stable_vector_detail::get_pointer(p))); + } + + static void_ptr_ptr void_ptr_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return void_ptr_ptr(static_cast(stable_vector_detail::get_pointer(p))); + } + + Value& dereference() const + { return pn->value; } + bool equal(const iterator& x) const + { return pn==x.pn; } + void increment() + { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+1)); } + void decrement() + { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)-1)); } + void advance(std::ptrdiff_t n) + { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+n)); } + std::ptrdiff_t distance_to(const iterator& x)const + { return void_ptr_ptr_cast(x.pn->up) - void_ptr_ptr_cast(pn->up); } + + public: + //Pointer like operators + reference operator*() const { return this->dereference(); } + pointer operator->() const { return pointer(&this->dereference()); } + + //Increment / Decrement + iterator& operator++() + { this->increment(); return *this; } + + iterator operator++(int) + { iterator tmp(*this); ++*this; return iterator(tmp); } + + iterator& operator--() + { this->decrement(); return *this; } + + iterator operator--(int) + { iterator tmp(*this); --*this; return iterator(tmp); } + + reference operator[](difference_type off) const + { + iterator tmp(*this); + tmp += off; + return *tmp; + } + + iterator& operator+=(difference_type off) + { + pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+off)); + return *this; + } + + iterator operator+(difference_type off) const + { + iterator tmp(*this); + tmp += off; + return tmp; + } + + friend iterator operator+(difference_type off, const iterator& right) + { + iterator tmp(right); + tmp += off; + return tmp; + } + + iterator& operator-=(difference_type off) + { *this += -off; return *this; } + + iterator operator-(difference_type off) const + { + iterator tmp(*this); + tmp -= off; + return tmp; + } + + difference_type operator-(const iterator& right) const + { + void_ptr_ptr p1 = void_ptr_ptr_cast(this->pn->up); + void_ptr_ptr p2 = void_ptr_ptr_cast(right.pn->up); + return p1 - p2; + } + + //Comparison operators + bool operator== (const iterator& r) const + { return pn == r.pn; } + + bool operator!= (const iterator& r) const + { return pn != r.pn; } + + bool operator< (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) < void_ptr_ptr_cast(r.pn->up); } + + bool operator<= (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) <= void_ptr_ptr_cast(r.pn->up); } + + bool operator> (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) > void_ptr_ptr_cast(r.pn->up); } + + bool operator>= (const iterator& r) const + { return void_ptr_ptr_cast(pn->up) >= void_ptr_ptr_cast(r.pn->up); } + + node_type_ptr_t pn; +}; + +/* +class node_access +{ + public: + template + static typename iterator::node_type_t* get(const iterator& it) + { + return stable_vector_detail::get_pointer(it.pn); + } +}; +*/ + +template +struct select_multiallocation_chain +{ + typedef typename Allocator::multiallocation_chain type; +}; + +template +struct select_multiallocation_chain +{ + typedef typename Allocator::template + rebind::other::pointer void_ptr; + typedef containers_detail::basic_multiallocation_cached_slist multialloc_cached; + typedef containers_detail::basic_multiallocation_cached_counted_slist + multialloc_cached_counted; + typedef boost::interprocess_container::containers_detail::transform_multiallocation_chain + type; +}; + +} //namespace stable_vector_detail + +#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + +#define STABLE_VECTOR_CHECK_INVARIANT \ +invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \ +BOOST_JOIN(check_invariant_,__LINE__).touch(); +#else + +#define STABLE_VECTOR_CHECK_INVARIANT + +#endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + +/// @endcond + +template > +class stable_vector +{ + typedef typename Allocator::template + rebind::other::pointer void_ptr; + typedef typename Allocator::template + rebind::other::pointer void_ptr_ptr; + typedef stable_vector_detail::node_type + node_type_t; + typedef typename Allocator::template + rebind::other::pointer node_type_ptr_t; + typedef stable_vector_detail::node_type_base + node_type_base_t; + typedef typename Allocator::template + rebind::other::pointer node_type_base_ptr_t; + typedef + #if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR) + ::boost::interprocess_container:: + #else + ::std:: + #endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR + vector::other + > impl_type; + typedef typename impl_type::iterator impl_iterator; + typedef typename impl_type::const_iterator const_impl_iterator; + + typedef ::boost::interprocess_container::containers_detail:: + integral_constant allocator_v1; + typedef ::boost::interprocess_container::containers_detail:: + integral_constant allocator_v2; + typedef ::boost::interprocess_container::containers_detail::integral_constant + ::value> alloc_version; + typedef typename Allocator:: + template rebind::other node_allocator_type; + + node_type_ptr_t allocate_one() + { return this->allocate_one(alloc_version()); } + + node_type_ptr_t allocate_one(allocator_v1) + { return get_al().allocate(1); } + + node_type_ptr_t allocate_one(allocator_v2) + { return get_al().allocate_one(); } + + void deallocate_one(node_type_ptr_t p) + { return this->deallocate_one(p, alloc_version()); } + + void deallocate_one(node_type_ptr_t p, allocator_v1) + { get_al().deallocate(p, 1); } + + void deallocate_one(node_type_ptr_t p, allocator_v2) + { get_al().deallocate_one(p); } + + friend class stable_vector_detail::clear_on_destroy; + + public: + // types: + + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef stable_vector_detail::iterator + iterator; + typedef stable_vector_detail::iterator + const_iterator; + typedef typename impl_type::size_type size_type; + typedef typename iterator::difference_type difference_type; + typedef T value_type; + typedef Allocator allocator_type; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + private: + static const size_type ExtraPointers = 3; + typedef typename stable_vector_detail:: + select_multiallocation_chain + < node_allocator_type + , alloc_version::value + >::type multiallocation_chain; + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(stable_vector) + + // construct/copy/destroy: + explicit stable_vector(const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + STABLE_VECTOR_CHECK_INVARIANT; + } + + stable_vector(size_type n,const T& t=T(),const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + stable_vector_detail::clear_on_destroy cod(*this); + this->insert(this->cbegin(), n, t); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + template + stable_vector(InputIterator first,InputIterator last,const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + stable_vector_detail::clear_on_destroy cod(*this); + this->insert(this->cbegin(), first, last); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + stable_vector(const stable_vector& x) + : internal_data(x.get_al()),impl(x.get_al()) + { + stable_vector_detail::clear_on_destroy cod(*this); + this->insert(this->cbegin(), x.begin(), x.end()); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + stable_vector(BOOST_INTERPROCESS_RV_REF(stable_vector) x) + : internal_data(x.get_al()),impl(x.get_al()) + { this->swap(x); } + + ~stable_vector() + { + this->clear(); + clear_pool(); + } + + stable_vector& operator=(const stable_vector &x) + { + STABLE_VECTOR_CHECK_INVARIANT; + if (this != &x) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + stable_vector& operator=(BOOST_INTERPROCESS_RV_REF(stable_vector) x) + { + if (&x != this){ + this->swap(x); + x.clear(); + } + return *this; + } + + template + void assign(InputIterator first,InputIterator last) + { + assign_dispatch(first, last, boost::is_integral()); + } + + void assign(size_type n,const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); + } + + allocator_type get_allocator()const {return get_al();} + + // iterators: + + iterator begin() + { return (impl.empty()) ? end(): iterator(node_ptr_cast(impl.front())) ; } + + const_iterator begin()const + { return (impl.empty()) ? cend() : const_iterator(node_ptr_cast(impl.front())) ; } + + iterator end() {return iterator(get_end_node());} + const_iterator end()const {return const_iterator(get_end_node());} + + reverse_iterator rbegin() {return reverse_iterator(this->end());} + const_reverse_iterator rbegin()const {return const_reverse_iterator(this->end());} + reverse_iterator rend() {return reverse_iterator(this->begin());} + const_reverse_iterator rend()const {return const_reverse_iterator(this->begin());} + + const_iterator cbegin()const {return this->begin();} + const_iterator cend()const {return this->end();} + const_reverse_iterator crbegin()const{return this->rbegin();} + const_reverse_iterator crend()const {return this->rend();} + + // capacity: + size_type size() const + { return impl.empty() ? 0 : (impl.size() - ExtraPointers); } + + size_type max_size() const + { return impl.max_size() - ExtraPointers; } + + size_type capacity() const + { + if(!impl.capacity()){ + return 0; + } + else{ + const size_type num_nodes = this->impl.size() + this->internal_data.pool_size; + const size_type num_buck = this->impl.capacity(); + return (num_nodes < num_buck) ? num_nodes : num_buck; + } + } + + bool empty() const + { return impl.empty() || impl.size() == ExtraPointers; } + + void resize(size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + if(n > size()) + this->insert(this->cend(), n - this->size(), t); + else if(n < this->size()) + this->erase(this->cbegin() + n, this->cend()); + } + + void resize(size_type n) + { + typedef default_construct_iterator default_iterator; + STABLE_VECTOR_CHECK_INVARIANT; + if(n > size()) + this->insert(this->cend(), default_iterator(n - this->size()), default_iterator()); + else if(n < this->size()) + this->erase(this->cbegin() + n, this->cend()); + } + + void reserve(size_type n) + { + STABLE_VECTOR_CHECK_INVARIANT; + if(n > this->max_size()) + throw std::bad_alloc(); + + size_type size = this->size(); + size_type old_capacity = this->capacity(); + if(n > old_capacity){ + this->initialize_end_node(n); + const void * old_ptr = &impl[0]; + impl.reserve(n + ExtraPointers); + bool realloced = &impl[0] != old_ptr; + //Fix the pointers for the newly allocated buffer + if(realloced){ + this->align_nodes(impl.begin(), impl.begin()+size+1); + } + //Now fill pool if data is not enough + if((n - size) > this->internal_data.pool_size){ + this->add_to_pool((n - size) - this->internal_data.pool_size, alloc_version()); + } + } + } + + template + void clear_pool(AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + if(!impl.empty() && impl.back()){ + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + + multiallocation_chain holder(p1, p2, this->internal_data.pool_size); + while(!holder.empty()){ + node_type_ptr_t n = holder.front(); + holder.pop_front(); + this->deallocate_one(n); + } + p1 = p2 = 0; + this->internal_data.pool_size = 0; + } + } + + template + void clear_pool(AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + + if(!impl.empty() && impl.back()){ + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, this->internal_data.pool_size); + get_al().deallocate_individual(boost::interprocess::move(holder)); + p1 = p2 = 0; + this->internal_data.pool_size = 0; + } + } + + void clear_pool() + { + this->clear_pool(alloc_version()); + } + + template + void add_to_pool(size_type n, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + size_type remaining = n; + while(remaining--){ + this->put_in_pool(this->allocate_one()); + } + } + + template + void add_to_pool(size_type n, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, this->internal_data.pool_size); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + multiallocation_chain m (get_al().allocate_individual(n)); + holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n); + this->internal_data.pool_size += n; + std::pair data(holder.extract_data()); + p1 = data.first; + p2 = data.second; + } + + void put_in_pool(node_type_ptr_t p) + { + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, internal_data.pool_size); + holder.push_front(p); + ++this->internal_data.pool_size; + std::pair ret(holder.extract_data()); + p1 = ret.first; + p2 = ret.second; + } + + node_type_ptr_t get_from_pool() + { + if(!impl.back()){ + return node_type_ptr_t(0); + } + else{ + void_ptr &p1 = *(impl.end()-2); + void_ptr &p2 = impl.back(); + multiallocation_chain holder(p1, p2, internal_data.pool_size); + node_type_ptr_t ret = holder.front(); + holder.pop_front(); + std::pair data(holder.extract_data()); + p1 = data.first; + p2 = data.second; + --this->internal_data.pool_size; + return ret; + } + } + + // element access: + + reference operator[](size_type n){return value(impl[n]);} + const_reference operator[](size_type n)const{return value(impl[n]);} + + const_reference at(size_type n)const + { + if(n>=size()) + throw std::out_of_range("invalid subscript at stable_vector::at"); + return operator[](n); + } + + reference at(size_type n) + { + if(n>=size()) + throw std::out_of_range("invalid subscript at stable_vector::at"); + return operator[](n); + } + + reference front() + { return value(impl.front()); } + + const_reference front()const + { return value(impl.front()); } + + reference back() + { return value(*(&impl.back() - ExtraPointers)); } + + const_reference back()const + { return value(*(&impl.back() - ExtraPointers)); } + + // modifiers: + + void push_back(const T& t) + { this->insert(end(), t); } + + void push_back(BOOST_INTERPROCESS_RV_REF(T) t) + { this->insert(end(), boost::interprocess::move(t)); } + + void pop_back() + { this->erase(this->end()-1); } + + iterator insert(const_iterator position, const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag()); + } + + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x) + { + typedef repeat_iterator repeat_it; + typedef boost::interprocess::move_iterator repeat_move_it; + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + this->insert(position + ,repeat_move_it(repeat_it(x, 1)) + ,repeat_move_it(repeat_it())); + return iterator(this->begin() + pos_n); + } + + void insert(const_iterator position, size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->insert_not_iter(position, n, t); + } + + template + void insert(const_iterator position,InputIterator first, InputIterator last) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->insert_iter(position,first,last, + boost::mpl::not_ >()); + } + + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef(boost::interprocess::forward(args)...); + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef(boost::interprocess::forward(args)...); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #else + + void emplace_back() + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef; + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } + + iterator emplace(const_iterator position) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef; + size_type pos_n = position - this->cbegin(); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); \ + } \ + \ + template \ + iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + size_type pos_n = pos - this->cbegin(); \ + this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \ + return iterator(this->begin() + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator erase(const_iterator position) + { + STABLE_VECTOR_CHECK_INVARIANT; + difference_type d=position-this->cbegin(); + impl_iterator it=impl.begin()+d; + this->delete_node(*it); + impl.erase(it); + this->align_nodes(impl.begin()+d,get_last_align()); + return this->begin()+d; + } + + iterator erase(const_iterator first, const_iterator last) + { return priv_erase(first, last, alloc_version()); } + + void swap(stable_vector & x) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->swap_impl(*this,x); + } + + void clear() + { this->erase(this->cbegin(),this->cend()); } + + /// @cond + private: + + void insert_iter_prolog(size_type n, difference_type d) + { + initialize_end_node(n); + const void* old_ptr = &impl[0]; + //size_type old_capacity = capacity(); + //size_type old_size = size(); + impl.insert(impl.begin()+d, n, 0); + bool realloced = &impl[0] != old_ptr; + //Fix the pointers for the newly allocated buffer + if(realloced){ + align_nodes(impl.begin(), impl.begin()+d); + } + } + + template + void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_) + { + STABLE_VECTOR_CHECK_INVARIANT; + iterator first1 = this->begin(); + iterator last1 = this->end(); + for ( ; first1 != last1 && first != last; ++first1, ++first) + *first1 = *first; + if (first == last){ + this->erase(first1, last1); + } + else{ + this->insert(last1, first, last); + } + } + + template + void assign_dispatch(Integer n, Integer t, boost::mpl::true_) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_()); + } + + iterator priv_erase(const_iterator first, const_iterator last, allocator_v1) + { + STABLE_VECTOR_CHECK_INVARIANT; + difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin(); + if(d1 != d2){ + impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2); + for(impl_iterator it = it1; it != it2; ++it) + this->delete_node(*it); + impl.erase(it1, it2); + this->align_nodes(impl.begin() + d1, get_last_align()); + } + return iterator(this->begin() + d1); + } + + impl_iterator get_last_align() + { + return impl.end() - (ExtraPointers - 1); + } + + const_impl_iterator get_last_align() const + { + return impl.cend() - (ExtraPointers - 1); + } + + template + iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + STABLE_VECTOR_CHECK_INVARIANT; + return priv_erase(first, last, allocator_v1()); + } + + static node_type_ptr_t node_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return node_type_ptr_t(static_cast(stable_vector_detail::get_pointer(p))); + } + + static node_type_base_ptr_t node_base_ptr_cast(void_ptr p) + { + using boost::get_pointer; + return node_type_base_ptr_t(static_cast(stable_vector_detail::get_pointer(p))); + } + + static value_type& value(void_ptr p) + { + return node_ptr_cast(p)->value; + } + + void initialize_end_node(size_type impl_capacity = 0) + { + if(impl.empty()){ + impl.reserve(impl_capacity + ExtraPointers); + impl.resize (ExtraPointers, void_ptr(0)); + impl[0] = &this->internal_data.end_node; + this->internal_data.end_node.up = &impl[0]; + } + } + + void readjust_end_node() + { + if(!this->impl.empty()){ + void_ptr &end_node_ref = *(this->get_last_align()-1); + end_node_ref = this->get_end_node(); + this->internal_data.end_node.up = &end_node_ref; + } + else{ + this->internal_data.end_node.up = void_ptr(&this->internal_data.end_node.up); + } + } + + node_type_ptr_t get_end_node() const + { + const node_type_base_t* cp = &this->internal_data.end_node; + node_type_base_t* p = const_cast(cp); + return node_ptr_cast(p); + } + + template + void_ptr new_node(void_ptr up, Iter it) + { + node_type_ptr_t p = this->allocate_one(); + try{ + boost::interprocess_container::construct_in_place(&*p, it); + p->set_pointer(up); + } + catch(...){ + this->deallocate_one(p); + throw; + } + return p; + } + + void delete_node(void_ptr p) + { + node_type_ptr_t n(node_ptr_cast(p)); + n->~node_type_t(); + this->put_in_pool(n); + } + + static void align_nodes(impl_iterator first,impl_iterator last) + { + while(first!=last){ + node_ptr_cast(*first)->up = void_ptr(&*first); + ++first; + } + } + + void insert_not_iter(const_iterator position, size_type n, const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag()); + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_) + { + typedef typename std::iterator_traits::iterator_category category; + this->insert_iter(position, first, last, category()); + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag) + { + for(; first!=last; ++first){ + this->insert(position, *first); + } + } + + template + iterator insert_iter(const_iterator position, InputIterator first, InputIterator last, std::forward_iterator_tag) + { + size_type n = (size_type)std::distance(first,last); + difference_type d = position-this->cbegin(); + if(n){ + this->insert_iter_prolog(n, d); + const impl_iterator it(impl.begin() + d); + this->insert_iter_fwd(it, first, last, n); + //Fix the pointers for the newly allocated buffer + this->align_nodes(it + n, get_last_align()); + } + return this->begin() + d; + } + + template + void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v1) + { + size_type i=0; + try{ + while(first!=last){ + *(it + i) = this->new_node(void_ptr((void*)(&*(it + i))), first); + ++first; + ++i; + } + } + catch(...){ + impl.erase(it + i, it + n); + this->align_nodes(it + i, get_last_align()); + throw; + } + } + + template + void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2) + { + multiallocation_chain mem(get_al().allocate_individual(n)); + + size_type i = 0; + node_type_ptr_t p = 0; + try{ + while(first != last){ + p = mem.front(); + mem.pop_front(); + //This can throw + boost::interprocess_container::construct_in_place(&*p, first); + p->set_pointer(void_ptr((void*)(&*(it + i)))); + ++first; + *(it + i) = p; + ++i; + } + } + catch(...){ + get_al().deallocate_one(p); + get_al().deallocate_many(boost::interprocess::move(mem)); + impl.erase(it+i, it+n); + this->align_nodes(it+i,get_last_align()); + throw; + } + } + + template + void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n) + { + size_type i = 0; + node_type_ptr_t p = 0; + try{ + while(first != last){ + p = get_from_pool(); + if(!p){ + insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version()); + break; + } + //This can throw + boost::interprocess_container::construct_in_place(&*p, first); + p->set_pointer(void_ptr(&*(it+i))); + ++first; + *(it+i)=p; + ++i; + } + } + catch(...){ + put_in_pool(p); + impl.erase(it+i,it+n); + this->align_nodes(it+i,get_last_align()); + throw; + } + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::false_) + { + this->insert_not_iter(position,first,last); + } + + static void swap_impl(stable_vector& x,stable_vector& y) + { + using std::swap; + swap(x.get_al(),y.get_al()); + swap(x.impl,y.impl); + swap(x.internal_data.pool_size, y.internal_data.pool_size); + x.readjust_end_node(); + y.readjust_end_node(); + } + + #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) + bool invariant()const + { + if(impl.empty()) + return !capacity() && !size(); + if(get_end_node() != *(impl.end() - ExtraPointers)){ + return false; + } + for(const_impl_iterator it=impl.begin(),it_end=get_last_align();it!=it_end;++it){ + if(node_ptr_cast(*it)->up != &*it) + return false; + } + size_type n = capacity()-size(); + const void_ptr &pool_head = impl.back(); + size_type num_pool = 0; + node_type_ptr_t p = node_ptr_cast(pool_head); + while(p){ + ++num_pool; + p = p->up; + } + return n >= num_pool; + } + + class invariant_checker:private boost::noncopyable + { + const stable_vector* p; + public: + invariant_checker(const stable_vector& v):p(&v){} + ~invariant_checker(){BOOST_ASSERT(p->invariant());} + void touch(){} + }; + #endif + + struct ebo_holder + : node_allocator_type + { + ebo_holder(const allocator_type &a) + : node_allocator_type(a), pool_size(0), end_node() + { + end_node.set_pointer(void_ptr(&end_node.up)); + } + size_type pool_size; + node_type_base_t end_node; + } internal_data; + + node_allocator_type &get_al() { return internal_data; } + const node_allocator_type &get_al() const { return internal_data; } + + impl_type impl; + /// @endcond +}; + +template +bool operator==(const stable_vector& x,const stable_vector& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template +bool operator< (const stable_vector& x,const stable_vector& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template +bool operator!=(const stable_vector& x,const stable_vector& y) +{ + return !(x==y); +} + +template +bool operator> (const stable_vector& x,const stable_vector& y) +{ + return y +bool operator>=(const stable_vector& x,const stable_vector& y) +{ + return !(x +bool operator<=(const stable_vector& x,const stable_vector& y) +{ + return !(x>y); +} + +// specialized algorithms: + +template +void swap(stable_vector& x,stable_vector& y) +{ + x.swap(y); +} + +/// @cond + +#undef STABLE_VECTOR_CHECK_INVARIANT + +/// @endcond + +}} + +#endif diff --git a/include/boost/interprocess/containers/container/string.hpp b/include/boost/interprocess/containers/container/string.hpp new file mode 100644 index 0000000..cb061ad --- /dev/null +++ b/include/boost/interprocess/containers/container/string.hpp @@ -0,0 +1,2320 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's string file. Modified by Ion Gaztanaga 2004-2008 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. + +#ifndef BOOST_CONTAINERS_STRING_HPP +#define BOOST_CONTAINERS_STRING_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +namespace containers_detail { +// ------------------------------------------------------------ +// Class basic_string_base. + +// basic_string_base is a helper class that makes it it easier to write +// an exception-safe version of basic_string. The constructor allocates, +// but does not initialize, a block of memory. The destructor +// deallocates, but does not destroy elements within, a block of +// memory. The destructor assumes that the memory either is the internal buffer, +// or else points to a block of memory that was allocated using _String_base's +// allocator and whose size is this->m_storage. +template +class basic_string_base +{ + basic_string_base(); + basic_string_base(basic_string_base&); + basic_string_base & operator=(basic_string_base&); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_string_base) + + typedef A allocator_type; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + typedef typename A::pointer pointer; + typedef typename A::value_type value_type; + typedef typename A::size_type size_type; + + basic_string_base(const allocator_type& a) + : members_(a) + { init(); } + + basic_string_base(const allocator_type& a, std::size_t n) + : members_(a) + { + this->init(); + this->allocate_initial_block(n); + } + + basic_string_base(BOOST_INTERPROCESS_RV_REF(basic_string_base) b) + : members_(b.members_) + { + init(); + this->swap(b); + } + + ~basic_string_base() + { + this->deallocate_block(); + if(!this->is_short()){ + static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); + } + } + + private: + + //This is the structure controlling a long string + struct long_t + { + size_type is_short : 1; + size_type length : (sizeof(size_type)*CHAR_BIT - 1); + size_type storage; + pointer start; + + long_t() + {} + + long_t(const long_t &other) + { + this->is_short = other.is_short; + length = other.length; + storage = other.storage; + start = other.start; + } + + long_t &operator =(const long_t &other) + { + this->is_short = other.is_short; + length = other.length; + storage = other.storage; + start = other.start; + return *this; + } + }; + + //This basic type should have the same alignment as long_t +//iG typedef typename type_with_alignment::value>::type +// long_alignment_type; + typedef void *long_alignment_type; + BOOST_STATIC_ASSERT((containers_detail::alignment_of::value % + containers_detail::alignment_of::value) == 0); + + + //This type is the first part of the structure controlling a short string + //The "data" member stores + struct short_header + { + unsigned char is_short : 1; + unsigned char length : (CHAR_BIT - 1); + }; + + //This type has the same alignment and size as long_t but it's POD + //so, unlike long_t, it can be placed in a union + struct long_raw_t + { + long_alignment_type a; + unsigned char b[sizeof(long_t) - sizeof(long_alignment_type)]; + }; + + protected: + static const size_type MinInternalBufferChars = 8; + static const size_type AlignmentOfValueType = + alignment_of::value; + static const size_type ShortDataOffset = + containers_detail::ct_rounded_size::value; + static const size_type ZeroCostInternalBufferChars = + (sizeof(long_t) - ShortDataOffset)/sizeof(value_type); + static const size_type UnalignedFinalInternalBufferChars = + (ZeroCostInternalBufferChars > MinInternalBufferChars) ? + ZeroCostInternalBufferChars : MinInternalBufferChars; + + struct short_t + { + short_header h; + value_type data[UnalignedFinalInternalBufferChars]; + }; + + union repr_t + { + long_raw_t r; + short_t s; + + short_t &short_repr() const + { return *const_cast(&s); } + + long_t &long_repr() const + { return *static_cast(const_cast(static_cast(&r))); } + }; + + struct members_holder + : public A + { + members_holder(const A &a) + : A(a) + {} + + repr_t m_repr; + } members_; + + const A &alloc() const + { return members_; } + + A &alloc() + { return members_; } + + static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type); + + private: + + static const size_type MinAllocation = InternalBufferChars*2; + + protected: + bool is_short() const + { return static_cast(this->members_.m_repr.s.h.is_short != 0); } + + void is_short(bool yes) + { + if(yes && !this->is_short()){ + static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); + } + else{ + new(static_cast(&this->members_.m_repr.r))long_t(); + } + this->members_.m_repr.s.h.is_short = yes; + } + + private: + void init() + { + this->members_.m_repr.s.h.is_short = 1; + this->members_.m_repr.s.h.length = 0; + } + + protected: + + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, pointer reuse = 0) + { + if(this->is_short() && (command & (expand_fwd | expand_bwd)) ){ + reuse = pointer(0); + command &= ~(expand_fwd | expand_bwd); + } + return this->allocation_command + (command, limit_size, preferred_size, received_size, reuse, alloc_version()); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + (void)limit_size; + (void)reuse; + if(!(command & allocate_new)) + return std::pair(pointer(0), 0); + received_size = preferred_size; + return std::make_pair(this->alloc().allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + pointer reuse, + allocator_v2) + { + return this->alloc().allocation_command(command, limit_size, preferred_size, + received_size, reuse); + } + + size_type next_capacity(size_type additional_objects) const + { return get_next_capacity(this->alloc().max_size(), this->priv_storage(), additional_objects); } + + void deallocate(pointer p, std::size_t n) + { + if (p && (n > InternalBufferChars)) + this->alloc().deallocate(p, n); + } + + void construct(pointer p, const value_type &value = value_type()) + { new((void*)containers_detail::get_pointer(p)) value_type(value); } + + void destroy(pointer p, size_type n) + { + for(; n--; ++p) + containers_detail::get_pointer(p)->~value_type(); + } + + void destroy(pointer p) + { containers_detail::get_pointer(p)->~value_type(); } + + void allocate_initial_block(std::size_t n) + { + if (n <= this->max_size()) { + if(n > InternalBufferChars){ + size_type new_cap = this->next_capacity(n); + pointer p = this->allocation_command(allocate_new, n, new_cap, new_cap).first; + this->is_short(false); + this->priv_addr(p); + this->priv_size(0); + this->priv_storage(new_cap); + } + } + else + throw_length_error(); + } + + void deallocate_block() + { this->deallocate(this->priv_addr(), this->priv_storage()); } + + std::size_t max_size() const + { return this->alloc().max_size() - 1; } + + // Helper functions for exception handling. + void throw_length_error() const + { throw(std::length_error("basic_string")); } + + void throw_out_of_range() const + { throw(std::out_of_range("basic_string")); } + + protected: + size_type priv_capacity() const + { return this->priv_storage() - 1; } + + pointer priv_addr() const + { return this->is_short() ? pointer(&this->members_.m_repr.short_repr().data[0]) : this->members_.m_repr.long_repr().start; } + + void priv_addr(pointer addr) + { this->members_.m_repr.long_repr().start = addr; } + + size_type priv_storage() const + { return this->is_short() ? InternalBufferChars : this->members_.m_repr.long_repr().storage; } + + void priv_storage(size_type storage) + { + if(!this->is_short()) + this->members_.m_repr.long_repr().storage = storage; + } + + size_type priv_size() const + { return this->is_short() ? this->members_.m_repr.short_repr().h.length : this->members_.m_repr.long_repr().length; } + + void priv_size(size_type sz) + { + if(this->is_short()) + this->members_.m_repr.s.h.length = (unsigned char)sz; + else + this->members_.m_repr.long_repr().length = static_cast(sz); + } + + void swap(basic_string_base& other) + { + if(this->is_short()){ + if(other.is_short()){ + std::swap(this->members_.m_repr, other.members_.m_repr); + } + else{ + repr_t copied(this->members_.m_repr); + this->members_.m_repr.long_repr() = other.members_.m_repr.long_repr(); + other.members_.m_repr = copied; + } + } + else{ + if(other.is_short()){ + repr_t copied(other.members_.m_repr); + other.members_.m_repr.long_repr() = this->members_.m_repr.long_repr(); + this->members_.m_repr = copied; + } + else{ + std::swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); + } + } + + allocator_type & this_al = this->alloc(), &other_al = other.alloc(); + if(this_al != other_al){ + containers_detail::do_swap(this_al, other_al); + } + } +}; + +} //namespace containers_detail { + +/// @endcond + +//! The basic_string class represents a Sequence of characters. It contains all the +//! usual operations of a Sequence, and, additionally, it contains standard string +//! operations such as search and concatenation. +//! +//! The basic_string class is parameterized by character type, and by that type's +//! Character Traits. +//! +//! This class has performance characteristics very much like vector<>, meaning, +//! for example, that it does not perform reference-count or copy-on-write, and that +//! concatenation of two strings is an O(N) operation. +//! +//! Some of basic_string's member functions use an unusual method of specifying positions +//! and ranges. In addition to the conventional method using iterators, many of +//! basic_string's member functions use a single value pos of type size_type to represent a +//! position (in which case the position is begin() + pos, and many of basic_string's +//! member functions use two values, pos and n, to represent a range. In that case pos is +//! the beginning of the range and n is its size. That is, the range is +//! [begin() + pos, begin() + pos + n). +//! +//! Note that the C++ standard does not specify the complexity of basic_string operations. +//! In this implementation, basic_string has performance characteristics very similar to +//! those of vector: access to a single character is O(1), while copy and concatenation +//! are O(N). +//! +//! In this implementation, begin(), +//! end(), rbegin(), rend(), operator[], c_str(), and data() do not invalidate iterators. +//! In this implementation, iterators are only invalidated by member functions that +//! explicitly change the string's contents. +template +class basic_string + : private containers_detail::basic_string_base +{ + /// @cond + private: + typedef containers_detail::basic_string_base base_t; + static const typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars; + + protected: + // A helper class to use a char_traits as a function object. + + template + struct Eq_traits + : public std::binary_function + { + bool operator()(const typename Tr::char_type& x, + const typename Tr::char_type& y) const + { return Tr::eq(x, y); } + }; + + template + struct Not_within_traits + : public std::unary_function + { + typedef const typename Tr::char_type* Pointer; + const Pointer m_first; + const Pointer m_last; + + Not_within_traits(Pointer f, Pointer l) + : m_first(f), m_last(l) {} + + bool operator()(const typename Tr::char_type& x) const + { + return std::find_if(m_first, m_last, + std::bind1st(Eq_traits(), x)) == m_last; + } + }; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_string) + + //! The allocator type + typedef A allocator_type; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + //! The type of object, CharT, stored in the string + typedef CharT value_type; + //! The second template parameter Traits + typedef Traits traits_type; + //! Pointer to CharT + typedef typename A::pointer pointer; + //! Const pointer to CharT + typedef typename A::const_pointer const_pointer; + //! Reference to CharT + typedef typename A::reference reference; + //! Const reference to CharT + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! Iterator used to iterate through a string. It's a Random Access Iterator + typedef pointer iterator; + //! Const iterator used to iterate through a string. It's a Random Access Iterator + typedef const_pointer const_iterator; + //! Iterator used to iterate backwards through a string + typedef std::reverse_iterator reverse_iterator; + //! Const iterator used to iterate backwards through a string + typedef std::reverse_iterator const_reverse_iterator; + //! The largest possible value of type size_type. That is, size_type(-1). + static const size_type npos; + + /// @cond + private: + typedef constant_iterator cvalue_iterator; + /// @endcond + + public: // Constructor, destructor, assignment. + /// @cond + struct reserve_t {}; + /// @endcond + + basic_string(reserve_t, std::size_t n, + const allocator_type& a = allocator_type()) + : base_t(a, n + 1) + { this->priv_terminate_string(); } + + //! Effects: Constructs a basic_string taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + explicit basic_string(const allocator_type& a = allocator_type()) + : base_t(a, InternalBufferChars) + { this->priv_terminate_string(); } + + //! Effects: Copy constructs a basic_string. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + basic_string(const basic_string& s) + : base_t(s.alloc()) + { this->priv_range_initialize(s.begin(), s.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + basic_string(BOOST_INTERPROCESS_RV_REF(basic_string) s) + : base_t(boost::interprocess::move((base_t&)s)) + {} + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by a specific number of characters of the s string. + basic_string(const basic_string& s, size_type pos, size_type n = npos, + const allocator_type& a = allocator_type()) + : base_t(a) + { + if (pos > s.size()) + this->throw_out_of_range(); + else + this->priv_range_initialize + (s.begin() + pos, s.begin() + pos + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by a specific number of characters of the s c-string. + basic_string(const CharT* s, size_type n, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + n); } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by the null-terminated s c-string. + basic_string(const CharT* s, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + Traits::length(s)); } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and is initialized by n copies of c. + basic_string(size_type n, CharT c, + const allocator_type& a = allocator_type()) + : base_t(a) + { + this->priv_range_initialize(cvalue_iterator(c, n), + cvalue_iterator()); + } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and a range of iterators. + template + basic_string(InputIterator f, InputIterator l, + const allocator_type& a = allocator_type()) + : base_t(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_initialize_dispatch(f, l, Result()); + } + + //! Effects: Destroys the basic_string. All used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + ~basic_string() + {} + + //! Effects: Copy constructs a string. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + basic_string& operator=(const basic_string& s) + { + if (&s != this) + this->assign(s.begin(), s.end()); + return *this; + } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + basic_string& operator=(BOOST_INTERPROCESS_RV_REF(basic_string) ms) + { + basic_string &s = ms; + if (&s != this){ + this->swap(s); + } + return *this; + } + + //! Effects: Assignment from a null-terminated c-string. + basic_string& operator=(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + //! Effects: Assignment from character. + basic_string& operator=(CharT c) + { return this->assign(static_cast(1), c); } + + //! Effects: Returns an iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return this->priv_addr(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->priv_addr(); } + + //! Effects: Returns an iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return this->priv_addr() + this->priv_size(); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->priv_addr() + this->priv_size(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(this->priv_addr() + this->priv_size()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(this->priv_addr()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return const_reverse_iterator(this->priv_addr()); } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return this->alloc(); } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->priv_size(); } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type length() const + { return this->size(); } + + //! Effects: Returns the largest possible size of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return base_t::max_size(); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n, CharT c) + { + if (n <= size()) + this->erase(this->begin() + n, this->end()); + else + this->append(n - this->size(), c); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n) + { resize(n, this->priv_null()); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + void reserve(size_type res_arg) + { + if (res_arg > this->max_size()) + this->throw_length_error(); + + if (this->capacity() < res_arg){ + size_type n = containers_detail::max_value(res_arg, this->size()) + 1; + size_type new_cap = this->next_capacity(n); + pointer new_start = this->allocation_command + (allocate_new, n, new_cap, new_cap).first; + size_type new_length = 0; + + new_length += priv_uninitialized_copy + (this->priv_addr(), this->priv_addr() + this->priv_size(), new_start); + this->priv_construct_null(new_start + new_length); + this->deallocate_block(); + this->is_short(false); + this->priv_addr(new_start); + this->priv_size(new_length); + this->priv_storage(new_cap); + } + } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return this->priv_capacity(); } + + //! Effects: Erases all the elements of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the vector. + void clear() + { + if (!empty()) { + Traits::assign(*this->priv_addr(), this->priv_null()); + this->priv_size(0); + } + } + + //! Effects: Returns true if the vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->priv_size(); } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return *(this->priv_addr() + n); } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const + { return *(this->priv_addr() + n); } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) { + if (n >= size()) + this->throw_out_of_range(); + return *(this->priv_addr() + n); + } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const { + if (n >= size()) + this->throw_out_of_range(); + return *(this->priv_addr() + n); + } + + //! Effects: Appends string s to *this. + basic_string& operator+=(const basic_string& s) + { return this->append(s); } + + //! Effects: Appends c-string s to *this. + basic_string& operator+=(const CharT* s) + { return this->append(s); } + + //! Effects: Appends character c to *this. + basic_string& operator+=(CharT c) + { this->push_back(c); return *this; } + + //! Effects: Appends string s to *this. + basic_string& append(const basic_string& s) + { return this->append(s.begin(), s.end()); } + + //! Effects: Appends the range [pos, pos + n) from string s to *this. + basic_string& append(const basic_string& s, size_type pos, size_type n) + { + if (pos > s.size()) + this->throw_out_of_range(); + return this->append(s.begin() + pos, + s.begin() + pos + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: Appends the range [s, s + n) from c-string s to *this. + basic_string& append(const CharT* s, size_type n) + { return this->append(s, s + n); } + + //! Effects: Appends the c-string s to *this. + basic_string& append(const CharT* s) + { return this->append(s, s + Traits::length(s)); } + + //! Effects: Appends the n times the character c to *this. + basic_string& append(size_type n, CharT c) + { return this->append(cvalue_iterator(c, n), cvalue_iterator()); } + + //! Effects: Appends the range [first, last) *this. + template + basic_string& append(InputIter first, InputIter last) + { this->insert(this->end(), first, last); return *this; } + + //! Effects: Inserts a copy of c at the end of the vector. + void push_back(CharT c) + { + if (this->priv_size() < this->capacity()){ + this->priv_construct_null(this->priv_addr() + (this->priv_size() + 1)); + Traits::assign(this->priv_addr()[this->priv_size()], c); + this->priv_size(this->priv_size()+1); + } + else{ + //No enough memory, insert a new object at the end + this->append((size_type)1, c); + } + } + + //! Effects: Removes the last element from the vector. + void pop_back() + { + Traits::assign(this->priv_addr()[this->priv_size()-1], this->priv_null()); + this->priv_size(this->priv_size()-1);; + } + + //! Effects: Assigns the value s to *this. + basic_string& assign(const basic_string& s) + { return this->operator=(s); } + + //! Effects: Moves the resources from ms *this. + basic_string& assign(BOOST_INTERPROCESS_RV_REF(basic_string) ms) + { return this->operator=(ms);} + + //! Effects: Assigns the range [pos, pos + n) from s to *this. + basic_string& assign(const basic_string& s, + size_type pos, size_type n) { + if (pos > s.size()) + this->throw_out_of_range(); + return this->assign(s.begin() + pos, + s.begin() + pos + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: Assigns the range [s, s + n) from s to *this. + basic_string& assign(const CharT* s, size_type n) + { return this->assign(s, s + n); } + + //! Effects: Assigns the c-string s to *this. + basic_string& assign(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + //! Effects: Assigns the character c n-times to *this. + basic_string& assign(size_type n, CharT c) + { return this->assign(cvalue_iterator(c, n), cvalue_iterator()); } + + //! Effects: Assigns the range [first, last) to *this. + template + basic_string& assign(InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + return this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Assigns the range [f, l) to *this. + basic_string& assign(const CharT* f, const CharT* l) + { + const std::ptrdiff_t n = l - f; + if (static_cast(n) <= size()) { + Traits::copy(containers_detail::get_pointer(this->priv_addr()), f, n); + this->erase(this->priv_addr() + n, this->priv_addr() + this->priv_size()); + } + else { + Traits::copy(containers_detail::get_pointer(this->priv_addr()), f, this->priv_size()); + this->append(f + this->priv_size(), l); + } + return *this; + } + + //! Effects: Inserts the string s before pos. + basic_string& insert(size_type pos, const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - s.size()) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, s.begin(), s.end()); + return *this; + } + + //! Effects: Inserts the range [pos, pos + n) from string s before pos. + basic_string& insert(size_type pos, const basic_string& s, + size_type beg, size_type n) + { + if (pos > this->size() || beg > s.size()) + this->throw_out_of_range(); + size_type len = containers_detail::min_value(n, s.size() - beg); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + const CharT *beg_ptr = containers_detail::get_pointer(s.begin()) + beg; + const CharT *end_ptr = beg_ptr + len; + this->insert(this->priv_addr() + pos, beg_ptr, end_ptr); + return *this; + } + + //! Effects: Inserts the range [s, s + n) before pos. + basic_string& insert(size_type pos, const CharT* s, size_type n) + { + if (pos > this->size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - n) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, s, s + n); + return *this; + } + + //! Effects: Inserts the c-string s before pos. + basic_string& insert(size_type pos, const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + size_type len = Traits::length(s); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, s, s + len); + return *this; + } + + //! Effects: Inserts the character c n-times before pos. + basic_string& insert(size_type pos, size_type n, CharT c) + { + if (pos > this->size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - n) + this->throw_length_error(); + this->insert(this->priv_addr() + pos, n, c); + return *this; + } + + //! Effects: Inserts the character c before position. + iterator insert(iterator position, CharT c) + { + size_type new_offset = position - this->priv_addr() + 1; + this->insert(position, cvalue_iterator(c, 1), + cvalue_iterator()); + return this->priv_addr() + new_offset; + } + + //! Effects: Inserts the character c n-times before position. + void insert(iterator position, std::size_t n, CharT c) + { + this->insert(position, cvalue_iterator(c, n), + cvalue_iterator()); + } + + //! Effects: Inserts the range [first, last) before position. + template + void insert(iterator p, InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + //! Effects: Inserts the range [pos, pos + n). + basic_string& erase(size_type pos = 0, size_type n = npos) + { + if (pos > size()) + this->throw_out_of_range(); + erase(this->priv_addr() + pos, this->priv_addr() + pos + containers_detail::min_value(n, size() - pos)); + return *this; + } + + //! Effects: Erases the character pointed by position. + iterator erase(iterator position) + { + // The move includes the terminating null. + Traits::move(containers_detail::get_pointer(position), + containers_detail::get_pointer(position + 1), + this->priv_size() - (position - this->priv_addr())); + this->priv_size(this->priv_size()-1); + return position; + } + + //! Effects: Erases the range [first, last). + iterator erase(iterator first, iterator last) + { + if (first != last) { // The move includes the terminating null. + size_type num_erased = last - first; + Traits::move(containers_detail::get_pointer(first), + containers_detail::get_pointer(last), + (this->priv_size() + 1)-(last - this->priv_addr())); + size_type new_length = this->priv_size() - num_erased; + this->priv_size(new_length); + } + return first; + } + + //! Effects: Replaces a substring of *this with the string s. + basic_string& replace(size_type pos, size_type n, + const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n, size() - pos); + if (this->size() - len >= this->max_size() - s.size()) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + s.begin(), s.end()); + } + + //! Effects: Replaces a substring of *this with a substring of s. + basic_string& replace(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) + { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + const size_type len1 = containers_detail::min_value(n1, size() - pos1); + const size_type len2 = containers_detail::min_value(n2, s.size() - pos2); + if (this->size() - len1 >= this->max_size() - len2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len1, + s.priv_addr() + pos2, s.priv_addr() + pos2 + len2); + } + + //! Effects: Replaces a substring of *this with the first n1 characters of s. + basic_string& replace(size_type pos, size_type n1, + const CharT* s, size_type n2) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + s, s + n2); + } + + //! Effects: Replaces a substring of *this with a null-terminated character array. + basic_string& replace(size_type pos, size_type n1, + const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n1, size() - pos); + const size_type n2 = Traits::length(s); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, + s, s + Traits::length(s)); + } + + //! Effects: Replaces a substring of *this with n1 copies of c. + basic_string& replace(size_type pos, size_type n1, + size_type n2, CharT c) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, n2, c); + } + + //! Effects: Replaces a substring of *this with the string s. + basic_string& replace(iterator first, iterator last, + const basic_string& s) + { return this->replace(first, last, s.begin(), s.end()); } + + //! Effects: Replaces a substring of *this with the first n characters of s. + basic_string& replace(iterator first, iterator last, + const CharT* s, size_type n) + { return this->replace(first, last, s, s + n); } + + //! Effects: Replaces a substring of *this with a null-terminated character array. + basic_string& replace(iterator first, iterator last, + const CharT* s) + { return this->replace(first, last, s, s + Traits::length(s)); } + + //! Effects: Replaces a substring of *this with n copies of c. + basic_string& replace(iterator first, iterator last, + size_type n, CharT c) + { + const size_type len = static_cast(last - first); + if (len >= n) { + Traits::assign(containers_detail::get_pointer(first), n, c); + erase(first + n, last); + } + else { + Traits::assign(containers_detail::get_pointer(first), len, c); + insert(last, n - len, c); + } + return *this; + } + + //! Effects: Replaces a substring of *this with the range [f, l) + template + basic_string& replace(iterator first, iterator last, + InputIter f, InputIter l) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + return this->priv_replace_dispatch(first, last, f, l, Result()); + } + + //! Effects: Copies a substring of *this to a buffer. + size_type copy(CharT* s, size_type n, size_type pos = 0) const + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = containers_detail::min_value(n, size() - pos); + Traits::copy(s, containers_detail::get_pointer(this->priv_addr() + pos), len); + return len; + } + + //! Effects: Swaps the contents of two strings. + void swap(basic_string& x) + { base_t::swap(x); } + + //! Returns: Returns a pointer to a null-terminated array of characters + //! representing the string's contents. For any string s it is guaranteed + //! that the first s.size() characters in the array pointed to by s.c_str() + //! are equal to the character in s, and that s.c_str()[s.size()] is a null + //! character. Note, however, that it not necessarily the first null character. + //! Characters within a string are permitted to be null. + const CharT* c_str() const + { return containers_detail::get_pointer(this->priv_addr()); } + + //! Returns: Returns a pointer to an array of characters, not necessarily + //! null-terminated, representing the string's contents. data() is permitted, + //! but not required, to be identical to c_str(). The first size() characters + //! of that array are guaranteed to be identical to the characters in *this. + //! The return value of data() is never a null pointer, even if size() is zero. + const CharT* data() const + { return containers_detail::get_pointer(this->priv_addr()); } + + //! Effects: Searches for s as a substring of *this, beginning at + //! character pos of *this. + size_type find(const basic_string& s, size_type pos = 0) const + { return find(s.c_str(), pos, s.size()); } + + //! Effects: Searches for a null-terminated character array as a + //! substring of *this, beginning at character pos of *this. + size_type find(const CharT* s, size_type pos = 0) const + { return find(s, pos, Traits::length(s)); } + + //! Effects: Searches for the first n characters of s as a substring + //! of *this, beginning at character pos of *this. + size_type find(const CharT* s, size_type pos, size_type n) const + { + if (pos + n > size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const const_iterator result = + std::search(containers_detail::get_pointer(this->priv_addr() + pos), + containers_detail::get_pointer(finish), + s, s + n, Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches for the character c, beginning at character + //! position pos. + size_type find(CharT c, size_type pos = 0) const + { + if (pos >= size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const const_iterator result = + std::find_if(this->priv_addr() + pos, finish, + std::bind2nd(Eq_traits(), c)); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches backward for s as a substring of *this, + //! beginning at character position min(pos, size()) + size_type rfind(const basic_string& s, size_type pos = npos) const + { return rfind(s.c_str(), pos, s.size()); } + + //! Effects: Searches backward for a null-terminated character array + //! as a substring of *this, beginning at character min(pos, size()) + size_type rfind(const CharT* s, size_type pos = npos) const + { return rfind(s, pos, Traits::length(s)); } + + //! Effects: Searches backward for the first n characters of s as a + //! substring of *this, beginning at character position min(pos, size()). + size_type rfind(const CharT* s, size_type pos, size_type n) const + { + const std::size_t len = size(); + + if (n > len) + return npos; + else if (n == 0) + return containers_detail::min_value(len, pos); + else { + const const_iterator last = begin() + containers_detail::min_value(len - n, pos) + n; + const const_iterator result = find_end(begin(), last, + s, s + n, + Eq_traits()); + return result != last ? result - begin() : npos; + } + } + + //! Effects: Searches backward for a null-terminated character array + //! as a substring of *this, beginning at character min(pos, size()). + size_type rfind(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + containers_detail::min_value(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::bind2nd(Eq_traits(), c)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to any character within s. + size_type find_first_of(const basic_string& s, size_type pos = 0) const + { return find_first_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to any character within s. + size_type find_first_of(const CharT* s, size_type pos = 0) const + { return find_first_of(s, pos, Traits::length(s)); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to any character within the first n characters of s. + size_type find_first_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos >= size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const_iterator result = std::find_first_of(this->priv_addr() + pos, finish, + s, s + n, + Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is equal to c. + size_type find_first_of(CharT c, size_type pos = 0) const + { return find(c, pos); } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is equal to any character within s. + size_type find_last_of(const basic_string& s, + size_type pos = npos) const + { return find_last_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches backward *this, beginning at min(pos, size()), for + //! the first character that is equal to any character within s. + size_type find_last_of(const CharT* s, size_type pos = npos) const + { return find_last_of(s, pos, Traits::length(s)); } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is equal to any character within the first n + //! characters of s. + size_type find_last_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = this->priv_addr() + containers_detail::min_value(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_first_of(const_reverse_iterator(last), rend(), + s, s + n, + Eq_traits()); + return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; + } + } + + //! Effects: Searches backward *this, beginning at min(pos, size()), for + //! the first character that is equal to c. + size_type find_last_of(CharT c, size_type pos = npos) const + { return rfind(c, pos); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to any character within s. + size_type find_first_not_of(const basic_string& s, + size_type pos = 0) const + { return find_first_not_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to any character within s. + size_type find_first_not_of(const CharT* s, size_type pos = 0) const + { return find_first_not_of(s, pos, Traits::length(s)); } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to any character within the first n + //! characters of s. + size_type find_first_not_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos > size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const_iterator result = std::find_if(this->priv_addr() + pos, finish, + Not_within_traits(s, s + n)); + return result != finish ? result - this->priv_addr() : npos; + } + } + + //! Effects: Searches within *this, beginning at pos, for the first + //! character that is not equal to c. + size_type find_first_not_of(CharT c, size_type pos = 0) const + { + if (pos > size()) + return npos; + else { + pointer finish = this->priv_addr() + this->priv_size(); + const_iterator result + = std::find_if(this->priv_addr() + pos, finish, + std::not1(std::bind2nd(Eq_traits(), c))); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is not equal to any character within s. + size_type find_last_not_of(const basic_string& s, + size_type pos = npos) const + { return find_last_not_of(s.c_str(), pos, s.size()); } + + //! Effects: Searches backward *this, beginning at min(pos, size()), + //! for the first character that is not equal to any character within s. + size_type find_last_not_of(const CharT* s, size_type pos = npos) const + { return find_last_not_of(s, pos, Traits::length(s)); } + + //! Effects: Searches backward within *this, beginning at min(pos, size()), + //! for the first character that is not equal to any character within the first + //! n characters of s. + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + containers_detail::min_value(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + Not_within_traits(s, s + n)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: Searches backward *this, beginning at min(pos, size()), + //! for the first character that is not equal to c. + size_type find_last_not_of(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + containers_detail::min_value(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::not1(std::bind2nd(Eq_traits(), c))); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: Returns a substring of *this. + basic_string substr(size_type pos = 0, size_type n = npos) const + { + if (pos > size()) + this->throw_out_of_range(); + return basic_string(this->priv_addr() + pos, + this->priv_addr() + pos + containers_detail::min_value(n, size() - pos), this->alloc()); + } + + //! Effects: Three-way lexicographical comparison of s and *this. + int compare(const basic_string& s) const + { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s.priv_addr(), s.priv_addr() + s.priv_size()); } + + //! Effects: Three-way lexicographical comparison of s and a substring + //! of *this. + int compare(size_type pos1, size_type n1, const basic_string& s) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return s_compare(this->priv_addr() + pos1, + this->priv_addr() + pos1 + containers_detail::min_value(n1, size() - pos1), + s.priv_addr(), s.priv_addr() + s.priv_size()); + } + + //! Effects: Three-way lexicographical comparison of a substring of s + //! and a substring of *this. + int compare(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) const { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + return s_compare(this->priv_addr() + pos1, + this->priv_addr() + pos1 + containers_detail::min_value(n1, size() - pos1), + s.priv_addr() + pos2, + s.priv_addr() + pos2 + containers_detail::min_value(n2, size() - pos2)); + } + + //! Effects: Three-way lexicographical comparison of s and *this. + int compare(const CharT* s) const + { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s, s + Traits::length(s)); } + + + //! Effects: Three-way lexicographical comparison of the first + //! min(len, traits::length(s) characters of s and a substring of *this. + int compare(size_type pos1, size_type n1, const CharT* s, + size_type n2 = npos) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return s_compare(this->priv_addr() + pos1, + this->priv_addr() + pos1 + containers_detail::min_value(n1, size() - pos1), + s, s + n2); + } + + /// @cond + private: + static int s_compare(const_pointer f1, const_pointer l1, + const_pointer f2, const_pointer l2) + { + const std::ptrdiff_t n1 = l1 - f1; + const std::ptrdiff_t n2 = l2 - f2; + const int cmp = Traits::compare(containers_detail::get_pointer(f1), + containers_detail::get_pointer(f2), + containers_detail::min_value(n1, n2)); + return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); + } + + void priv_construct_null(pointer p) + { this->construct(p, 0); } + + static CharT priv_null() + { return (CharT) 0; } + + // Helper functions used by constructors. It is a severe error for + // any of them to be called anywhere except from within constructors. + void priv_terminate_string() + { this->priv_construct_null(this->priv_addr() + this->priv_size()); } + + template + void priv_range_initialize(InputIter f, InputIter l, + std::input_iterator_tag) + { + this->allocate_initial_block(InternalBufferChars); + this->priv_construct_null(this->priv_addr() + this->priv_size()); + this->append(f, l); + } + + template + void priv_range_initialize(ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + this->allocate_initial_block(containers_detail::max_value(n+1, InternalBufferChars)); + priv_uninitialized_copy(f, l, this->priv_addr()); + this->priv_size(n); + this->priv_terminate_string(); + } + + template + void priv_range_initialize(InputIter f, InputIter l) + { + typedef typename std::iterator_traits::iterator_category Category; + this->priv_range_initialize(f, l, Category()); + } + + template + void priv_initialize_dispatch(Integer n, Integer x, containers_detail::true_) + { + this->allocate_initial_block(containers_detail::max_value(n+1, InternalBufferChars)); + priv_uninitialized_fill_n(this->priv_addr(), n, x); + this->priv_size(n); + this->priv_terminate_string(); + } + + template + void priv_initialize_dispatch(InputIter f, InputIter l, containers_detail::false_) + { this->priv_range_initialize(f, l); } + + template inline + void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val) + { + //Save initial position + FwdIt init = first; + + BOOST_TRY{ + //Construct objects + for (; count--; ++first){ + this->construct(first, val); + } + } + BOOST_CATCH(...){ + //Call destructors + for (; init != first; ++init){ + this->destroy(init); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template inline + size_type priv_uninitialized_copy(InpIt first, InpIt last, FwdIt dest) + { + //Save initial destination position + FwdIt dest_init = dest; + size_type constructed = 0; + + BOOST_TRY{ + //Try to build objects + for (; first != last; ++dest, ++first, ++constructed){ + this->construct(dest, *first); + } + } + BOOST_CATCH(...){ + //Call destructors + for (; constructed--; ++dest_init){ + this->destroy(dest_init); + } + BOOST_RETHROW + } + BOOST_CATCH_END + return (constructed); + } + + template + basic_string& priv_assign_dispatch(Integer n, Integer x, containers_detail::true_) + { return this->assign((size_type) n, (CharT) x); } + + template + basic_string& priv_assign_dispatch(InputIter f, InputIter l, + containers_detail::false_) + { + size_type cur = 0; + CharT *ptr = containers_detail::get_pointer(this->priv_addr()); + while (f != l && cur != this->priv_size()) { + Traits::assign(*ptr, *f); + ++f; + ++cur; + ++ptr; + } + if (f == l) + this->erase(this->priv_addr() + cur, this->priv_addr() + this->priv_size()); + else + this->append(f, l); + return *this; + } + + template + void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) + { + for ( ; first != last; ++first, ++p) { + p = this->insert(p, *first); + } + } + + template + void priv_insert(iterator position, ForwardIter first, + ForwardIter last, std::forward_iterator_tag) + { + if (first != last) { + size_type n = std::distance(first, last); + size_type remaining = this->capacity() - this->priv_size(); + const size_type old_size = this->size(); + pointer old_start = this->priv_addr(); + bool enough_capacity = false; + std::pair allocation_ret; + size_type new_cap = 0; + + //Check if we have enough capacity + if (remaining >= n){ + enough_capacity = true; + } + else { + //Otherwise expand current buffer or allocate new storage + new_cap = this->next_capacity(n); + allocation_ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, + new_cap, new_cap, old_start); + + //Check forward expansion + if(old_start == allocation_ret.first){ + enough_capacity = true; + this->priv_storage(new_cap); + } + } + + //Reuse same buffer + if(enough_capacity){ + const size_type elems_after = + this->priv_size() - (position - this->priv_addr()); + size_type old_length = this->priv_size(); + if (elems_after >= n) { + pointer pointer_past_last = this->priv_addr() + this->priv_size() + 1; + priv_uninitialized_copy(this->priv_addr() + (this->priv_size() - n + 1), + pointer_past_last, pointer_past_last); + + this->priv_size(this->priv_size()+n); + Traits::move(containers_detail::get_pointer(position + n), + containers_detail::get_pointer(position), + (elems_after - n) + 1); + this->priv_copy(first, last, position); + } + else { + ForwardIter mid = first; + std::advance(mid, elems_after + 1); + + priv_uninitialized_copy(mid, last, this->priv_addr() + this->priv_size() + 1); + this->priv_size(this->priv_size() + (n - elems_after)); + priv_uninitialized_copy + (position, this->priv_addr() + old_length + 1, + this->priv_addr() + this->priv_size()); + this->priv_size(this->priv_size() + elems_after); + this->priv_copy(first, mid, position); + } + } + else{ + pointer new_start = allocation_ret.first; + if(!allocation_ret.second){ + //Copy data to new buffer + size_type new_length = 0; + //This can't throw, since characters are POD + new_length += priv_uninitialized_copy + (this->priv_addr(), position, new_start); + new_length += priv_uninitialized_copy + (first, last, new_start + new_length); + new_length += priv_uninitialized_copy + (position, this->priv_addr() + this->priv_size(), + new_start + new_length); + this->priv_construct_null(new_start + new_length); + + this->deallocate_block(); + this->is_short(false); + this->priv_addr(new_start); + this->priv_size(new_length); + this->priv_storage(new_cap); + } + else{ + //value_type is POD, so backwards expansion is much easier + //than with vector + value_type *oldbuf = containers_detail::get_pointer(old_start); + value_type *newbuf = containers_detail::get_pointer(new_start); + value_type *pos = containers_detail::get_pointer(position); + size_type before = pos - oldbuf; + + //First move old data + Traits::move(newbuf, oldbuf, before); + Traits::move(newbuf + before + n, pos, old_size - before); + //Now initialize the new data + priv_uninitialized_copy(first, last, new_start + before); + this->priv_construct_null(new_start + (old_size + n)); + this->is_short(false); + this->priv_addr(new_start); + this->priv_size(old_size + n); + this->priv_storage(new_cap); + } + } + } + } + + template + void priv_insert_dispatch(iterator p, Integer n, Integer x, + containers_detail::true_) + { insert(p, (size_type) n, (CharT) x); } + + template + void priv_insert_dispatch(iterator p, InputIter first, InputIter last, + containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + priv_insert(p, first, last, Category()); + } + + template + void priv_copy(InputIterator first, InputIterator last, iterator result) + { + for ( ; first != last; ++first, ++result) + Traits::assign(*result, *first); + } + + void priv_copy(const CharT* first, const CharT* last, CharT* result) + { Traits::copy(result, first, last - first); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + Integer n, Integer x, + containers_detail::true_) + { return this->replace(first, last, (size_type) n, (CharT) x); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + InputIter f, InputIter l, + containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + return this->priv_replace(first, last, f, l, Category()); + } + + + template + basic_string& priv_replace(iterator first, iterator last, + InputIter f, InputIter l, std::input_iterator_tag) + { + for ( ; first != last && f != l; ++first, ++f) + Traits::assign(*first, *f); + + if (f == l) + this->erase(first, last); + else + this->insert(last, f, l); + return *this; + } + + template + basic_string& priv_replace(iterator first, iterator last, + ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + const difference_type len = last - first; + if (len >= n) { + this->priv_copy(f, l, first); + this->erase(first + n, last); + } + else { + ForwardIter m = f; + std::advance(m, len); + this->priv_copy(f, m, first); + this->insert(last, m, l); + } + return *this; + } + /// @endcond +}; + +/// @cond + +template +const typename basic_string::size_type +basic_string::npos + = (typename basic_string::size_type) -1; + +/// @endcond + +// ------------------------------------------------------------ +// Non-member functions. + +// Operator+ + +template +inline basic_string +operator+(const basic_string& x, + const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + y.size(), x.alloc()); + result.append(x); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) + operator+( + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const basic_string& y) +{ + mx += y; + return boost::interprocess::move(mx); +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) + operator+(const basic_string& x, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return my.replace(size_type(0), size_type(0), x); +} + +template +inline basic_string +operator+(const CharT* s, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, n + y.size()); + result.append(s, s + n); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(const CharT* s, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return boost::interprocess::move(my.get().replace(size_type(0), size_type(0), s)); +} + +template +inline basic_string +operator+(CharT c, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, 1 + y.size()); + result.push_back(c); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(CharT c, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return my.replace(size_type(0), size_type(0), &c, &c + 1); +} + +template +inline basic_string +operator+(const basic_string& x, const CharT* s) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, x.size() + n, x.alloc()); + result.append(x); + result.append(s, s + n); + return result; +} + +template +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const CharT* s) +{ + mx += s; + return boost::interprocess::move(mx); +} + +template +inline basic_string +operator+(const basic_string& x, const CharT c) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + 1, x.alloc()); + result.append(x); + result.push_back(c); + return result; +} + +template +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+( BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const CharT c) +{ + mx += c; + return boost::interprocess::move(mx); +} + +// Operator== and operator!= + +template +inline bool +operator==(const basic_string& x, + const basic_string& y) +{ + return x.size() == y.size() && + Traits::compare(x.data(), y.data(), x.size()) == 0; +} + +template +inline bool +operator==(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return n == y.size() && Traits::compare(s, y.data(), n) == 0; +} + +template +inline bool +operator==(const basic_string& x, const CharT* s) +{ + std::size_t n = Traits::length(s); + return x.size() == n && Traits::compare(x.data(), s, n) == 0; +} + +template +inline bool +operator!=(const basic_string& x, + const basic_string& y) + { return !(x == y); } + +template +inline bool +operator!=(const CharT* s, const basic_string& y) + { return !(s == y); } + +template +inline bool +operator!=(const basic_string& x, const CharT* s) + { return !(x == s); } + + +// Operator< (and also >, <=, and >=). + +template +inline bool +operator<(const basic_string& x, const basic_string& y) +{ + return x.compare(y) < 0; +// return basic_string +// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const CharT* s, const basic_string& y) +{ + return y.compare(s) > 0; +// std::size_t n = Traits::length(s); +// return basic_string +// ::s_compare(s, s + n, y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const basic_string& x, + const CharT* s) +{ + return x.compare(s) < 0; +// std::size_t n = Traits::length(s); +// return basic_string +// ::s_compare(x.begin(), x.end(), s, s + n) < 0; +} + +template +inline bool +operator>(const basic_string& x, + const basic_string& y) { + return y < x; +} + +template +inline bool +operator>(const CharT* s, const basic_string& y) { + return y < s; +} + +template +inline bool +operator>(const basic_string& x, const CharT* s) +{ + return s < x; +} + +template +inline bool +operator<=(const basic_string& x, + const basic_string& y) +{ + return !(y < x); +} + +template +inline bool +operator<=(const CharT* s, const basic_string& y) + { return !(y < s); } + +template +inline bool +operator<=(const basic_string& x, const CharT* s) + { return !(s < x); } + +template +inline bool +operator>=(const basic_string& x, + const basic_string& y) + { return !(x < y); } + +template +inline bool +operator>=(const CharT* s, const basic_string& y) + { return !(s < y); } + +template +inline bool +operator>=(const basic_string& x, const CharT* s) + { return !(x < s); } + +// Swap. +template +inline void swap(basic_string& x, basic_string& y) +{ x.swap(y); } + +/// @cond +// I/O. +namespace containers_detail { + +template +inline bool +string_fill(std::basic_ostream& os, + std::basic_streambuf* buf, + std::size_t n) +{ + CharT f = os.fill(); + std::size_t i; + bool ok = true; + + for (i = 0; i < n; i++) + ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); + return ok; +} + +} //namespace containers_detail { +/// @endcond + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& s) +{ + typename std::basic_ostream::sentry sentry(os); + bool ok = false; + + if (sentry) { + ok = true; + std::size_t n = s.size(); + std::size_t pad_len = 0; + const bool left = (os.flags() & std::ios::left) != 0; + const std::size_t w = os.width(0); + std::basic_streambuf* buf = os.rdbuf(); + + if (w != 0 && n < w) + pad_len = w - n; + + if (!left) + ok = containers_detail::string_fill(os, buf, pad_len); + + ok = ok && + buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); + + if (left) + ok = ok && containers_detail::string_fill(os, buf, pad_len); + } + + if (!ok) + os.setstate(std::ios_base::failbit); + + return os; +} + + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& s) +{ + typename std::basic_istream::sentry sentry(is); + + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + const std::ctype& ctype = std::use_facet >(is.getloc()); + + s.clear(); + std::size_t n = is.width(0); + if (n == 0) + n = static_cast(-1); + else + s.reserve(n); + + while (n-- > 0) { + typename Traits::int_type c1 = buf->sbumpc(); + + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + CharT c = Traits::to_char_type(c1); + + if (ctype.is(std::ctype::space, c)) { + if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) + is.setstate(std::ios_base::failbit); + break; + } + else + s.push_back(c); + } + } + + // If we have read no characters, then set failbit. + if (s.size() == 0) + is.setstate(std::ios_base::failbit); + } + else + is.setstate(std::ios_base::failbit); + + return is; +} + +template +std::basic_istream& +getline(std::istream& is, basic_string& s,CharT delim) +{ + std::size_t nread = 0; + typename std::basic_istream::sentry sentry(is, true); + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + s.clear(); + + int c1; + while (nread < s.max_size()) { + int c1 = buf->sbumpc(); + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + ++nread; + CharT c = Traits::to_char_type(c1); + if (!Traits::eq(c, delim)) + s.push_back(c); + else + break; // Character is extracted but not appended. + } + } + } + if (nread == 0 || nread >= s.max_size()) + is.setstate(std::ios_base::failbit); + + return is; +} + +template +inline std::basic_istream& +getline(std::basic_istream& is, basic_string& s) +{ + return getline(is, s, '\n'); +} + +template +inline std::size_t hash_value(basic_string, A> const& v) +{ + return hash_range(v.begin(), v.end()); +} + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +}} + +/// @endcond + +#include + +#endif // BOOST_CONTAINERS_STRING_HPP diff --git a/include/boost/interprocess/containers/container/vector.hpp b/include/boost/interprocess/containers/container/vector.hpp new file mode 100644 index 0000000..4c38e25 --- /dev/null +++ b/include/boost/interprocess/containers/container/vector.hpp @@ -0,0 +1,1933 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's stl_vector.h file. Modified by Ion Gaztanaga. +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +// +// +// Copyright (c) 1996 +// Silicon Graphics Computer Systems, Inc. +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Silicon Graphics makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. + +#ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP +#define BOOST_CONTAINERS_CONTAINERS_VECTOR_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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace containers_detail { + +//! Const vector_iterator used to iterate through a vector. +template +class vector_const_iterator + : public std::iterator::value_type + ,typename std::iterator_traits::difference_type + ,typename boost::pointer_to_other + ::value_type + >::type + ,const typename std::iterator_traits::value_type &> +{ + public: + typedef const typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename boost::pointer_to_other::type pointer; + typedef value_type& reference; + + /// @cond + protected: + Pointer m_ptr; + + public: + Pointer get_ptr() const { return m_ptr; } + explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){} + /// @endcond + + public: + + //Constructors + vector_const_iterator() : m_ptr(0){} + + //Pointer like operators + reference operator*() const + { return *m_ptr; } + + const value_type * operator->() const + { return containers_detail::get_pointer(m_ptr); } + + reference operator[](difference_type off) const + { return m_ptr[off]; } + + //Increment / Decrement + vector_const_iterator& operator++() + { ++m_ptr; return *this; } + + vector_const_iterator operator++(int) + { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } + + vector_const_iterator& operator--() + { --m_ptr; return *this; } + + vector_const_iterator operator--(int) + { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } + + //Arithmetic + vector_const_iterator& operator+=(difference_type off) + { m_ptr += off; return *this; } + + vector_const_iterator operator+(difference_type off) const + { return vector_const_iterator(m_ptr+off); } + + friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) + { return vector_const_iterator(off + right.m_ptr); } + + vector_const_iterator& operator-=(difference_type off) + { m_ptr -= off; return *this; } + + vector_const_iterator operator-(difference_type off) const + { return vector_const_iterator(m_ptr-off); } + + difference_type operator-(const vector_const_iterator& right) const + { return m_ptr - right.m_ptr; } + + //Comparison operators + bool operator== (const vector_const_iterator& r) const + { return m_ptr == r.m_ptr; } + + bool operator!= (const vector_const_iterator& r) const + { return m_ptr != r.m_ptr; } + + bool operator< (const vector_const_iterator& r) const + { return m_ptr < r.m_ptr; } + + bool operator<= (const vector_const_iterator& r) const + { return m_ptr <= r.m_ptr; } + + bool operator> (const vector_const_iterator& r) const + { return m_ptr > r.m_ptr; } + + bool operator>= (const vector_const_iterator& r) const + { return m_ptr >= r.m_ptr; } +}; + +//! Iterator used to iterate through a vector +template +class vector_iterator + : public vector_const_iterator +{ + public: + explicit vector_iterator(Pointer ptr) + : vector_const_iterator(ptr) + {} + + public: + typedef typename std::iterator_traits::value_type value_type; + typedef typename vector_const_iterator::difference_type difference_type; + typedef Pointer pointer; + typedef value_type& reference; + + //Constructors + vector_iterator() + {} + + //Pointer like operators + reference operator*() const + { return *this->m_ptr; } + + value_type* operator->() const + { return containers_detail::get_pointer(this->m_ptr); } + + reference operator[](difference_type off) const + { return this->m_ptr[off]; } + + //Increment / Decrement + vector_iterator& operator++() + { ++this->m_ptr; return *this; } + + vector_iterator operator++(int) + { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } + + vector_iterator& operator--() + { --this->m_ptr; return *this; } + + vector_iterator operator--(int) + { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } + + // Arithmetic + vector_iterator& operator+=(difference_type off) + { this->m_ptr += off; return *this; } + + vector_iterator operator+(difference_type off) const + { return vector_iterator(this->m_ptr+off); } + + friend vector_iterator operator+(difference_type off, const vector_iterator& right) + { return vector_iterator(off + right.m_ptr); } + + vector_iterator& operator-=(difference_type off) + { this->m_ptr -= off; return *this; } + + vector_iterator operator-(difference_type off) const + { return vector_iterator(this->m_ptr-off); } + + difference_type operator-(const vector_const_iterator& right) const + { return static_cast&>(*this) - right; } +}; + +template +struct vector_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + boost::interprocess::has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::value; + + //This is the anti-exception array destructor + //to deallocate values already constructed + typedef typename containers_detail::if_c + + ,containers_detail::scoped_destructor_n + >::type OldArrayDestructor; + //This is the anti-exception array destructor + //to destroy objects created with copy construction + typedef typename containers_detail::if_c + + ,containers_detail::scoped_destructor_n + >::type UCopiedArrayDestructor; + //This is the anti-exception array deallocator + typedef typename containers_detail::if_c + + ,containers_detail::scoped_array_deallocator + >::type UCopiedArrayDeallocator; +}; + +//!This struct deallocates and allocated memory +template +struct vector_alloc_holder +{ + typedef typename A::pointer pointer; + typedef typename A::size_type size_type; + typedef typename A::value_type value_type; + typedef vector_value_traits value_traits; + + //Constructor, does not throw + vector_alloc_holder(const A &a) + : members_(a) + {} + + //Constructor, does not throw + vector_alloc_holder(const vector_alloc_holder &h) + : members_(h.alloc()) + {} + + //Destructor + ~vector_alloc_holder() + { + this->prot_destroy_all(); + this->prot_deallocate(); + } + + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + return allocation_command(command, limit_size, preferred_size, + received_size, reuse, alloc_version()); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + (void)limit_size; + (void)reuse; + if(!(command & allocate_new)) + return std::pair(pointer(0), 0); + received_size = preferred_size; + return std::make_pair(this->alloc().allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v2) + { + return this->alloc().allocation_command + (command, limit_size, preferred_size, received_size, reuse); + } + + size_type next_capacity(size_type additional_objects) const + { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); } + + struct members_holder + : public A + { + private: + members_holder(const members_holder&); + + public: + members_holder(const A &alloc) + : A(alloc), m_start(0), m_size(0), m_capacity(0) + {} + + pointer m_start; + size_type m_size; + size_type m_capacity; + } members_; + + protected: + void prot_deallocate() + { + if(!this->members_.m_capacity) return; + this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + this->members_.m_start = 0; + this->members_.m_size = 0; + this->members_.m_capacity = 0; + } + + void destroy(value_type* p) + { + if(!value_traits::trivial_dctr) + containers_detail::get_pointer(p)->~value_type(); + } + + void destroy_n(value_type* p, size_type n) + { + if(!value_traits::trivial_dctr) + for(; n--; ++p) p->~value_type(); + } + + void prot_destroy_all() + { + this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); + this->members_.m_size = 0; + } + + A &alloc() + { return members_; } + + const A &alloc() const + { return members_; } +}; + +} //namespace containers_detail { +/// @endcond + +//! \class ::boost::interprocess::vector boost/interprocess/containers/container/vector.hpp +//! A vector is a sequence that supports random access to elements, constant +//! time insertion and removal of elements at the end, and linear time insertion +//! and removal of elements at the beginning or in the middle. The number of +//! elements in a vector may vary dynamically; memory management is automatic. +//! boost::interprocess_container::vector is similar to std::vector but it's compatible +//! with shared memory and memory mapped files. +template +class vector : private containers_detail::vector_alloc_holder +{ + /// @cond + typedef vector self_t; + typedef containers_detail::vector_alloc_holder base_t; + /// @endcond + public: + //! The type of object, T, stored in the vector + typedef T value_type; + //! Pointer to T + typedef typename A::pointer pointer; + //! Const pointer to T + typedef typename A::const_pointer const_pointer; + //! Reference to T + typedef typename A::reference reference; + //! Const reference to T + typedef typename A::const_reference const_reference; + //! An unsigned integral type + typedef typename A::size_type size_type; + //! A signed integral type + typedef typename A::difference_type difference_type; + //! The allocator type + typedef A allocator_type; + //! The random access iterator + typedef containers_detail::vector_iterator iterator; + //! The random access const_iterator + typedef containers_detail::vector_const_iterator const_iterator; + + //! Iterator used to iterate backwards through a vector. + typedef std::reverse_iterator + reverse_iterator; + //! Const iterator used to iterate backwards through a vector. + typedef std::reverse_iterator + const_reverse_iterator; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + + /// @cond + private: + typedef containers_detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef containers_detail::vector_value_traits value_traits; + + typedef typename base_t::allocator_v1 allocator_v1; + typedef typename base_t::allocator_v2 allocator_v2; + typedef typename base_t::alloc_version alloc_version; + + typedef constant_iterator cvalue_iterator; + typedef repeat_iterator repeat_it; + typedef boost::interprocess::move_iterator repeat_move_it; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(vector) + + //! Effects: Constructs a vector taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit vector(const A& a = A()) + : base_t(a) + {} + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n default contructed values. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n) + : base_t(allocator_type()) + { this->resize(n); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n, const T& value, const allocator_type& a = allocator_type()) + : base_t(a) + { this->insert(this->cend(), n, value); } + + //! Effects: Copy constructs a vector. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + vector(const vector& x) + : base_t((base_t&)x) + { *this = x; } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + vector(BOOST_INTERPROCESS_RV_REF(vector) mx) + : base_t(boost::interprocess::move(mx)) + { this->swap(mx); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the vector. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + vector(InIt first, InIt last, const allocator_type& a = allocator_type()) + : base_t(a) + { this->assign(first, last); } + + //! Effects: Destroys the vector. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~vector() + {} //vector_alloc_holder clears the data + + //! Effects: Returns an iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns an iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(this->end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin()const + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(this->begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin()const + { return const_reverse_iterator(this->end());} + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->begin()); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + pointer data() + { return this->members_.m_start; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_pointer data() const + { return this->members_.m_start; } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->members_.m_size; } + + //! Effects: Returns the largest possible size of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return this->alloc().max_size(); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return this->members_.m_capacity; } + + //! Effects: Returns true if the vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->members_.m_size; } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const + { return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return this->alloc(); } + + const stored_allocator_type &get_stored_allocator() const + { return this->alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->alloc(); } + + //! Effects: If n is less than or equal to capacity(), this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + void reserve(size_type new_cap) + { + if (this->capacity() < new_cap){ + //There is not enough memory, allocate a new + //buffer or expand the old one. + bool same_buffer_start; + size_type real_cap = 0; + std::pair ret = + this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + new_cap, new_cap, real_cap, this->members_.m_start); + + //Check for forward expansion + same_buffer_start = ret.second && this->members_.m_start == ret.first; + if(same_buffer_start){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->members_.m_capacity = real_cap; + } + + //If there is no forward expansion, move objects + else{ + //We will reuse insert code, so create a dummy input iterator + T *dummy_it(containers_detail::get_pointer(this->members_.m_start)); + containers_detail::advanced_insert_aux_proxy, T*> + proxy(boost::interprocess::make_move_iterator(dummy_it), boost::interprocess::make_move_iterator(dummy_it)); + //Backwards (and possibly forward) expansion + if(ret.second){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(this->members_.m_start) + , 0 + , proxy); + } + //New buffer + else{ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(this->members_.m_start) + , 0 + , proxy); + } + } + } + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + vector& operator=(const vector& x) + { + if (&x != this){ + this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + vector& operator=(BOOST_INTERPROCESS_RV_REF(vector) x) + { + if (&x != this){ + this->swap(x); + x.clear(); + } + return *this; + } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const value_type& val) + { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Inserts a copy of x at the end of the vector. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T& x) + { + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); + ++this->members_.m_size; + } + else{ + this->insert(this->cend(), x); + } + } + + //! Effects: Constructs a new element in the end of the vector + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(BOOST_INTERPROCESS_RV_REF(T) x) + { + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)containers_detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(boost::interprocess::move(x)); + ++this->members_.m_size; + } + else{ + this->insert(this->cend(), boost::interprocess::move(x)); + } + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)(back_pos))value_type(boost::interprocess::forward(args)...); + ++this->members_.m_size; + } + else{ + containers_detail::advanced_insert_aux_emplace proxy + (boost::interprocess::forward(args)...); + priv_range_insert(back_pos, 1, proxy); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy + (boost::interprocess::forward(args)...); + priv_range_insert(position.get_ptr(), 1, proxy); + return iterator(this->members_.m_start + pos_n); + } + + #else + + void emplace_back() + { + T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + if (this->members_.m_size < this->members_.m_capacity){ + //There is more memory, just construct a new object at the end + new((void*)(back_pos))value_type(); + ++this->members_.m_size; + } + else{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_range_insert(back_pos, 1, proxy); + } + } + + iterator emplace(const_iterator position) + { + size_type pos_n = position - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy; + priv_range_insert(containers_detail::get_pointer(position.get_ptr()), 1, proxy); + return iterator(this->members_.m_start + pos_n); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + T* back_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; \ + if (this->members_.m_size < this->members_.m_capacity){ \ + new((void*)(back_pos))value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + ++this->members_.m_size; \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(back_pos, 1, proxy); \ + } \ + } \ + \ + template \ + iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + size_type pos_n = pos - cbegin(); \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(containers_detail::get_pointer(pos.get_ptr()), 1, proxy); \ + return iterator(this->members_.m_start + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(vector& x) + { + allocator_type &this_al = this->alloc(), &other_al = x.alloc(); + //Just swap internals + containers_detail::do_swap(this->members_.m_start, x.members_.m_start); + containers_detail::do_swap(this->members_.m_size, x.members_.m_size); + containers_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); + + if (this_al != other_al){ + containers_detail::do_swap(this_al, other_al); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before position. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, const T& x) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + this->insert(position, (size_type)1, x); + return iterator(this->members_.m_start + pos_n); + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a new element before position with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + this->insert(position + ,repeat_move_it(repeat_it(x, 1)) + ,repeat_move_it(repeat_it())); + return iterator(this->members_.m_start + pos_n); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + void insert(const_iterator pos, InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void insert(const_iterator p, size_type n, const T& x) + { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + + //! Effects: Removes the last element from the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() + { + //Destroy last element + --this->members_.m_size; + this->destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + } + + //! Effects: Erases the element at position pos. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements between pos and the + //! last element. Constant if pos is the first or the last element. + iterator erase(const_iterator position) + { + T *pos = containers_detail::get_pointer(position.get_ptr()); + T *beg = containers_detail::get_pointer(this->members_.m_start); + boost::interprocess::move(pos + 1, beg + this->members_.m_size, pos); + --this->members_.m_size; + //Destroy last element + base_t::destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + return iterator(position.get_ptr()); + } + + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and last. + iterator erase(const_iterator first, const_iterator last) + { + if (first != last){ // worth doing, copy down over hole + T* end_pos = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + T* ptr = containers_detail::get_pointer(boost::interprocess::move + (containers_detail::get_pointer(last.get_ptr()) + ,end_pos + ,containers_detail::get_pointer(first.get_ptr()) + )); + size_type destroyed = (end_pos - ptr); + this->destroy_n(ptr, destroyed); + this->members_.m_size -= destroyed; + } + return iterator(first.get_ptr()); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const T& x) + { + pointer finish = this->members_.m_start + this->members_.m_size; + if (new_size < size()){ + //Destroy last elements + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + } + else{ + //Insert new elements at the end + this->insert(const_iterator(finish), new_size - this->size(), x); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + if (new_size < this->size()){ + //Destroy last elements + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + } + else{ + size_type n = new_size - this->size(); + this->reserve(new_size); + containers_detail::default_construct_aux_proxy proxy(n); + priv_range_insert(this->cend().get_ptr(), n, proxy); + } + } + + //! Effects: Erases all the elements of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the vector. + void clear() + { this->prot_destroy_all(); } + + /// @cond + + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { priv_shrink_to_fit(alloc_version()); } + + private: + void priv_shrink_to_fit(allocator_v1) + { + if(this->members_.m_capacity){ + if(!size()){ + this->prot_deallocate(); + } + else{ + //This would not work with stateful allocators + vector(*this).swap(*this); + } + } + } + + void priv_shrink_to_fit(allocator_v2) + { + if(this->members_.m_capacity){ + if(!size()){ + this->prot_deallocate(); + } + else{ + size_type received_size; + 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_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_shrink; + #endif + } + } + } + } + + template + void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) + { + if(first != last){ + const size_type n = std::distance(first, last); + containers_detail::advanced_insert_aux_proxy proxy(first, last); + priv_range_insert(pos, n, proxy); + } + } + + void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) + { + //Check if we have enough memory or try to expand current memory + size_type remaining = this->members_.m_capacity - this->members_.m_size; + bool same_buffer_start; + std::pair ret; + size_type real_cap = this->members_.m_capacity; + + //Check if we already have room + if (n <= remaining){ + same_buffer_start = true; + } + else{ + //There is not enough memory, allocate a new + //buffer or expand the old one. + size_type new_cap = this->next_capacity(n); + ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->members_.m_size + n, new_cap, real_cap, this->members_.m_start); + + //Check for forward expansion + same_buffer_start = ret.second && this->members_.m_start == ret.first; + if(same_buffer_start){ + this->members_.m_capacity = real_cap; + } + } + + //If we had room or we have expanded forward + if (same_buffer_start){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->priv_range_insert_expand_forward + (containers_detail::get_pointer(pos), n, interf); + } + //Backwards (and possibly forward) expansion + else if(ret.second){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(pos) + , n + , interf); + } + //New buffer + else{ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(pos) + , n + , interf); + } + } + + void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf) + { + //There is enough memory + T* old_finish = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + const size_type elems_after = old_finish - pos; + + if (elems_after > n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + boost::interprocess::uninitialized_move(old_finish - n, old_finish, old_finish); + this->members_.m_size += n; + //Copy previous to last objects to the initialized end + boost::interprocess::move_backward(pos, old_finish - n, old_finish); + //Insert new objects in the pos + interf.copy_all_to(pos); + } + else { + //The new elements don't fit in the [pos, end()) range. Copy + //to the beginning of the unallocated zone the last new elements. + interf.uninitialized_copy_some_and_update(old_finish, elems_after, false); + this->members_.m_size += n - elems_after; + //Copy old [pos, end()) elements to the uninitialized memory + boost::interprocess::uninitialized_move + ( pos, old_finish, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + this->members_.m_size += elems_after; + //Copy first new elements in pos + interf.copy_all_to(pos); + } + } + + void priv_range_insert_new_allocation + (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf) + { + T* new_finish = new_start; + T *old_finish; + //Anti-exception rollbacks + typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); + typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u); + + //Initialize with [begin(), pos) old buffer + //the start of the new buffer + new_finish = boost::interprocess::uninitialized_move + (containers_detail::get_pointer(this->members_.m_start), pos, old_finish = new_finish); + constructed_values_destroyer.increment_size(new_finish - old_finish); + //Initialize new objects, starting from previous point + interf.uninitialized_copy_all_to(old_finish = new_finish); + new_finish += n; + constructed_values_destroyer.increment_size(new_finish - old_finish); + //Initialize from the rest of the old buffer, + //starting from previous point + new_finish = boost::interprocess::uninitialized_move + ( pos, containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size, new_finish); + //All construction successful, disable rollbacks + constructed_values_destroyer.release(); + scoped_alloc.release(); + //Destroy and deallocate old elements + //If there is allocated memory, destroy and deallocate + if(this->members_.m_start != 0){ + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); + this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + } + this->members_.m_start = new_start; + this->members_.m_size = new_finish - new_start; + this->members_.m_capacity = new_cap; + } + + void priv_range_insert_expand_backwards + (T* new_start, size_type new_capacity, + T* pos, const size_type n, advanced_insert_aux_int_t &interf) + { + //Backup old data + T* old_start = containers_detail::get_pointer(this->members_.m_start); + T* old_finish = old_start + this->members_.m_size; + size_type old_size = this->members_.m_size; + + //We can have 8 possibilities: + const size_type elemsbefore = (size_type)(pos - old_start); + const size_type s_before = (size_type)(old_start - new_start); + + //Update the vector buffer information to a safe state + this->members_.m_start = new_start; + this->members_.m_capacity = new_capacity; + this->members_.m_size = 0; + + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); + //Check if s_before is big enough to hold the beginning of old data + new data + if(difference_type(s_before) >= difference_type(elemsbefore + n)){ + //Copy first old values before pos, after that the new objects + boost::interprocess::uninitialized_move(old_start, pos, new_start); + this->members_.m_size = elemsbefore; + interf.uninitialized_copy_all_to(new_start + elemsbefore); + this->members_.m_size += n; + //Check if s_before is so big that even copying the old data + new data + //there is a gap between the new data and the old data + if(s_before >= (old_size + n)){ + //Old situation: + // _________________________________________________________ + //| raw_mem | old_begin | old_end | + //| __________________________________|___________|_________| + // + //New situation: + // _________________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|________________________| + // + //Now initialize the rest of memory with the last old values + boost::interprocess::uninitialized_move + (pos, old_finish, new_start + elemsbefore + n); + //All new elements correctly constructed, avoid new element destruction + this->members_.m_size = old_size + n; + //Old values destroyed automatically with "old_values_destroyer" + //when "old_values_destroyer" goes out of scope unless the have trivial + //destructor after move. + if(value_traits::trivial_dctr_after_move) + old_values_destroyer.release(); + } + //s_before is so big that divides old_end + else{ + //Old situation: + // __________________________________________________ + //| raw_mem | old_begin | old_end | + //| ___________________________|___________|_________| + // + //New situation: + // __________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|_________________| + // + //Now initialize the rest of memory with the last old values + //All new elements correctly constructed, avoid new element destruction + size_type raw_gap = s_before - (elemsbefore + n); + //Now initialize the rest of s_before memory with the + //first of elements after new values + boost::interprocess::uninitialized_move(pos, pos + raw_gap, new_start + elemsbefore + n); + //Update size since we have a contiguous buffer + this->members_.m_size = old_size + s_before; + //All new elements correctly constructed, avoid old element destruction + old_values_destroyer.release(); + //Now copy remaining last objects in the old buffer begin + T *to_destroy = boost::interprocess::move(pos + raw_gap, 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; + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(to_destroy, n_destroy); + this->members_.m_size -= n_destroy; + } + } + else{ + //Check if we have to do the insertion in two phases + //since maybe s_before is not big enough and + //the buffer was expanded both sides + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin + old_end | raw_mem | + //|_________|_____________________|_________________| + // + //New situation with do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|___________________________________|_____________| + // + //New without do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|____________________________|____________________| + // + bool do_after = n > s_before; + + //Now we can have two situations: the raw_mem of the + //beginning divides the old_begin, or the new elements: + if (s_before <= elemsbefore) { + //The raw memory divides the old_begin group: + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_________|___________|_________|_________________| + // + //New situation with do_after(1): + //This is not definitive situation, the second phase + //will include + // _________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_________|_________|_________________| + // + //New situation without do_after: + // _________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|_____________________| + // + //Copy the first part of old_begin to raw_mem + T *start_n = old_start + difference_type(s_before); + boost::interprocess::uninitialized_move(old_start, 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 = boost::interprocess::move(start_n, pos, old_start); + if(do_after){ + //Now copy the new_beg elements + interf.copy_some_and_update(next, s_before, true); + } + else{ + //Now copy the all the new elements + interf.copy_all_to(next); + T* move_start = next + n; + //Now displace old_end elements + T* move_end = boost::interprocess::move(pos, 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; + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(move_end, n_destroy); + this->members_.m_size -= n_destroy; + } + } + else { + //If we have to expand both sides, + //we will play if the first new values so + //calculate the upper bound of new values + + //The raw memory divides the new elements + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_______________|___________|_________|_________________| + // + //New situation with do_after(): + // ____________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_______________|_________|______________| + // + //New situation without do_after: + // ______________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|__________________________| + // + //First copy whole old_begin and part of new to raw_mem + boost::interprocess::uninitialized_move(old_start, pos, new_start); + this->members_.m_size = elemsbefore; + + const size_type mid_n = difference_type(s_before) - elemsbefore; + interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true); + this->members_.m_size = old_size + s_before; + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + + if(do_after){ + //Copy new_beg part + interf.copy_some_and_update(old_start, s_before - mid_n, true); + } + else{ + //Copy all new elements + interf.copy_all_to(old_start); + T* move_start = old_start + (n-mid_n); + //Displace old_end + T* move_end = boost::interprocess::move(pos, 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; + if(!value_traits::trivial_dctr_after_move) + this->destroy_n(move_end, n_destroy); + this->members_.m_size -= n_destroy; + } + } + + //This is only executed if two phase construction is needed + //This can be executed without exception handling since we + //have to just copy and append in raw memory and + //old_values_destroyer has been released in phase 1. + if(do_after){ + //The raw memory divides the new elements + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //New situation with do_after(2): + // ______________________________________________________ + //| old_begin + new | old_end |raw | + //|_______________________________________|_________|____| + // + const size_type n_after = n - s_before; + const difference_type elemsafter = old_size - elemsbefore; + + //We can have two situations: + if (elemsafter > difference_type(n_after)){ + //The raw_mem from end will divide displaced old_end + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //First copy the part of old_end raw_mem + T* finish_n = old_finish - difference_type(n_after); + boost::interprocess::uninitialized_move(finish_n, old_finish, old_finish); + this->members_.m_size += n_after; + //Displace the rest of old_end to the new position + boost::interprocess::move_backward(pos, finish_n, old_finish); + //Now overwrite with new_end + //The new_end part is [first + (n - n_after), last) + interf.copy_all_to(pos); + } + else { + //The raw_mem from end will divide new_end part + // + //Old situation: + // _____________________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|_____________________| + // + //New situation with do_after(2): + // _____________________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_______________|________|_________| + // + size_type mid_last_dist = n_after - elemsafter; + //First initialize data in raw memory + //The new_end part is [first + (n - n_after), last) + interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); + this->members_.m_size += mid_last_dist; + boost::interprocess::uninitialized_move(pos, old_finish, old_finish + mid_last_dist); + this->members_.m_size += n_after - mid_last_dist; + //Now copy the part of new_end over constructed elements + interf.copy_all_to(pos); + } + } + } + } + + template + void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, boost::interprocess::move(value_type(*first))); + } + } + + template + void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) + { + //Overwrite all elements we can from [first, last) + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first){ + *cur = *first; + } + + if (first == last){ + //There are no more elements in the sequence, erase remaining + this->erase(cur, cend()); + } + else{ + //There are more elements in the range, insert the remaining ones + this->insert(this->cend(), first, last); + } + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = std::distance(first, last); + //Check if we have enough memory or try to expand current memory + size_type remaining = this->members_.m_capacity - this->members_.m_size; + bool same_buffer_start; + std::pair ret; + size_type real_cap = this->members_.m_capacity; + + if (n <= remaining){ + same_buffer_start = true; + } + else{ + //There is not enough memory, allocate a new buffer + size_type new_cap = this->next_capacity(n); + ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->size() + n, new_cap, real_cap, this->members_.m_start); + same_buffer_start = ret.second && this->members_.m_start == ret.first; + if(same_buffer_start){ + this->members_.m_capacity = real_cap; + } + } + + if(same_buffer_start){ + T *start = containers_detail::get_pointer(this->members_.m_start); + if (this->size() >= n){ + //There is memory, but there are more old elements than new ones + //Overwrite old elements with new ones + // iG std::copy(first, last, start); + std::copy(first, last, start); + //Destroy remaining old elements + this->destroy_n(start + n, this->members_.m_size - n); + this->members_.m_size = n; + } + else{ + //There is memory, but there are less old elements than new ones + //First overwrite some old elements with new ones + FwdIt mid = first; + std::advance(mid, this->size()); + // iG T *end = std::copy(first, mid, start); + T *end = std::copy(first, mid, start); + //Initialize the remaining new elements in the uninitialized memory + // iG std::uninitialized_copy(mid, last, end); + boost::interprocess::uninitialized_copy_or_move(mid, last, end); + this->members_.m_size = n; + } + } + else if(!ret.second){ + typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); + // iG std::uninitialized_copy(first, last, containers_detail::get_pointer(ret.first)); + boost::interprocess::uninitialized_copy_or_move(first, last, containers_detail::get_pointer(ret.first)); + scoped_alloc.release(); + //Destroy and deallocate old buffer + if(this->members_.m_start != 0){ + this->destroy_n(containers_detail::get_pointer(this->members_.m_start), this->members_.m_size); + this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + } + this->members_.m_start = ret.first; + this->members_.m_size = n; + this->members_.m_capacity = real_cap; + } + else{ + //Backwards expansion + //If anything goes wrong, this object will destroy old objects + T *old_start = containers_detail::get_pointer(this->members_.m_start); + size_type old_size = this->members_.m_size; + typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); + //If something goes wrong size will be 0 + //but holding the whole buffer + this->members_.m_size = 0; + this->members_.m_start = ret.first; + this->members_.m_capacity = real_cap; + + //Backup old buffer data + size_type old_offset = old_start - containers_detail::get_pointer(ret.first); + size_type first_count = containers_detail::min_value(n, old_offset); + + FwdIt mid = first; + std::advance(mid, first_count); + // iG std::uninitialized_copy(first, mid, containers_detail::get_pointer(ret.first)); + boost::interprocess::uninitialized_copy_or_move(first, mid, containers_detail::get_pointer(ret.first)); + + if(old_offset > n){ + //All old elements will be destroyed by "old_values_destroyer" + this->members_.m_size = n; + } + else{ + //We have constructed objects from the new begin until + //the old end so release the rollback destruction + old_values_destroyer.release(); + this->members_.m_start = ret.first; + this->members_.m_size = first_count + old_size; + //Now overwrite the old values + size_type second_count = containers_detail::min_value(old_size, n - first_count); + FwdIt mid2 = mid; + std::advance(mid2, second_count); + // iG std::copy(mid, mid2, old_start); + std::copy(mid, mid2, old_start); + + //Check if we still have to append elements in the + //uninitialized end + if(second_count == old_size){ + // iG std::copy(mid2, last, old_start + old_size); + std::copy(mid2, last, old_start + old_size); + } + else{ + //We have to destroy some old values + this->destroy_n + (old_start + second_count, old_size - second_count); + this->members_.m_size = n; + } + this->members_.m_size = n; + } + } + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InIt first, InIt last, containers_detail::false_) + { + //Dispatch depending on integer/iterator + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, containers_detail::true_) + { this->insert(pos, (size_type)n, (T)val); } + + template + void priv_insert_dispatch(const_iterator pos, InIt first, + InIt last, containers_detail::false_) + { + //Dispatch depending on integer/iterator + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); + } + + void priv_check_range(size_type n) const + { + //If n is out of range, throw an out_of_range exception + if (n >= size()) + throw std::out_of_range("vector::at"); + } + + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + 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_shrink = 0; } + #endif + /// @endcond +}; + +template +inline bool +operator==(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator!=(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const vector& x, const vector& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline void swap(vector& x, vector& y) +{ x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +}} + +/// @endcond + +#include + +#endif // #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP + diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index e820596..249fda6 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -1,1538 +1,32 @@ -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2006. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 comes from SGI's stl_deque.h and stl_uninitialized.h files. -// Modified by Ion Gaztanaga 2005. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DEQUE_HPP -#define BOOST_INTERPROCESS_DEQUE_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_DEQUE_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 -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond -template -class deque; - -template -struct deque_value_traits -{ - typedef T value_type; - typedef A allocator_type; - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::value; - -}; - -// Note: this function is simply a kludge to work around several compilers' -// bugs in handling constant expressions. -inline std::size_t deque_buf_size(std::size_t size) - { return size < 512 ? std::size_t(512 / size) : std::size_t(1); } - -// Deque base class. It has two purposes. First, its constructor -// and destructor allocate (but don't initialize) storage. This makes -// exception safety easier. -template -class deque_base -{ - public: - typedef typename Alloc::value_type val_alloc_val; - typedef typename Alloc::pointer val_alloc_ptr; - typedef typename Alloc::const_pointer val_alloc_cptr; - typedef typename Alloc::reference val_alloc_ref; - typedef typename Alloc::const_reference val_alloc_cref; - typedef typename Alloc::value_type val_alloc_diff; - typedef typename Alloc::template rebind - ::other ptr_alloc_t; - typedef typename ptr_alloc_t::value_type ptr_alloc_val; - typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; - typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; - typedef typename ptr_alloc_t::reference ptr_alloc_ref; - typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; - typedef typename Alloc::template - rebind::other allocator_type; - typedef allocator_type stored_allocator_type; - - protected: - - typedef deque_value_traits traits_t; - typedef typename Alloc::template - rebind::other map_allocator_type; - - static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); } - - val_alloc_ptr priv_allocate_node() - { return this->alloc().allocate(s_buffer_size()); } - - void priv_deallocate_node(val_alloc_ptr p) - { this->alloc().deallocate(p, s_buffer_size()); } - - ptr_alloc_ptr priv_allocate_map(std::size_t n) - { return this->ptr_alloc().allocate(n); } - - void priv_deallocate_map(ptr_alloc_ptr p, std::size_t n) - { this->ptr_alloc().deallocate(p, n); } - - public: - // Class invariants: - // For any nonsingular iterator i: - // i.node is the address of an element in the map array. The - // contents of i.node is a pointer to the beginning of a node. - // i.first == //(i.node) - // i.last == i.first + node_size - // i.cur is a pointer in the range [i.first, i.last). NOTE: - // the implication of this is that i.cur is always a dereferenceable - // pointer, even if i is a past-the-end iterator. - // Start and Finish are always nonsingular iterators. NOTE: this means - // that an empty deque must have one node, and that a deque - // with N elements, where N is the buffer size, must have two nodes. - // For every node other than start.node and finish.node, every element - // in the node is an initialized object. If start.node == finish.node, - // then [start.cur, finish.cur) are initialized objects, and - // the elements outside that range are uninitialized storage. Otherwise, - // [start.cur, start.last) and [finish.first, finish.cur) are initialized - // objects, and [start.first, start.cur) and [finish.cur, finish.last) - // are uninitialized storage. - // [map, map + map_size) is a valid, non-empty range. - // [start.node, finish.node] is a valid range contained within - // [map, map + map_size). - // A pointer in the range [map, map + map_size) points to an allocated node - // if and only if the pointer is in the range [start.node, finish.node]. - class const_iterator - : public std::iterator - { - public: - static std::size_t s_buffer_size() { return deque_base::s_buffer_size(); } - - typedef std::random_access_iterator_tag iterator_category; - typedef val_alloc_val value_type; - typedef val_alloc_cptr pointer; - typedef val_alloc_cref reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - typedef ptr_alloc_ptr index_pointer; - typedef const_iterator self_t; - - friend class deque; - friend class deque_base; - - protected: - val_alloc_ptr m_cur; - val_alloc_ptr m_first; - val_alloc_ptr m_last; - index_pointer m_node; - - public: - const_iterator(val_alloc_ptr x, index_pointer y) - : m_cur(x), m_first(*y), - m_last(*y + s_buffer_size()), m_node(y) {} - - const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} - - const_iterator(const const_iterator& x) - : m_cur(x.m_cur), m_first(x.m_first), - m_last(x.m_last), m_node(x.m_node) {} - - reference operator*() const - { return *this->m_cur; } - - pointer operator->() const - { return this->m_cur; } - - difference_type operator-(const self_t& x) const - { - if(!this->m_cur && !x.m_cur){ - return 0; - } - return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + - (this->m_cur - this->m_first) + (x.m_last - x.m_cur); - } - - self_t& operator++() - { - ++this->m_cur; - if (this->m_cur == this->m_last) { - this->priv_set_node(this->m_node + 1); - this->m_cur = this->m_first; - } - return *this; - } - - self_t operator++(int) - { - self_t tmp = *this; - ++*this; - return tmp; - } - - self_t& operator--() - { - if (this->m_cur == this->m_first) { - this->priv_set_node(this->m_node - 1); - this->m_cur = this->m_last; - } - --this->m_cur; - return *this; - } - - self_t operator--(int) - { - self_t tmp = *this; - --*this; - return tmp; - } - - self_t& operator+=(difference_type n) - { - difference_type offset = n + (this->m_cur - this->m_first); - if (offset >= 0 && offset < difference_type(this->s_buffer_size())) - this->m_cur += n; - else { - difference_type node_offset = - offset > 0 ? offset / difference_type(this->s_buffer_size()) - : -difference_type((-offset - 1) / this->s_buffer_size()) - 1; - this->priv_set_node(this->m_node + node_offset); - this->m_cur = this->m_first + - (offset - node_offset * difference_type(this->s_buffer_size())); - } - return *this; - } - - self_t operator+(difference_type n) const - { self_t tmp = *this; return tmp += n; } - - self_t& operator-=(difference_type n) - { return *this += -n; } - - self_t operator-(difference_type n) const - { self_t tmp = *this; return tmp -= n; } - - reference operator[](difference_type n) const - { return *(*this + n); } - - bool operator==(const self_t& x) const - { return this->m_cur == x.m_cur; } - - bool operator!=(const self_t& x) const - { return !(*this == x); } - - bool operator<(const self_t& x) const - { - return (this->m_node == x.m_node) ? - (this->m_cur < x.m_cur) : (this->m_node < x.m_node); - } - - bool operator>(const self_t& x) const - { return x < *this; } - - bool operator<=(const self_t& x) const - { return !(x < *this); } - - bool operator>=(const self_t& x) const - { return !(*this < x); } - - void priv_set_node(index_pointer new_node) - { - this->m_node = new_node; - this->m_first = *new_node; - this->m_last = this->m_first + difference_type(this->s_buffer_size()); - } - - friend const_iterator operator+(std::ptrdiff_t n, const const_iterator& x) - { return x + n; } - }; - - //Deque iterator - class iterator : public const_iterator - { - public: - typedef std::random_access_iterator_tag iterator_category; - typedef val_alloc_val value_type; - typedef val_alloc_ptr pointer; - typedef val_alloc_ref reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - typedef ptr_alloc_ptr index_pointer; - typedef const_iterator self_t; - - friend class deque; - friend class deque_base; - - private: - explicit iterator(const const_iterator& x) : const_iterator(x){} - - public: - //Constructors - iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} - iterator() : const_iterator(){} - //iterator(const const_iterator &cit) : const_iterator(cit){} - iterator(const iterator& x) : const_iterator(x){} - - //Pointer like operators - reference operator*() const { return *this->m_cur; } - pointer operator->() const { return this->m_cur; } - - reference operator[](difference_type n) const { return *(*this + n); } - - //Increment / Decrement - iterator& operator++() - { this->const_iterator::operator++(); return *this; } - - iterator operator++(int) - { iterator tmp = *this; ++*this; return tmp; } - - iterator& operator--() - { this->const_iterator::operator--(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - - // Arithmetic - iterator& operator+=(difference_type off) - { this->const_iterator::operator+=(off); return *this; } - - iterator operator+(difference_type off) const - { return iterator(this->const_iterator::operator+(off)); } - - friend iterator operator+(difference_type off, const iterator& right) - { return iterator(off+static_cast(right)); } - - iterator& operator-=(difference_type off) - { this->const_iterator::operator-=(off); return *this; } - - iterator operator-(difference_type off) const - { return iterator(this->const_iterator::operator-(off)); } - - difference_type operator-(const const_iterator& right) const - { return static_cast(*this) - right; } - }; - - deque_base(const allocator_type& a, std::size_t num_elements) - : members_(a) - { this->priv_initialize_map(num_elements); } - - deque_base(const allocator_type& a) - : members_(a) - {} - - ~deque_base() - { - if (this->members_.m_map) { - this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - } - } - - private: - deque_base(const deque_base&); - - protected: - - void priv_initialize_map(std::size_t num_elements) - { -// if(num_elements){ - std::size_t num_nodes = num_elements / s_buffer_size() + 1; - - this->members_.m_map_size = max_value((std::size_t) InitialMapSize, num_nodes + 2); - this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size); - - ptr_alloc_ptr nstart = this->members_.m_map + (this->members_.m_map_size - num_nodes) / 2; - ptr_alloc_ptr nfinish = nstart + num_nodes; - - BOOST_TRY { - this->priv_create_nodes(nstart, nfinish); - } - BOOST_CATCH(...){ - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - this->members_.m_map = 0; - this->members_.m_map_size = 0; - BOOST_RETHROW - } - BOOST_CATCH_END - - this->members_.m_start.priv_set_node(nstart); - this->members_.m_finish.priv_set_node(nfinish - 1); - this->members_.m_start.m_cur = this->members_.m_start.m_first; - this->members_.m_finish.m_cur = this->members_.m_finish.m_first + - num_elements % s_buffer_size(); -// } - } - - void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) - { - ptr_alloc_ptr cur; - BOOST_TRY { - for (cur = nstart; cur < nfinish; ++cur) - *cur = this->priv_allocate_node(); - } - BOOST_CATCH(...){ - this->priv_destroy_nodes(nstart, cur); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) - { - for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) - this->priv_deallocate_node(*n); - } - - enum { InitialMapSize = 8 }; - - protected: - struct members_holder - : public ptr_alloc_t - , public allocator_type - { - members_holder(const allocator_type &a) - : map_allocator_type(a), allocator_type(a) - , m_map(0), m_map_size(0) - , m_start(), m_finish(m_start) - {} - - ptr_alloc_ptr m_map; - std::size_t m_map_size; - iterator m_start; - iterator m_finish; - } members_; - - ptr_alloc_t &ptr_alloc() - { return members_; } - - const ptr_alloc_t &ptr_alloc() const - { return members_; } - - allocator_type &alloc() - { return members_; } - - const allocator_type &alloc() const - { return members_; } -}; -/// @endcond - -//! Deque class -//! -template -class deque : protected deque_base -{ - /// @cond - typedef deque_base Base; - - public: // Basic types - typedef typename Alloc::value_type val_alloc_val; - typedef typename Alloc::pointer val_alloc_ptr; - typedef typename Alloc::const_pointer val_alloc_cptr; - typedef typename Alloc::reference val_alloc_ref; - typedef typename Alloc::const_reference val_alloc_cref; - typedef typename Alloc::template - rebind::other ptr_alloc_t; - typedef typename ptr_alloc_t::value_type ptr_alloc_val; - typedef typename ptr_alloc_t::pointer ptr_alloc_ptr; - typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr; - typedef typename ptr_alloc_t::reference ptr_alloc_ref; - typedef typename ptr_alloc_t::const_reference ptr_alloc_cref; - /// @endcond - - typedef T value_type; - typedef val_alloc_ptr pointer; - typedef val_alloc_cptr const_pointer; - typedef val_alloc_ref reference; - typedef val_alloc_cref const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - typedef typename Base::allocator_type allocator_type; - - public: // Iterators - typedef typename Base::iterator iterator; - typedef typename Base::const_iterator const_iterator; - - typedef std::reverse_iterator const_reverse_iterator; - typedef std::reverse_iterator reverse_iterator; - - /// @cond - private: // Internal typedefs - typedef ptr_alloc_ptr index_pointer; - static std::size_t s_buffer_size() - { return Base::s_buffer_size(); } - typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; - typedef repeat_iterator r_iterator; - typedef detail::move_iterator move_it; - - /// @endcond - - allocator_type get_allocator() const { return Base::alloc(); } - - public: // Basic accessors - iterator begin() - { return this->members_.m_start; } - - iterator end() - { return this->members_.m_finish; } - - const_iterator begin() const - { return this->members_.m_start; } - - const_iterator end() const - { return this->members_.m_finish; } - - reverse_iterator rbegin() - { return reverse_iterator(this->members_.m_finish); } - - reverse_iterator rend() - { return reverse_iterator(this->members_.m_start); } - - const_reverse_iterator rbegin() const - { return const_reverse_iterator(this->members_.m_finish); } - - const_reverse_iterator rend() const - { return const_reverse_iterator(this->members_.m_start); } - - const_iterator cbegin() const - { return this->members_.m_start; } - - const_iterator cend() const - { return this->members_.m_finish; } - - const_reverse_iterator crbegin() const - { return const_reverse_iterator(this->members_.m_finish); } - - const_reverse_iterator crend() const - { return const_reverse_iterator(this->members_.m_start); } - - reference operator[](size_type n) - { return this->members_.m_start[difference_type(n)]; } - - const_reference operator[](size_type n) const - { return this->members_.m_start[difference_type(n)]; } - - void priv_range_check(size_type n) const - { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } - - reference at(size_type n) - { this->priv_range_check(n); return (*this)[n]; } - - const_reference at(size_type n) const - { this->priv_range_check(n); return (*this)[n]; } - - reference front() { return *this->members_.m_start; } - - reference back() { return *(end()-1); } - - const_reference front() const - { return *this->members_.m_start; } - - const_reference back() const { return *(cend()-1); } - - size_type size() const - { return this->members_.m_finish - this->members_.m_start; } - - size_type max_size() const - { return this->alloc().max_size(); } - - bool empty() const - { return this->members_.m_finish == this->members_.m_start; } - - explicit deque(const allocator_type& a = allocator_type()) - : Base(a) - {} - - deque(const deque& x) - : Base(x.alloc()) - { - if(x.size()){ - this->priv_initialize_map(x.size()); - std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - deque(detail::moved_object mx) - : Base(mx.get().alloc()) - { this->swap(mx.get()); } - #else - deque(deque &&x) - : Base(x.alloc()) - { this->swap(x); } - #endif - - deque(size_type n, const value_type& value, - const allocator_type& a = allocator_type()) : Base(a, n) - { this->priv_fill_initialize(value); } - - explicit deque(size_type n) : Base(allocator_type(), n) - { this->resize(n); } - - // Check whether it's an integral type. If so, it's not an iterator. - template - deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) - : Base(a) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_initialize_dispatch(first, last, Result()); - } - - ~deque() - { - priv_destroy_range(this->members_.m_start, this->members_.m_finish); - } - - deque& operator= (const deque& x) - { - const size_type len = size(); - if (&x != this) { - if (len >= x.size()) - this->erase(std::copy(x.begin(), x.end(), this->members_.m_start), this->members_.m_finish); - else { - const_iterator mid = x.begin() + difference_type(len); - std::copy(x.begin(), mid, this->members_.m_start); - this->insert(this->members_.m_finish, mid, x.end()); - } - } - return *this; - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - deque& operator= (detail::moved_object mx) - { - deque &x = mx.get(); - #else - deque& operator= (deque &&x) - { - #endif - this->clear(); - this->swap(x); - return *this; - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(deque& x) - #else - void swap(deque &&x) - #endif - { - std::swap(this->members_.m_start, x.members_.m_start); - std::swap(this->members_.m_finish, x.members_.m_finish); - std::swap(this->members_.m_map, x.members_.m_map); - std::swap(this->members_.m_map_size, x.members_.m_map_size); - } - - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - template - void assign(InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - void push_back(const value_type& t) - { - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(t); - this->priv_push_back_simple_commit(); - } - else{ - this->priv_insert_aux(cend(), size_type(1), t); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back(detail::moved_object mt) - { - value_type &t = mt.get(); - #else - void push_back(value_type &&t) - { - #endif - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(detail::move_impl(t)); - this->priv_push_back_simple_commit(); - } - else{ - this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator())); - } - } - - void push_front(const value_type& t) - { - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(t); - this->priv_push_front_simple_commit(); - } - else{ - this->priv_insert_aux(cbegin(), size_type(1), t); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object mt) - { - value_type &t = mt.get(); - #else - void push_front(value_type &&t) - { - #endif - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(detail::move_impl(t)); - this->priv_push_front_simple_commit(); - } - else{ - this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator())); - } - } - - void pop_back() - { - if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { - --this->members_.m_finish.m_cur; - detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); - } - else - this->priv_pop_back_aux(); - } - - void pop_front() - { - if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { - detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); - ++this->members_.m_start.m_cur; - } - else - this->priv_pop_front_aux(); - } - - iterator insert(const_iterator position, const value_type& x) - { - if (position == cbegin()){ - this->push_front(x); - return begin(); - } - else if (position == cend()){ - this->push_back(x); - return (end()-1); - } - else { - size_type n = position - cbegin(); - this->priv_insert_aux(position, size_type(1), x); - return iterator(this->begin() + n); - } - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object m) - { - value_type &mx = m.get(); - #else - iterator insert(const_iterator position, value_type &&mx) - { - #endif - if (position == cbegin()) { - this->push_front(detail::move_impl(mx)); - return begin(); - } - else if (position == cend()) { - this->push_back(detail::move_impl(mx)); - return(end()-1); - } - else { - //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); - this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator())); - return iterator(this->begin() + n); - } - } - - void insert(const_iterator pos, size_type n, const value_type& x) - { this->priv_fill_insert(pos, n, x); } - - // Check whether it's an integral type. If so, it's not an iterator. - template - void insert(const_iterator pos, InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - void emplace_back(Args&&... args) - { - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(detail::forward_impl(args)...); - this->priv_push_back_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(this->cend(), 1, proxy); - } - } - - template - void emplace_front(Args&&... args) - { - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(detail::forward_impl(args)...); - this->priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(this->cbegin(), 1, proxy); - } - } - - template - iterator emplace(const_iterator p, Args&&... args) - { - if(p == this->cbegin()){ - this->emplace_front(detail::forward_impl(args)...); - return this->begin(); - } - else if(p == this->cend()){ - this->emplace_back(detail::forward_impl(args)...); - return (this->end()-1); - } - else{ - size_type n = p - this->cbegin(); - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(p, 1, proxy); - return iterator(this->begin() + n); - } - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //0 args - void emplace_back() - { - if(priv_push_front_simple_available()){ - new(priv_push_front_simple_pos())value_type(); - priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy; - priv_insert_aux_impl(cend(), 1, proxy); - } - } - - void emplace_front() - { - if(priv_push_front_simple_available()){ - new(priv_push_front_simple_pos())value_type(); - priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy; - priv_insert_aux_impl(cbegin(), 1, proxy); - } - } - - iterator emplace(const_iterator p) - { - if(p == cbegin()){ - emplace_front(); - return begin(); - } - else if(p == cend()){ - emplace_back(); - return (end()-1); - } - else{ - size_type n = p - cbegin(); - detail::advanced_insert_aux_emplace proxy; - priv_insert_aux_impl(p, 1, proxy); - return iterator(this->begin() + n); - } - } - - //advanced_insert_int.hpp includes all necessary preprocessor machinery... - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - if(priv_push_back_simple_available()){ \ - new(priv_push_back_simple_pos())value_type \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_push_back_simple_commit(); \ - } \ - else{ \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_insert_aux_impl(cend(), 1, proxy); \ - } \ - } \ - \ - template \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - if(priv_push_front_simple_available()){ \ - new(priv_push_front_simple_pos())value_type \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_push_front_simple_commit(); \ - } \ - else{ \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_insert_aux_impl(cbegin(), 1, proxy); \ - } \ - } \ - \ - template \ - iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - if(p == this->cbegin()){ \ - this->emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - return this->begin(); \ - } \ - else if(p == cend()){ \ - this->emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - return (this->end()-1); \ - } \ - else{ \ - size_type pos_num = p - this->cbegin(); \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - this->priv_insert_aux_impl(p, 1, proxy); \ - return iterator(this->begin() + pos_num); \ - } \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - void resize(size_type new_size, const value_type& x) - { - const size_type len = size(); - if (new_size < len) - this->erase(this->members_.m_start + new_size, this->members_.m_finish); - else - this->insert(this->members_.m_finish, new_size - len, x); - } - - void resize(size_type new_size) - { - const size_type len = size(); - if (new_size < len) - this->erase(this->members_.m_start + new_size, this->members_.m_finish); - else{ - size_type n = new_size - this->size(); - detail::default_construct_aux_proxy proxy(n); - priv_insert_aux_impl(this->cend(), n, proxy); - } - } - - iterator erase(const_iterator pos) - { - const_iterator next = pos; - ++next; - difference_type index = pos - this->members_.m_start; - if (size_type(index) < (this->size() >> 1)) { - std::copy_backward( detail::make_move_iterator(begin()) - , detail::make_move_iterator(iterator(pos)) - , iterator(next)); - pop_front(); - } - else { - std::copy( detail::make_move_iterator(iterator(next)) - , detail::make_move_iterator(end()) - , iterator(pos)); - pop_back(); - } - return this->members_.m_start + index; - } - - iterator erase(const_iterator first, const_iterator last) - { - if (first == this->members_.m_start && last == this->members_.m_finish) { - this->clear(); - return this->members_.m_finish; - } - else { - difference_type n = last - first; - difference_type elems_before = first - this->members_.m_start; - if (elems_before < static_cast(this->size() - n) - elems_before) { - std::copy_backward( detail::make_move_iterator(begin()) - , detail::make_move_iterator(iterator(first)) - , iterator(last)); - iterator new_start = this->members_.m_start + n; - if(!Base::traits_t::trivial_dctr_after_move) - this->priv_destroy_range(this->members_.m_start, new_start); - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); - this->members_.m_start = new_start; - } - else { - std::copy( detail::make_move_iterator(iterator(last)) - , detail::make_move_iterator(end()) - , iterator(first)); - iterator new_finish = this->members_.m_finish - n; - if(!Base::traits_t::trivial_dctr_after_move) - this->priv_destroy_range(new_finish, this->members_.m_finish); - this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); - this->members_.m_finish = new_finish; - } - return this->members_.m_start + elems_before; - } - } - - void clear() - { - for (index_pointer node = this->members_.m_start.m_node + 1; - node < this->members_.m_finish.m_node; - ++node) { - this->priv_destroy_range(*node, *node + this->s_buffer_size()); - this->priv_deallocate_node(*node); - } - - if (this->members_.m_start.m_node != this->members_.m_finish.m_node) { - this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.m_last); - this->priv_destroy_range(this->members_.m_finish.m_first, this->members_.m_finish.m_cur); - this->priv_deallocate_node(this->members_.m_finish.m_first); - } - else - this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur); - - this->members_.m_finish = this->members_.m_start; - } - - /// @cond - private: - - bool priv_push_back_simple_available() const - { - return this->members_.m_map && - (this->members_.m_finish.m_cur != (this->members_.m_finish.m_last - 1)); - } - - void *priv_push_back_simple_pos() const - { - return static_cast(detail::get_pointer(this->members_.m_finish.m_cur)); - } - - void priv_push_back_simple_commit() - { - ++this->members_.m_finish.m_cur; - } - - bool priv_push_front_simple_available() const - { - return this->members_.m_map && - (this->members_.m_start.m_cur != this->members_.m_start.m_first); - } - - void *priv_push_front_simple_pos() const - { return static_cast(detail::get_pointer(this->members_.m_start.m_cur) - 1); } - - void priv_push_front_simple_commit() - { --this->members_.m_start.m_cur; } - - template - void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, move_impl(value_type(*first))); - } - } - - template - void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { this->priv_insert_aux(pos, first, last); } - - // assign(), a generalized assignment member function. Two - // versions: one that takes a count, and one that takes a range. - // The range version is a member template, so we dispatch on whether - // or not the type is an integer. - void priv_fill_assign(size_type n, const T& val) - { - if (n > size()) { - std::fill(begin(), end(), val); - this->insert(cend(), n - size(), val); - } - else { - this->erase(cbegin() + n, cend()); - std::fill(begin(), end(), val); - } - } - - template - void priv_initialize_dispatch(Integer n, Integer x, detail::true_) - { - this->priv_initialize_map(n); - this->priv_fill_initialize(x); - } - - template - void priv_initialize_dispatch(InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_initialize(first, last, ItCat()); - } - - void priv_destroy_range(iterator p, iterator p2) - { - for(;p != p2; ++p) - detail::get_pointer(&*p)->~value_type(); - } - - void priv_destroy_range(pointer p, pointer p2) - { - for(;p != p2; ++p) - detail::get_pointer(&*p)->~value_type(); - } - - template - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) - { - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first) - *cur = *first; - if (first == last) - this->erase(cur, cend()); - else - this->insert(cend(), first, last); - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type len = std::distance(first, last); - if (len > size()) { - FwdIt mid = first; - std::advance(mid, size()); - std::copy(first, mid, begin()); - this->insert(cend(), mid, last); - } - else - this->erase(std::copy(first, last, begin()), cend()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, detail::true_) - { this->priv_fill_insert(pos, (size_type) n, (value_type) x); } - - template - void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_insert_aux(pos, first, last, ItCat()); - } - - void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) - { - typedef constant_iterator c_it; - this->priv_insert_aux(pos, c_it(x, n), c_it()); - } - - //Just forward all operations to priv_insert_aux_impl - template - void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) - { - detail::advanced_insert_aux_proxy proxy(first, last); - priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy); - } - - void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf) - { - iterator pos(p); - if(!this->members_.m_map){ - this->priv_initialize_map(0); - pos = this->begin(); - } - - const difference_type elemsbefore = pos - this->members_.m_start; - size_type length = this->size(); - if (elemsbefore < static_cast(length / 2)) { - iterator new_start = this->priv_reserve_elements_at_front(n); - iterator old_start = this->members_.m_start; - pos = this->members_.m_start + elemsbefore; - if (elemsbefore >= difference_type(n)) { - iterator start_n = this->members_.m_start + difference_type(n); - std::uninitialized_copy(detail::make_move_iterator(this->members_.m_start), detail::make_move_iterator(start_n), new_start); - this->members_.m_start = new_start; - std::copy(detail::make_move_iterator(start_n), detail::make_move_iterator(pos), old_start); - interf.copy_all_to(pos - difference_type(n)); - } - else { - difference_type mid_count = (difference_type(n) - elemsbefore); - iterator mid_start = old_start - mid_count; - interf.uninitialized_copy_some_and_update(mid_start, mid_count, true); - this->members_.m_start = mid_start; - std::uninitialized_copy(detail::make_move_iterator(old_start), detail::make_move_iterator(pos), new_start); - this->members_.m_start = new_start; - interf.copy_all_to(old_start); - } - } - else { - iterator new_finish = this->priv_reserve_elements_at_back(n); - iterator old_finish = this->members_.m_finish; - const difference_type elemsafter = - difference_type(length) - elemsbefore; - pos = this->members_.m_finish - elemsafter; - if (elemsafter >= difference_type(n)) { - iterator finish_n = this->members_.m_finish - difference_type(n); - std::uninitialized_copy(detail::make_move_iterator(finish_n), detail::make_move_iterator(this->members_.m_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - std::copy_backward(detail::make_move_iterator(pos), detail::make_move_iterator(finish_n), old_finish); - interf.copy_all_to(pos); - } - else { - interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); - this->members_.m_finish += n-elemsafter; - std::uninitialized_copy(detail::make_move_iterator(pos), detail::make_move_iterator(old_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - interf.copy_all_to(pos); - } - } - } - - void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) - { - typedef constant_iterator c_it; - this->insert(pos, c_it(x, n), c_it()); - } - - // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, - // but none of the deque's elements have yet been constructed. - void priv_fill_initialize(const value_type& value) - { - index_pointer cur; - BOOST_TRY { - for (cur = this->members_.m_start.m_node; cur < this->members_.m_finish.m_node; ++cur){ - std::uninitialized_fill(*cur, *cur + this->s_buffer_size(), value); - } - std::uninitialized_fill(this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value); - } - BOOST_CATCH(...){ - this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) - { - this->priv_initialize_map(0); - BOOST_TRY { - for ( ; first != last; ++first) - this->push_back(*first); - } - BOOST_CATCH(...){ - this->clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type n = 0; - n = std::distance(first, last); - this->priv_initialize_map(n); - - index_pointer cur_node; - BOOST_TRY { - for (cur_node = this->members_.m_start.m_node; - cur_node < this->members_.m_finish.m_node; - ++cur_node) { - FwdIt mid = first; - std::advance(mid, this->s_buffer_size()); - std::uninitialized_copy(first, mid, *cur_node); - first = mid; - } - std::uninitialized_copy(first, last, this->members_.m_finish.m_first); - } - BOOST_CATCH(...){ - this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first. - void priv_pop_back_aux() - { - this->priv_deallocate_node(this->members_.m_finish.m_first); - 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_last - 1; - detail::get_pointer(this->members_.m_finish.m_cur)->~value_type(); - } - - // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_last - 1. Note that - // if the deque has at least one element (a precondition for this member - // function), and if this->members_.m_start.m_cur == this->members_.m_start.m_last, then the deque - // must have at least two nodes. - void priv_pop_front_aux() - { - detail::get_pointer(this->members_.m_start.m_cur)->~value_type(); - this->priv_deallocate_node(this->members_.m_start.m_first); - 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_first; - } - - iterator priv_reserve_elements_at_front(size_type n) - { - size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first; - if (n > vacancies){ - size_type new_elems = n-vacancies; - size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / - this->s_buffer_size(); - size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map); - if (new_nodes > s){ - this->priv_reallocate_map(new_nodes, true); - } - size_type i = 1; - BOOST_TRY { - for (; i <= new_nodes; ++i) - *(this->members_.m_start.m_node - i) = this->priv_allocate_node(); - } - BOOST_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->priv_deallocate_node(*(this->members_.m_start.m_node - j)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - return this->members_.m_start - difference_type(n); - } - - iterator priv_reserve_elements_at_back(size_type n) - { - size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1; - if (n > vacancies){ - size_type new_elems = n - vacancies; - size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size(); - size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)); - if (new_nodes + 1 > s){ - this->priv_reallocate_map(new_nodes, false); - } - size_type i; - BOOST_TRY { - for (i = 1; i <= new_nodes; ++i) - *(this->members_.m_finish.m_node + i) = this->priv_allocate_node(); - } - BOOST_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->priv_deallocate_node(*(this->members_.m_finish.m_node + j)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - return this->members_.m_finish + difference_type(n); - } - - void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) - { - size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1; - size_type new_num_nodes = old_num_nodes + nodes_to_add; - - index_pointer new_nstart; - if (this->members_.m_map_size > 2 * new_num_nodes) { - new_nstart = this->members_.m_map + (this->members_.m_map_size - new_num_nodes) / 2 - + (add_at_front ? nodes_to_add : 0); - if (new_nstart < this->members_.m_start.m_node) - std::copy(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); - else - std::copy_backward(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, - new_nstart + old_num_nodes); - } - else { - size_type new_map_size = - this->members_.m_map_size + max_value(this->members_.m_map_size, nodes_to_add) + 2; - - index_pointer new_map = this->priv_allocate_map(new_map_size); - new_nstart = new_map + (new_map_size - new_num_nodes) / 2 - + (add_at_front ? nodes_to_add : 0); - std::copy(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - - this->members_.m_map = new_map; - this->members_.m_map_size = new_map_size; - } - - this->members_.m_start.priv_set_node(new_nstart); - this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); - } - /// @endcond -}; - -// Nonmember functions. -template -inline bool operator==(const deque& x, - const deque& y) -{ - return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool operator<(const deque& x, - const deque& y) -{ - return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); -} - -template -inline bool operator!=(const deque& x, - const deque& y) - { return !(x == y); } - -template -inline bool operator>(const deque& x, - const deque& y) - { return y < x; } - -template -inline bool operator<=(const deque& x, - const deque& y) - { return !(y < x); } - -template -inline bool operator>=(const deque& x, - const deque& y) - { return !(x < y); } - - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(deque& x, deque& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, deque& y) -{ x.get().swap(y); } - -template -inline void swap(deque &x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(deque&&x, deque&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::deque; } //namespace interprocess { } //namespace boost { #include -#endif // #ifndef BOOST_INTERPROCESS_DEQUE_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 3649906..4129bbb 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -8,1434 +8,25 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_MAP_HPP -#define BOOST_INTERPROCESS_FLAT_MAP_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { -namespace boost { namespace interprocess { +using boost::interprocess_container::flat_map; +using boost::interprocess_container::flat_multimap; -/// @cond -// Forward declarations of operators == and <, needed for friend declarations. -template -class flat_map; - -template -inline bool operator==(const flat_map& x, - const flat_map& y); - -template -inline bool operator<(const flat_map& x, - const flat_map& y); -/// @endcond - -//! A flat_map is a kind of associative container that supports unique keys (contains at -//! most one of each key value) and provides for fast retrieval of values of another -//! type T based on the keys. The flat_map class supports random-access iterators. -//! -//! A flat_map satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. A flat_map also provides -//! most operations described for unique keys. For a -//! flat_map the key_type is Key and the value_type is std::pair -//! (unlike std::map which value_type is std::pair<const Key, T>). -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -//! -//! flat_map is similar to std::map but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_map invalidates -//! previous iterators and references -//! -//! Erasing an element of a flat_map invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. -template -class flat_map -{ - /// @cond - private: - //This is the tree that we should store if pair was movable - 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, - 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; - typedef typename impl_tree_t::pointer impl_pointer; - typedef typename impl_tree_t::const_pointer impl_const_pointer; - typedef typename impl_tree_t::reference impl_reference; - typedef typename impl_tree_t::const_reference impl_const_reference; - typedef typename impl_tree_t::value_compare impl_value_compare; - typedef typename impl_tree_t::iterator impl_iterator; - typedef typename impl_tree_t::const_iterator impl_const_iterator; - typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; - typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; - typedef typename impl_tree_t::allocator_type impl_allocator_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef detail::moved_object impl_moved_value_type; - #endif - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &force(const S &s) - { return *const_cast(reinterpret_cast(&s)); } - - template - static D force_copy(S s) - { - value_type *vp = reinterpret_cast(&*s); - return D(vp); - } - - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::value_compare value_compare; - typedef T mapped_type; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_map using the specified - //! comparison object and allocator. - //! - //! Complexity: Constant. - explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) {} - - //! Effects: Constructs an empty flat_map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) - { m_flat_tree.insert_unique(first, last); } - - //! Effects: Copy constructs a flat_map. - //! - //! Complexity: Linear in x.size(). - flat_map(const flat_map& x) - : m_flat_tree(x.m_flat_tree) {} - - //! Effects: Move constructs a flat_map. - //! Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_map(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} - - #else - flat_map(flat_map && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_map& operator=(const flat_map& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: Move constructs a flat_map. - //! Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_map& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_map& operator=(flat_map && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return force(m_flat_tree.key_comp()); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(force(m_flat_tree.key_comp())); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return force(m_flat_tree.get_allocator()); } - - const stored_allocator_type &get_stored_allocator() const - { return force(m_flat_tree.get_stored_allocator()); } - - stored_allocator_type &get_stored_allocator() - { return force(m_flat_tree.get_stored_allocator()); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return force_copy(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return force(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return force(m_flat_tree.cbegin()); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return force_copy(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return force(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return force(m_flat_tree.cend()); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return force(m_flat_tree.crbegin()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return force(m_flat_tree.crend()); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: If there is no key equivalent to x in the flat_map, inserts - //! value_type(x, T()) into the flat_map. - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - T &operator[](const key_type& k) - { - 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, T())); - return (*i).second; - } - - //! 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) - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - T &operator[](detail::moved_object mk) - { - key_type &k = mk.get(); - 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, detail::move_impl(T()))); - return (*i).second; - } - #else - T &operator[](key_type &&mk) - { - key_type &k = mk; - 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(detail::forward_impl(k), detail::move_impl(T()))); - return (*i).second; - } - #endif - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - T& at(const key_type& k) - { - iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - const T& at(const key_type& k) const - { - const_iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_map& x) - #else - void swap(flat_map &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - std::pair insert(const value_type& x) - { return force >( - m_flat_tree.insert_unique(force(x))); } - - //! Effects: Inserts a new value_type move constructed from the pair if and - //! only if there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return force >( - m_flat_tree.insert_unique(force(x))); } - #else - std::pair insert(value_type &&x) - { return force >( - m_flat_tree.insert_unique(detail::move_impl(force(x)))); } - #endif - - //! Effects: Inserts a copy of x in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return force_copy( - m_flat_tree.insert_unique(force(position), force(x))); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return force_copy( - m_flat_tree.insert_unique(force(position), force(x))); } - #else - iterator insert(const_iterator position, value_type &&x) - { return force_copy( - m_flat_tree.insert_unique(force(position), detail::move_impl(force(x)))); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return force_copy(m_flat_tree.emplace_unique(detail::forward_impl(args)...)); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), detail::forward_impl(args)...)); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return force_copy(m_flat_tree.emplace_unique()); } - - iterator emplace_hint(const_iterator hint) - { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_unique \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_hint_unique \ - (force(hint), \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return force_copy(m_flat_tree.erase(force(position))); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return force_copy(m_flat_tree.erase(force(first), force(last))); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return force_copy(m_flat_tree.find(x)); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return force(m_flat_tree.find(x)); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return force_copy(m_flat_tree.lower_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return force(m_flat_tree.lower_bound(x)); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return force_copy(m_flat_tree.upper_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return force(m_flat_tree.upper_bound(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return force >(m_flat_tree.equal_range(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const - { return force >(m_flat_tree.equal_range(x)); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_map&, - const flat_map&); - template - friend bool operator< (const flat_map&, - const flat_map&); - /// @endcond -}; - -template -inline bool operator==(const flat_map& x, - const flat_map& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_map& x, - const flat_map& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_map& x, - const flat_map& y) - { return !(x == y); } - -template -inline bool operator>(const flat_map& x, - const flat_map& y) - { return y < x; } - -template -inline bool operator<=(const flat_map& x, - const flat_map& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_map& x, - const flat_map& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_map& x, - flat_map& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, - flat_map& y) - { x.get().swap(y); } - -template -inline void swap(flat_map& x, - detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_map&&x, - flat_map&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. -template -class flat_multimap; - -template -inline bool operator==(const flat_multimap& x, - const flat_multimap& y); - -template -inline bool operator<(const flat_multimap& x, - const flat_multimap& y); -/// @endcond - -//! A flat_multimap is a kind of associative container that supports equivalent keys -//! (possibly containing multiple copies of the same key value) and provides for -//! fast retrieval of values of another type T based on the keys. The flat_multimap -//! class supports random-access iterators. -//! -//! A flat_multimap satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! flat_multimap the key_type is Key and the value_type is std::pair -//! (unlike std::multimap which value_type is std::pair<const Key, T>). -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -template -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, - 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; - typedef typename impl_tree_t::pointer impl_pointer; - typedef typename impl_tree_t::const_pointer impl_const_pointer; - typedef typename impl_tree_t::reference impl_reference; - typedef typename impl_tree_t::const_reference impl_const_reference; - typedef typename impl_tree_t::value_compare impl_value_compare; - typedef typename impl_tree_t::iterator impl_iterator; - typedef typename impl_tree_t::const_iterator impl_const_iterator; - typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator; - typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator; - typedef typename impl_tree_t::allocator_type impl_allocator_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef detail::moved_object impl_moved_value_type; - #endif - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &force(const S &s) - { return *const_cast((reinterpret_cast(&s))); } - - template - static D force_copy(S s) - { - value_type *vp = reinterpret_cast(&*s); - return D(vp); - } - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::value_compare value_compare; - typedef T mapped_type; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_multimap using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit flat_multimap(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) { } - - //! Effects: Constructs an empty flat_multimap using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_multimap(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) - { m_flat_tree.insert_equal(first, last); } - - //! Effects: Copy constructs a flat_multimap. - //! - //! Complexity: Linear in x.size(). - flat_multimap(const flat_multimap& x) - : m_flat_tree(x.m_flat_tree) { } - - //! Effects: Move constructs a flat_multimap. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multimap(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) { } - #else - flat_multimap(flat_multimap && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) { } - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_multimap& operator=(const flat_multimap& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multimap& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_multimap& operator=(flat_multimap && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return force(m_flat_tree.key_comp()); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(force(m_flat_tree.key_comp())); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return force(m_flat_tree.get_allocator()); } - - const stored_allocator_type &get_stored_allocator() const - { return force(m_flat_tree.get_stored_allocator()); } - - stored_allocator_type &get_stored_allocator() - { return force(m_flat_tree.get_stored_allocator()); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return force_copy(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return force(m_flat_tree.begin()); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return force_copy(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return force(m_flat_tree.end()); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return force(m_flat_tree.rend()); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_multimap& x) - #else - void swap(flat_multimap &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const value_type& x) - { return force_copy(m_flat_tree.insert_equal(force(x))); } - - //! Effects: Inserts a new value move-constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return force_copy(m_flat_tree.insert_equal(force(x))); } - #else - iterator insert(value_type &&x) - { return force_copy(m_flat_tree.insert_equal(detail::move_impl(x))); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant time if the value - //! is to be inserted before p) plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } - - //! Effects: Inserts a value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant time if the value - //! is to be inserted before p) plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } - #else - iterator insert(const_iterator position, value_type &&x) - { return force_copy(m_flat_tree.insert_equal(force(position), detail::move_impl(x))); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return force_copy(m_flat_tree.emplace_equal(detail::forward_impl(args)...)); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant time if the value - //! is to be inserted before p) plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { - return force_copy(m_flat_tree.emplace_hint_equal - (force(hint), detail::forward_impl(args)...)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return force_copy(m_flat_tree.emplace_equal()); } - - iterator emplace_hint(const_iterator hint) - { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_equal \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_hint_equal \ - (force(hint), \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return force_copy(m_flat_tree.erase(force(position))); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return force_copy(m_flat_tree.erase(force(first), force(last))); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return force_copy(m_flat_tree.find(x)); } - - //! Returns: An const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return force(m_flat_tree.find(x)); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - {return force_copy(m_flat_tree.lower_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key - //! not less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return force(m_flat_tree.lower_bound(x)); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - {return force_copy(m_flat_tree.upper_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return force(m_flat_tree.upper_bound(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return force_copy >(m_flat_tree.equal_range(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return force_copy >(m_flat_tree.equal_range(x)); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_multimap& x, - const flat_multimap& y); - - template - friend bool operator< (const flat_multimap& x, - const flat_multimap& y); - /// @endcond -}; - -template -inline bool operator==(const flat_multimap& x, - const flat_multimap& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_multimap& x, - const flat_multimap& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_multimap& x, - const flat_multimap& y) - { return !(x == y); } - -template -inline bool operator>(const flat_multimap& x, - const flat_multimap& y) - { return y < x; } - -template -inline bool operator<=(const flat_multimap& x, - const flat_multimap& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_multimap& x, - const flat_multimap& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_multimap& x, - flat_multimap& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, - flat_multimap& y) - { x.get().swap(y); } - - -template -inline void swap(flat_multimap& x, - detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_multimap&&x, - flat_multimap&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_FLAT_MAP_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index 1e3c9bf..0c38930 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -8,1237 +8,25 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_SET_HPP -#define BOOST_INTERPROCESS_FLAT_SET_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { +using boost::interprocess_container::flat_set; +using boost::interprocess_container::flat_multiset; -namespace boost { namespace interprocess { - -/// @cond -// Forward declarations of operators < and ==, needed for friend declaration. - -template -class flat_set; - -template -inline bool operator==(const flat_set& x, - const flat_set& y); - -template -inline bool operator<(const flat_set& x, - const flat_set& y); -/// @endcond - -//! flat_set is a Sorted Associative Container that stores objects of type Key. -//! flat_set is a Simple Associative Container, meaning that its value type, -//! as well as its key type, is Key. It is also a Unique Associative Container, -//! meaning that no two elements are the same. -//! -//! flat_set is similar to std::set but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_set invalidates -//! previous iterators and references -//! -//! Erasing an element of a flat_set invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. -template -class flat_set -{ - /// @cond - private: - typedef detail::flat_tree, Pred, Alloc> tree_t; - tree_t m_flat_tree; // flat tree representing flat_set - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::value_compare value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_map using the specified - //! comparison object and allocator. - //! - //! Complexity: Constant. - explicit flat_set(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - {} - - //! Effects: Constructs an empty map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_set(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_unique(first, last); } - - //! Effects: Copy constructs a map. - //! - //! Complexity: Linear in x.size(). - flat_set(const flat_set& x) - : m_flat_tree(x.m_flat_tree) {} - - //! Effects: Move constructs a map. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_set(detail::moved_object > mx) - : m_flat_tree(detail::move_impl(mx.get().m_flat_tree)) {} - #else - flat_set(flat_set && mx) - : m_flat_tree(detail::move_impl(mx.m_flat_tree)) {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_set& operator=(const flat_set& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_set& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - - #else - flat_set& operator=(flat_set &&mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_flat_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_flat_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_flat_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_flat_tree.cbegin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_flat_tree.cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_flat_tree.crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_flat_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_set& x) - #else - void swap(flat_set &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - std::pair insert(const value_type& x) - { return m_flat_tree.insert_unique(x); } - - //! Effects: Inserts a new value_type move constructed from the pair if and - //! only if there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_flat_tree.insert_unique(x); } - #else - std::pair insert(value_type && 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 - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return m_flat_tree.insert_unique(position, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return m_flat_tree.insert_unique(position, x); } - #else - iterator insert(const_iterator position, value_type && x) - { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return m_flat_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_flat_tree.emplace_hint_unique(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_flat_tree.emplace_unique(); } - - iterator emplace_hint(const_iterator hint) - { return m_flat_tree.emplace_hint_unique(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return m_flat_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return m_flat_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_flat_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return m_flat_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_flat_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_flat_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_flat_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_flat_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_flat_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_flat_tree.equal_range(x); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_set&, const flat_set&); - - template - friend bool operator< (const flat_set&, const flat_set&); - /// @endcond -}; - -template -inline bool operator==(const flat_set& x, - const flat_set& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_set& x, - const flat_set& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_set& x, - const flat_set& y) - { return !(x == y); } - -template -inline bool operator>(const flat_set& x, - const flat_set& y) - { return y < x; } - -template -inline bool operator<=(const flat_set& x, - const flat_set& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_set& x, - const flat_set& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_set& x, flat_set& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, flat_set& y) - { x.get().swap(y); } - -template -inline void swap(flat_set& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_set&&x, flat_set&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -class flat_multiset; - -template -inline bool operator==(const flat_multiset& x, - const flat_multiset& y); - -template -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 -{ - /// @cond - private: - typedef detail::flat_tree, Pred, Alloc> tree_t; - tree_t m_flat_tree; // flat tree representing flat_multiset - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::value_compare value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - // allocation/deallocation - explicit flat_multiset(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) {} - - template - flat_multiset(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_equal(first, last); } - - flat_multiset(const flat_multiset& x) - : m_flat_tree(x.m_flat_tree) {} - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multiset(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} - #else - flat_multiset(flat_multiset && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} - #endif - - flat_multiset& operator=(const flat_multiset& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multiset& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_multiset& operator=(flat_multiset && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_flat_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_flat_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_flat_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_flat_tree.cbegin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_flat_tree.cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_flat_tree.crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_flat_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(flat_multiset& x) - #else - void swap(flat_multiset &&x) - #endif - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const value_type& x) - { return m_flat_tree.insert_equal(x); } - - //! Effects: Inserts a new value_type move constructed from x - //! and returns the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return m_flat_tree.insert_equal(x); } - #else - iterator insert(value_type && x) - { return m_flat_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return m_flat_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return m_flat_tree.insert_equal(position, x); } - #else - iterator insert(const_iterator position, value_type && x) - { return m_flat_tree.insert_equal(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return m_flat_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_flat_tree.emplace_hint_equal(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_flat_tree.emplace_equal(); } - - iterator emplace_hint(const_iterator hint) - { return m_flat_tree.emplace_hint_equal(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_flat_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return m_flat_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - size_type erase(const key_type& x) - { return m_flat_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return m_flat_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_flat_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return m_flat_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_flat_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_flat_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_flat_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_flat_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_flat_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_flat_tree.equal_range(x); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: If capacity() is less than "count", iterators and references to - //! to values might be invalidated. - void reserve(size_type count) - { m_flat_tree.reserve(count); } - - /// @cond - template - friend bool operator== (const flat_multiset&, - const flat_multiset&); - template - friend bool operator< (const flat_multiset&, - const flat_multiset&); - /// @endcond -}; - -template -inline bool operator==(const flat_multiset& x, - const flat_multiset& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_multiset& x, - const flat_multiset& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_multiset& x, - const flat_multiset& y) - { return !(x == y); } - -template -inline bool operator>(const flat_multiset& x, - const flat_multiset& y) - { return y < x; } - -template -inline bool operator<=(const flat_multiset& x, - const flat_multiset& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_multiset& x, - const flat_multiset& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_multiset& x, flat_multiset& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, flat_multiset& y) - { x.get().swap(y); } - -template -inline void swap(flat_multiset& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_multiset&&x, flat_multiset&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_FLAT_SET_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index 9f17f5f..1eaf3f6 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -1,1469 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 comes from SGI's stl_list.h file. Modified by Ion Gaztanaga 2004 -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_LIST_HPP_ -#define BOOST_INTERPROCESS_LIST_HPP_ +#ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_LIST_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -//Preprocessor library to emulate perfect forwarding -#include -#endif - -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond -namespace detail { - -template -struct list_hook -{ - typedef typename bi::make_list_base_hook - , bi::link_mode >::type type; -}; - -template -struct list_node - : public list_hook::type -{ - - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - list_node() - : m_data() - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - list_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ - {} \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - list_node(Args &&...args) - : m_data(detail::forward_impl(args)...) - {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - T m_data; -}; - -template -struct intrusive_list_type -{ - typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other - ::type void_pointer; - typedef typename detail::list_node - node_type; - typedef typename bi::make_list - < node_type - , bi::base_hook::type> - , bi::constant_time_size - , bi::size_type - >::type container_type; - typedef container_type type ; -}; - -} //namespace detail { -/// @endcond - -//! A list is a doubly linked list. That is, it is a Sequence that supports both -//! forward and backward traversal, and (amortized) constant time insertion and -//! removal of elements at the beginning or the end, or in the middle. Lists have -//! the important property that insertion and splicing do not invalidate iterators -//! to list elements, and that even removal invalidates only the iterators that point -//! to the elements that are removed. The ordering of iterators may be changed -//! (that is, list::iterator might have a different predecessor or successor -//! after a list operation than it did before), but the iterators themselves will -//! not be invalidated or made to point to different elements unless that invalidation -//! or mutation is explicit. -template -class list - : protected detail::node_alloc_holder - ::type> -{ - /// @cond - typedef typename - detail::intrusive_list_type::type Icont; - typedef list ThisType; - typedef detail::node_alloc_holder AllocHolder; - typedef typename AllocHolder::NodePtr NodePtr; - typedef typename AllocHolder::NodeAlloc NodeAlloc; - typedef typename AllocHolder::ValAlloc ValAlloc; - typedef typename AllocHolder::Node Node; - typedef detail::allocator_destroyer Destroyer; - typedef typename AllocHolder::allocator_v1 allocator_v1; - typedef typename AllocHolder::allocator_v2 allocator_v2; - typedef typename AllocHolder::alloc_version alloc_version; - - class equal_to_value - { - typedef typename AllocHolder::value_type value_type; - const value_type &t_; - - public: - equal_to_value(const value_type &t) - : t_(t) - {} - - bool operator()(const value_type &t)const - { return t_ == t; } - }; - - template - struct ValueCompareToNodeCompare - : Pred - { - ValueCompareToNodeCompare(Pred pred) - : Pred(pred) - {} - - bool operator()(const Node &a, const Node &b) const - { return static_cast(*this)(a.m_data, b.m_data); } - - bool operator()(const Node &a) const - { return static_cast(*this)(a.m_data); } - }; - /// @endcond - - public: - //! The type of object, T, stored in the list - typedef T value_type; - //! Pointer to T - typedef typename A::pointer pointer; - //! Const pointer to T - typedef typename A::const_pointer const_pointer; - //! Reference to T - typedef typename A::reference reference; - //! Const reference to T - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The stored allocator type - typedef NodeAlloc stored_allocator_type; - - /// @cond - private: - typedef difference_type list_difference_type; - typedef pointer list_pointer; - typedef const_pointer list_const_pointer; - typedef reference list_reference; - typedef const_reference list_const_reference; - /// @endcond - - public: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - protected: - typename Icont::iterator m_it; - explicit const_iterator(typename Icont::iterator it) : m_it(it){} - void prot_incr() { ++m_it; } - void prot_decr() { --m_it; } - - private: - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class list; - typedef list_difference_type difference_type; - - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->m_data; } - - const_pointer operator->() const - { return const_pointer(&m_it->m_data); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } - - const_iterator& operator--() - { prot_decr(); return *this; } - - const_iterator operator--(int) - { typename Icont::iterator tmp = m_it; --*this; return const_iterator(tmp); } - - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } - - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - } - /// @endcond - ; - - //! Iterator used to iterate through a list - class iterator - /// @cond - : public const_iterator - { - - private: - explicit iterator(typename Icont::iterator it) - : const_iterator(it) - {} - - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class list; - typedef list_pointer pointer; - typedef list_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } - - iterator& operator--() - { this->prot_decr(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - } - /// @endcond - ; - - //! Iterator used to iterate backwards through a list. - typedef std::reverse_iterator reverse_iterator; - //! Const iterator used to iterate backwards through a list. - typedef std::reverse_iterator const_reverse_iterator; - - //! Effects: Constructs a list taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit list(const allocator_type &a = A()) - : AllocHolder(a) - {} - -// list(size_type n) -// : AllocHolder(detail::move_impl(allocator_type())) -// { this->resize(n); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - list(size_type n, const T& value = T(), const A& a = A()) - : AllocHolder(a) - { this->insert(this->cbegin(), n, value); } - - //! Effects: Copy constructs a list. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - list(const list& x) - : AllocHolder(x) - { this->insert(this->cbegin(), x.begin(), x.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - list(detail::moved_object x) - : AllocHolder(detail::move_impl((AllocHolder&)x.get())) - {} - #else - list(list &&x) - : AllocHolder(detail::move_impl((AllocHolder&)x)) - {} - #endif - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the list. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - list(InpIt first, InpIt last, const A &a = A()) - : AllocHolder(a) - { this->insert(this->cbegin(), first, last); } - - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~list() - {} //AllocHolder clears the list - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return allocator_type(this->node_alloc()); } - - const stored_allocator_type &get_stored_allocator() const - { return this->node_alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->node_alloc(); } - - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { AllocHolder::clear(alloc_version()); } - - //! Effects: Returns an iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->icont().begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->cbegin(); } - - //! Effects: Returns an iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->icont().end()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return this->crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(begin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return this->crend(); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->non_const_icont().begin()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->non_const_icont().end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return const_reverse_iterator(this->cend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return const_reverse_iterator(this->cbegin()); } - - //! Effects: Returns true if the list contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } - - //! Effects: Returns the number of the elements contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->icont().size(); } - - //! Effects: Returns the largest possible size of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return AllocHolder::max_size(); } - - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const T& x) - { this->insert(this->cbegin(), x); } - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object x) - { this->insert(this->cbegin(), x); } - #else - void push_front(T &&x) - { this->insert(this->cbegin(), detail::move_impl(x)); } - #endif - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void push_back (const T& x) - { this->insert(this->cend(), x); } - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back (detail::moved_object x) - { this->insert(this->cend(), x); } - #else - void push_back (T &&x) - { this->insert(this->cend(), detail::move_impl(x)); } - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->erase(this->cbegin()); } - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_back() - { const_iterator tmp = this->cend(); this->erase(--tmp); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return *(--this->end()); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const - { return *(--this->end()); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - const_iterator iend = this->cend(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - while(to_erase--){ - --iend; - } - this->erase(iend, this->cend()); - } - else{ - this->priv_create_and_insert_nodes(iend, new_size - len, x); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - const_iterator iend = this->end(); - size_type len = this->size(); - - if(len > new_size){ - size_type to_erase = len - new_size; - const_iterator ifirst; - if(to_erase < len/2u){ - ifirst = iend; - while(to_erase--){ - --ifirst; - } - } - 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->cend(), new_size - len); - } - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(ThisType& x) - #else - void swap(ThisType &&x) - #endif - { AllocHolder::swap(x); } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - ThisType& operator=(const ThisType& x) - { - if (this != &x) { - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - ThisType& operator=(detail::moved_object mx) - { - this->clear(); - this->swap(mx.get()); - return *this; - } - #else - ThisType& operator=(ThisType &&mx) - { - this->clear(); - this->swap(mx); - return *this; - } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->priv_create_and_insert_nodes(p, n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator p, InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Amortized constant time. - iterator insert(const_iterator p, const T& x) - { - NodePtr tmp = AllocHolder::create_node(x); - return iterator(this->icont().insert(p.get(), *tmp)); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { - NodePtr tmp = AllocHolder::create_node(x); - return iterator(this->icont().insert(p.get(), *tmp)); - } - #else - iterator insert(const_iterator p, T &&x) - { - NodePtr tmp = AllocHolder::create_node(detail::move_impl(x)); - return iterator(this->icont().insert(p.get(), *tmp)); - } - #endif - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_back(Args&&... args) - { - this->emplace(this->cend(), detail::forward_impl(args)...); - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_front(Args&&... args) - { - this->emplace(this->cbegin(), detail::forward_impl(args)...); - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - iterator emplace(const_iterator p, Args&&... args) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(detail::forward_impl(args)...); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert(p.get(), *node)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //0 args - void emplace_back() - { this->emplace(this->cend()); } - - void emplace_front() - { this->emplace(this->cbegin()); } - - iterator emplace(const_iterator p) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert(p.get(), *node)); - } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - this->emplace(this->cend(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - } \ - \ - template \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { this->emplace(this->cbegin(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));} \ - \ - template \ - iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ - new ((void*)detail::get_pointer(d.get())) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - NodePtr node = d.get(); \ - d.release(); \ - return iterator(this->icont().insert(p.get(), *node)); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - iterator erase(const_iterator p) - { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last. - iterator erase(const_iterator first, const_iterator last) - { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(iterator p, detail::moved_object x) - { this->splice(p, x.get()); } - void splice(iterator p, ThisType& x) - #else - void splice(iterator p, ThisType&& x) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont()); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! If p == i or p == ++i, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator i) - { this->splice(p, x.get(), i); } - void splice(const_iterator p, ThisType &x, const_iterator i) - #else - void splice(const_iterator p, ThisType &&x, const_iterator i) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont(), i.get()); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the number of elements transferred. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator first, const_iterator last) - { this->splice(p, x.get(), first, last); } - void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) - #else - void splice(const_iterator p, ThisType &&x, const_iterator first, const_iterator last) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont(), first.get(), last.get()); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! n == std::distance(first, last) - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator first, const_iterator last, size_type n) - { this->splice(p, x.get(), first, last, n); } - void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) - #else - void splice(const_iterator p, ThisType &&x, const_iterator first, const_iterator last, size_type n) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); - } - else{ - throw std::runtime_error("list::splice called with unequal allocators"); - } - } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } - - //! Effects: Removes all the elements that compare equal to value. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time. It performs exactly size() comparisons for equality. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void remove(const T& value) - { remove_if(equal_to_value(value)); } - - //! Effects: Removes all the elements for which a specified - //! predicate is satisfied. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time. It performs exactly size() calls to the predicate. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void remove_if(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that are equal from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time (size()-1 comparisons calls to pred()). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void unique() - { this->unique(value_equal()); } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that satisfy some binary predicate from the list. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time (size()-1 comparisons equality comparisons). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void unique(BinaryPredicate binary_pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc())); - } - - //! Requires: The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this according to std::less. The merge is stable; - //! that is, if an element from *this is equivalent to one from x, then the element - //! from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void merge(detail::moved_object > x) - { this->merge(x.get()); } - void merge(list& x) - #else - void merge(list&& x) - #endif - { this->merge(x, value_less()); } - - //! Requires: p must be a comparison function that induces a strict weak - //! ordering and both *this and x must be sorted according to that ordering - //! The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this. The merge is stable; that is, if an element from *this is - //! equivalent to one from x, then the element from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - template - void merge(detail::moved_object > x, StrictWeakOrdering comp) - { this->merge(x.get(), comp); } - template - void merge(list& x, StrictWeakOrdering comp) - #else - template - void merge(list&& x, StrictWeakOrdering comp) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().merge(x.icont(), - ValueCompareToNodeCompare(comp)); - } - else{ - throw std::runtime_error("list::merge called with unequal allocators"); - } - } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - void sort() - { this->sort(value_less()); } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - template - void sort(StrictWeakOrdering comp) - { - // nothing if the list has length 0 or 1. - if (this->size() < 2) - return; - this->icont().sort(ValueCompareToNodeCompare(comp)); - } - - /// @cond - private: - - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert(pos.get(), *this->create_node_from_it(beg)); - } - } - - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag()); - } - - class insertion_functor; - friend class insertion_functor; - - class insertion_functor - { - Icont &icont_; - typename Icont::const_iterator pos_; - - public: - insertion_functor(Icont &icont, typename Icont::const_iterator pos) - : icont_(icont), pos_(pos) - {} - - void operator()(Node &n) - { this->icont_.insert(pos_, n); } - }; - - - template - void priv_create_and_insert_nodes - (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - if(beg != end){ - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get())); - } - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator p, - InputIter first, InputIter last, - detail::false_) - { this->priv_create_and_insert_nodes(p, first, last); } - - template - void priv_insert_dispatch(const_iterator p, Integer n, Integer x, detail::true_) - { this->insert(p, (size_type)n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator i = this->begin(), iend = this->end(); - - for ( ; i != iend && n > 0; ++i, --n) - *i = val; - if (n > 0){ - this->priv_create_and_insert_nodes(this->cend(), n, val); - } - else{ - this->erase(i, cend()); - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InputIter first2, InputIter last2, detail::false_) - { - iterator first1 = this->begin(); - iterator last1 = this->end(); - for ( ; first1 != last1 && first2 != last2; ++first1, ++first2) - *first1 = *first2; - if (first2 == last2) - this->erase(first1, last1); - else{ - this->priv_create_and_insert_nodes(last1, first2, last2); - } - } - - //Functors for member algorithm defaults - struct value_less - { - bool operator()(const value_type &a, const value_type &b) const - { return a < b; } - }; - - struct value_equal - { - bool operator()(const value_type &a, const value_type &b) const - { return a == b; } - }; - /// @endcond - -}; - -template -inline bool operator==(const list& x, const list& y) -{ - if(x.size() != y.size()){ - return false; - } - typedef typename list::const_iterator const_iterator; - const_iterator end1 = x.end(); - - const_iterator i1 = x.begin(); - const_iterator i2 = y.begin(); - while (i1 != end1 && *i1 == *i2) { - ++i1; - ++i2; - } - return i1 == end1; -} - -template -inline bool operator<(const list& x, - const list& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); -} - -template -inline bool operator!=(const list& x, const list& y) -{ - return !(x == y); -} - -template -inline bool operator>(const list& x, const list& y) -{ - return y < x; -} - -template -inline bool operator<=(const list& x, const list& y) -{ - return !(y < x); -} - -template -inline bool operator>=(const list& x, const list& y) -{ - return !(x < y); -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(list& x, list& y) -{ - x.swap(y); -} - -template -inline void swap(detail::moved_object >& x, list y) -{ - x.get().swap(y); -} - -template -inline void swap(list& x, detail::moved_object > y) -{ - x.swap(y.get()); -} -#else -template -inline void swap(list &&x, list &&y) -{ - x.swap(y); -} - -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/* -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -*/ -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::list; } //namespace interprocess { } //namespace boost { #include -#endif // BOOST_INTERPROCESS_LIST_HPP_ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP + diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index 2d7f1a3..a5f0d41 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -1,1313 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 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. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_MAP_HPP -#define BOOST_INTERPROCESS_MAP_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_MAP_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { -namespace boost { namespace interprocess { +using boost::interprocess_container::map; +using boost::interprocess_container::multimap; -/// @cond -// Forward declarations of operators == and <, needed for friend declarations. -template -inline bool operator==(const map& x, - const map& y); - -template -inline bool operator<(const map& x, - const map& y); -/// @endcond - -//! A map is a kind of associative container that supports unique keys (contains at -//! most one of each key value) and provides for fast retrieval of values of another -//! type T based on the keys. The map class supports bidirectional iterators. -//! -//! A map satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! map the key_type is Key and the value_type is std::pair. -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -template -class map -{ - /// @cond - private: - typedef detail::rbtree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - tree_t m_tree; // red-black tree representing map - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef T mapped_type; - typedef Pred key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - /// @cond - class value_compare_impl - : public Pred, - public std::binary_function - { - friend class map; - protected : - value_compare_impl(const Pred &c) : Pred(c) {} - public: - bool operator()(const value_type& x, const value_type& y) const { - return Pred::operator()(x.first, y.first); - } - }; - /// @endcond - typedef value_compare_impl value_compare; - - //! Effects: Constructs an empty map using the specified comparison object - //! and allocator. - //! - //! Complexity: Constant. - explicit map(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - map(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) - {} - - //! Effects: Copy constructs a map. - //! - //! Complexity: Linear in x.size(). - map(const map& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a map. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - map(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - map(map &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - map& operator=(const map& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - map& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - map& operator=(map &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(m_tree.key_comp()); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(x, T()) into the map. - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - T& operator[](const key_type& k) - { - //we can optimize this - 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, 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(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. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - T& operator[](detail::moved_object mk) - { - key_type &k = mk.get(); - //we can optimize this - 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, detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; - } - #else - T& operator[](key_type &&mk) - { - key_type &k = mk; - //we can optimize this - 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(detail::move_impl(k), detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; - } - #endif - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - T& at(const key_type& k) - { - iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Returns: A reference to the element whose key is equivalent to x. - //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. - const T& at(const key_type& k) const - { - const_iterator i = this->find(k); - if(i == this->end()){ - throw std::out_of_range("key not found"); - } - return i->second; - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(map& x) - #else - void swap(map &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - std::pair insert(const value_type& x) - { return m_tree.insert_unique(x); } - - //! Effects: Inserts a new value_type created from the pair if and only if - //! there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - std::pair insert(const std::pair& x) - { return m_tree.insert_unique(x); } - - //! Effects: Inserts a new value_type move constructed from the pair if and - //! only if there is no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object > x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(std::pair &&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 - //! no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(value_type &&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 - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const value_type& x) - { return m_tree.insert_unique(position, x); } - - //! Effects: Move constructs a new value from x if and only if there is - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object > x) - { return m_tree.insert_unique(position, x); } - #else - iterator insert(iterator position, std::pair &&x) - { return m_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - iterator insert(iterator position, const std::pair& x) - { return m_tree.insert_unique(position, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object x) - { return m_tree.insert_unique(position, x); } - #else - iterator insert(iterator position, value_type &&x) - { return m_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with an equivalent key. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container if and only if there is - //! no element in the container with an equivalent key. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_unique(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_unique(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_unique(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));}\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator position) - { return m_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const map&, - const map&); - template - friend bool operator< (const map&, - const map&); - /// @endcond -}; - -template -inline bool operator==(const map& x, - const map& y) - { return x.m_tree == y.m_tree; } - -template -inline bool operator<(const map& x, - const map& y) - { return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const map& x, - const map& y) - { return !(x == y); } - -template -inline bool operator>(const map& x, - const map& y) - { return y < x; } - -template -inline bool operator<=(const map& x, - const map& y) - { return !(y < x); } - -template -inline bool operator>=(const map& x, - const map& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(map& x, map& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, map& y) - { x.get().swap(y); } - -template -inline void swap(map& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(map&&x, map&&y) - { x.swap(y); } -#endif - - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -inline bool operator==(const multimap& x, - const multimap& y); - -template -inline bool operator<(const multimap& x, - const multimap& y); - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -//! A multimap is a kind of associative container that supports equivalent keys -//! (possibly containing multiple copies of the same key value) and provides for -//! fast retrieval of values of another type T based on the keys. The multimap class -//! supports bidirectional iterators. -//! -//! A multimap satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. For a -//! map the key_type is Key and the value_type is std::pair. -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//!(e.g. boost::interprocess:allocator< std::pair<const Key, T>). -template -class multimap -{ - /// @cond - private: - typedef detail::rbtree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - tree_t m_tree; // red-black tree representing map - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef T mapped_type; - typedef Pred key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - /// @cond - class value_compare_impl - : public Pred, - public std::binary_function - { - friend class multimap; - protected : - value_compare_impl(const Pred &c) : Pred(c) {} - public: - bool operator()(const value_type& x, const value_type& y) const { - return Pred::operator()(x.first, y.first); - } - }; - /// @endcond - typedef value_compare_impl value_compare; - - //! Effects: Constructs an empty multimap using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit multimap(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty multimap using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - multimap(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) - {} - - //! Effects: Copy constructs a multimap. - //! - //! Complexity: Linear in x.size(). - multimap(const multimap& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a multimap. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multimap(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - multimap(multimap && x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - multimap& - operator=(const multimap& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multimap& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - multimap& operator=(multimap && x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(m_tree.key_comp()); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(multimap& x) - #else - void swap(multimap &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const value_type& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a new value constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const std::pair& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a new value move-constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object > x) - { return m_tree.insert_equal(x); } - #else - iterator insert(std::pair && x) - { return m_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const value_type& x) - { return m_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const std::pair& x) - { return m_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object > x) - { return m_tree.insert_equal(position, x); } - #else - iterator insert(iterator position, std::pair && x) - { return m_tree.insert_equal(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_equal(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_equal(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_equal(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator position) - { return m_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - {return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const multimap& x, - const multimap& y); - - template - friend bool operator< (const multimap& x, - const multimap& y); - /// @endcond -}; - -template -inline bool operator==(const multimap& x, - const multimap& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const multimap& x, - const multimap& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const multimap& x, - const multimap& y) -{ return !(x == y); } - -template -inline bool operator>(const multimap& x, - const multimap& y) -{ return y < x; } - -template -inline bool operator<=(const multimap& x, - const multimap& y) -{ return !(y < x); } - -template -inline bool operator>=(const multimap& x, - const multimap& y) -{ return !(x < y); } - - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(multimap& x, multimap& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, multimap& y) -{ x.get().swap(y); } - -template -inline void swap(multimap& x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(multimap&&x, multimap&&y) -{ x.swap(y); } -#endif - -/// @cond -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_MAP_HPP */ - +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP diff --git a/include/boost/interprocess/containers/pair.hpp b/include/boost/interprocess/containers/pair.hpp new file mode 100644 index 0000000..0510d1a --- /dev/null +++ b/include/boost/interprocess/containers/pair.hpp @@ -0,0 +1,32 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_PAIR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::interprocess_container::containers_detail::pair; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index 0908116..53d36c0 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -1,1186 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztanaga 2004. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_SET_HPP -#define BOOST_INTERPROCESS_SET_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SET_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include -#include +#include -#include -#include -#include +namespace boost { +namespace interprocess { -#include -#include -#include -#include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include -#endif +using boost::interprocess_container::set; +using boost::interprocess_container::multiset; -namespace boost { namespace interprocess { - -/// @cond -// Forward declarations of operators < and ==, needed for friend declaration. -template -inline bool operator==(const set& x, - const set& y); - -template -inline bool operator<(const set& x, - const set& y); -/// @endcond - -//! A set is a kind of associative container that supports unique keys (contains at -//! most one of each key value) and provides for fast retrieval of the keys themselves. -//! Class set supports bidirectional iterators. -//! -//! A set satisfies all of the requirements of a container and of a reversible container -//! , and of an associative container. A set also provides most operations described in -//! for unique keys. -template -class set -{ - /// @cond - private: - typedef detail::rbtree, Pred, Alloc> tree_t; - tree_t m_tree; // red-black tree representing set - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef Pred key_compare; - typedef Pred value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty set using the specified comparison object - //! and allocator. - //! - //! Complexity: Constant. - explicit set(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty set using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - set(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) - {} - - //! Effects: Copy constructs a set. - //! - //! Complexity: Linear in x.size(). - set(const set& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a set. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - set(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - set(set &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - set& operator=(const set& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - set& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - set& operator=(set &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_tree.cbegin(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_tree.cend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_tree.crbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(set& x) - #else - void swap(set &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - std::pair insert(const value_type& x) - { return m_tree.insert_unique(x); } - - //! Effects: Move constructs a new value from x if and only if there is - //! no element in the container with key equivalent to the key of x. - //! - //! Returns: The bool component of the returned pair is true if and only - //! if the insertion takes place, and the iterator component of the pair - //! points to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(value_type &&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 - //! no element in the container with key equivalent to the key of x. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(const_iterator p, const value_type& x) - { return m_tree.insert_unique(p, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return m_tree.insert_unique(p, x); } - #else - iterator insert(const_iterator p, value_type &&x) - { return m_tree.insert_unique(p, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) if and only - //! if there is no element with key equivalent to the key of that element. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is - //! no element in the container with equivalent value. - //! and returns the iterator pointing to the - //! newly inserted element. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Logarithmic. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is - //! no element in the container with equivalent value. - //! p is a hint pointing to where the insert - //! should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_unique(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_unique(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_unique(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));}\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by p. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator p) - { return m_tree.erase(p); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const set&, const set&); - - template - friend bool operator< (const set&, const set&); - /// @endcond -}; - -template -inline bool operator==(const set& x, - const set& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const set& x, - const set& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const set& x, - const set& y) -{ return !(x == y); } - -template -inline bool operator>(const set& x, - const set& y) -{ return y < x; } - -template -inline bool operator<=(const set& x, - const set& y) -{ return !(y < x); } - -template -inline bool operator>=(const set& x, - const set& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(set& x, set& y) -{ x.swap(y); } - -template -inline void swap(set& x, detail::moved_object >& y) -{ x.swap(y.get()); } - -template -inline void swap(detail::moved_object >& y, set& x) -{ y.swap(x.get()); } - -#else -template -inline void swap(set&&x, set&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -inline bool operator==(const multiset& x, - const multiset& y); - -template -inline bool operator<(const multiset& x, - const multiset& y); -/// @endcond - -//! A multiset is a kind of associative container that supports equivalent keys -//! (possibly contains multiple copies of the same key value) and provides for -//! fast retrieval of the keys themselves. Class multiset supports bidirectional iterators. -//! -//! A multiset satisfies all of the requirements of a container and of a reversible -//! container, and of an associative container). multiset also provides most operations -//! described for duplicate keys. -template -class multiset -{ - /// @cond - private: - typedef detail::rbtree, Pred, Alloc> tree_t; - tree_t m_tree; // red-black tree representing multiset - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef Pred key_compare; - typedef Pred value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty multiset using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit multiset(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty multiset using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - multiset(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) - {} - - //! Effects: Copy constructs a multiset. - //! - //! Complexity: Linear in x.size(). - multiset(const multiset& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a multiset. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multiset(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - multiset(multiset &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - multiset& operator=(const multiset& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multiset& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - multiset& operator=(multiset &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return m_tree.get_allocator(); } - - const stored_allocator_type &get_stored_allocator() const - { return m_tree.get_stored_allocator(); } - - stored_allocator_type &get_stored_allocator() - { return m_tree.get_stored_allocator(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_tree.cbegin(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_tree.cend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_tree.crbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(multiset& x) - #else - void swap(multiset &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const value_type& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a copy of x in the container. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return m_tree.insert_equal(x); } - #else - iterator insert(value_type && x) - { return m_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(const_iterator p, const value_type& x) - { return m_tree.insert_equal(p, x); } - - //! Effects: Inserts a value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return m_tree.insert_equal(p, x); } - #else - iterator insert(const_iterator p, value_type && x) - { return m_tree.insert_equal(p, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_equal(hint, detail::forward_impl(args)...); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return m_tree.emplace_equal(); } - - iterator emplace_hint(const_iterator hint) - { return m_tree.emplace_hint_equal(hint); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element pointed to by p. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator p) - { return m_tree.erase(p); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: log(size())+N where N is the distance from first to last. - iterator erase(const_iterator first, const_iterator last) - { return m_tree.erase(first, last); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const multiset&, - const multiset&); - template - friend bool operator< (const multiset&, - const multiset&); - /// @endcond -}; - -template -inline bool operator==(const multiset& x, - const multiset& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const multiset& x, - const multiset& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const multiset& x, - const multiset& y) -{ return !(x == y); } - -template -inline bool operator>(const multiset& x, - const multiset& y) -{ return y < x; } - -template -inline bool operator<=(const multiset& x, - const multiset& y) -{ return !(y < x); } - -template -inline bool operator>=(const multiset& x, - const multiset& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(multiset& x, multiset& y) -{ x.swap(y); } - -template -inline void swap(multiset& x, detail::moved_object >& y) -{ x.swap(y.get()); } - -template -inline void swap(detail::moved_object >& y, multiset& x) -{ y.swap(x.get()); } -#else -template -inline void swap(multiset&&x, multiset&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_SET_HPP */ - +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 4b0728d..7a3cafd 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -1,1642 +1,31 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2004-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 comes from SGI's stl_slist.h file. Modified by Ion Gaztanaga 2004-2008 -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef BOOST_INTERPROCESS_SLIST_HPP -#define BOOST_INTERPROCESS_SLIST_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { +using boost::interprocess_container::slist; -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -//Preprocessor library to emulate perfect forwarding -#include -#endif - -#include -#include -#include -#include -#include - -namespace boost{ namespace interprocess{ - -/// @cond - -namespace detail { - -template -struct slist_hook -{ - typedef typename bi::make_slist_base_hook - , bi::link_mode >::type type; -}; - -template -struct slist_node - : public slist_hook::type -{ - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - slist_node() - : m_data() - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - slist_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ - {} \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - slist_node(Args &&...args) - : m_data(detail::forward_impl(args)...) - {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - T m_data; -}; - -template -struct intrusive_slist_type -{ - typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other - ::type void_pointer; - typedef typename detail::slist_node - node_type; - - typedef typename bi::make_slist - ::type> - ,bi::constant_time_size - ,bi::size_type - >::type container_type; - typedef container_type type ; -}; - -} //namespace detail { - -/// @endcond - -//! An slist is a singly linked list: a list where each element is linked to the next -//! element, but not to the previous element. That is, it is a Sequence that -//! supports forward but not backward traversal, and (amortized) constant time -//! insertion and removal of elements. Slists, like lists, have the important -//! property that insertion and splicing do not invalidate iterators to list elements, -//! and that even removal invalidates only the iterators that point to the elements -//! that are removed. The ordering of iterators may be changed (that is, -//! slist::iterator might have a different predecessor or successor after a list -//! operation than it did before), but the iterators themselves will not be invalidated -//! or made to point to different elements unless that invalidation or mutation is explicit. -//! -//! The main difference between slist and list is that list's iterators are bidirectional -//! iterators, while slist's iterators are forward iterators. This means that slist is -//! less versatile than list; frequently, however, bidirectional iterators are -//! unnecessary. You should usually use slist unless you actually need the extra -//! functionality of list, because singly linked lists are smaller and faster than double -//! linked lists. -//! -//! Important performance note: like every other Sequence, slist defines the member -//! functions insert and erase. Using these member functions carelessly, however, can -//! result in disastrously slow programs. The problem is that insert's first argument is -//! an iterator p, and that it inserts the new element(s) before p. This means that -//! insert must find the iterator just before p; this is a constant-time operation -//! for list, since list has bidirectional iterators, but for slist it must find that -//! iterator by traversing the list from the beginning up to p. In other words: -//! insert and erase are slow operations anywhere but near the beginning of the slist. -//! -//! Slist provides the member functions insert_after and erase_after, which are constant -//! time operations: you should always use insert_after and erase_after whenever -//! possible. If you find that insert_after and erase_after aren't adequate for your -//! needs, and that you often need to use insert and erase in the middle of the list, -//! then you should probably use list instead of slist. -template -class slist - : protected detail::node_alloc_holder - ::type> -{ - /// @cond - typedef typename - detail::intrusive_slist_type::type Icont; - typedef detail::node_alloc_holder AllocHolder; - typedef typename AllocHolder::NodePtr NodePtr; - typedef slist ThisType; - typedef typename AllocHolder::NodeAlloc NodeAlloc; - typedef typename AllocHolder::ValAlloc ValAlloc; - typedef typename AllocHolder::Node Node; - typedef detail::allocator_destroyer Destroyer; - typedef typename AllocHolder::allocator_v1 allocator_v1; - typedef typename AllocHolder::allocator_v2 allocator_v2; - typedef typename AllocHolder::alloc_version alloc_version; - - class equal_to_value - { - typedef typename AllocHolder::value_type value_type; - const value_type &t_; - - public: - equal_to_value(const value_type &t) - : t_(t) - {} - - bool operator()(const value_type &t)const - { return t_ == t; } - }; - - template - struct ValueCompareToNodeCompare - : Pred - { - ValueCompareToNodeCompare(Pred pred) - : Pred(pred) - {} - - bool operator()(const Node &a, const Node &b) const - { return static_cast(*this)(a.m_data, b.m_data); } - - bool operator()(const Node &a) const - { return static_cast(*this)(a.m_data); } - }; - /// @endcond - public: - //! The type of object, T, stored in the list - typedef T value_type; - //! Pointer to T - typedef typename A::pointer pointer; - //! Const pointer to T - typedef typename A::const_pointer const_pointer; - //! Reference to T - typedef typename A::reference reference; - //! Const reference to T - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The stored allocator type - typedef NodeAlloc stored_allocator_type; - - /// @cond - private: - typedef difference_type list_difference_type; - typedef pointer list_pointer; - typedef const_pointer list_const_pointer; - typedef reference list_reference; - typedef const_reference list_const_reference; - /// @endcond - - public: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - protected: - typename Icont::iterator m_it; - explicit const_iterator(typename Icont::iterator it) : m_it(it){} - void prot_incr(){ ++m_it; } - - private: - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class slist; - typedef list_difference_type difference_type; - - //Constructors - const_iterator() - : m_it() - {} - - //Pointer like operators - const_reference operator*() const - { return m_it->m_data; } - - const_pointer operator->() const - { return const_pointer(&m_it->m_data); } - - //Increment / Decrement - const_iterator& operator++() - { prot_incr(); return *this; } - - const_iterator operator++(int) - { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); } - - //Comparison operators - bool operator== (const const_iterator& r) const - { return m_it == r.m_it; } - - bool operator!= (const const_iterator& r) const - { return m_it != r.m_it; } - } - /// @endcond - ; - - //! Iterator used to iterate through a list - class iterator - /// @cond - : public const_iterator - { - - private: - explicit iterator(typename Icont::iterator it) - : const_iterator(it) - {} - - typename Icont::iterator get() - { return this->m_it; } - - public: - friend class slist; - typedef list_pointer pointer; - typedef list_reference reference; - - //Constructors - iterator(){} - - //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } - - //Increment / Decrement - iterator& operator++() - { this->prot_incr(); return *this; } - - iterator operator++(int) - { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); } - } - /// @endcond - ; - - public: - //! Effects: Constructs a list taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit slist(const allocator_type& a = allocator_type()) - : AllocHolder(a) - {} - -// explicit slist(size_type n) -// : AllocHolder(detail::move_impl(allocator_type())) -// { this->resize(n); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - explicit slist(size_type n, const value_type& x = value_type(), - const allocator_type& a = allocator_type()) - : AllocHolder(a) - { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the list. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - slist(InpIt first, InpIt last, - const allocator_type& a = allocator_type()) - : AllocHolder(a) - { this->insert_after(this->before_begin(), first, last); } - - //! Effects: Copy constructs a list. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - slist(const slist& x) - : AllocHolder(x) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - slist(detail::moved_object x) - : AllocHolder(detail::move_impl((AllocHolder&)x.get())) - {} - #else - slist(slist &&x) - : AllocHolder(detail::move_impl((AllocHolder&)x)) - {} - #endif - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - slist& operator= (const slist& x) - { - if (&x != this){ - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - slist& operator= (detail::moved_object mx) - { - if (&mx.get() != this){ - this->clear(); - this->swap(mx.get()); - } - return *this; - } - #else - slist& operator= (slist && mx) - { - if (&mx != this){ - this->clear(); - this->swap(mx); - } - return *this; - } - #endif - - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~slist() - {} //AllocHolder clears the slist - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return allocator_type(this->node_alloc()); } - - const stored_allocator_type &get_stored_allocator() const - { return this->node_alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->node_alloc(); } - - public: - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - //! Effects: Assigns the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Returns an iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->icont().begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->cbegin(); } - - //! Effects: Returns an iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->icont().end()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a non-dereferenceable iterator that, - //! when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator before_begin() - { return iterator(end()); } - - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator before_begin() const - { return this->cbefore_begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->non_const_icont().begin()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->non_const_icont().end()); } - - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbefore_begin() const - { return const_iterator(end()); } - - //! Effects: Returns the number of the elements contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->icont().size(); } - - //! Effects: Returns the largest possible size of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return AllocHolder::max_size(); } - - //! Effects: Returns true if the list contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements on *this and x. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(slist& x) - #else - void swap(slist &&x) - #endif - { AllocHolder::swap(x); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->begin(); } - - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const value_type& x) - { this->icont().push_front(*this->create_node(x)); } - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object x) - { this->icont().push_front(*this->create_node(x)); } - #else - void push_front(T && x) - { this->icont().push_front(*this->create_node(detail::move_impl(x))); } - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } - - //! Returns: The iterator to the element before i in the sequence. - //! Returns the end-iterator, if either i is the begin-iterator or the - //! sequence is empty. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - iterator previous(iterator p) - { return iterator(this->icont().previous(p.get())); } - - //! Returns: The const_iterator to the element before i in the sequence. - //! Returns the end-const_iterator, if either i is the begin-const_iterator or - //! the sequence is empty. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - const_iterator previous(const_iterator p) - { return const_iterator(this->icont().previous(p.get())); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts a copy of the value after the p pointed - //! by prev_p. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - iterator insert_after(const_iterator prev_pos, const value_type& x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts a move constructed copy object from the value after the - //! p pointed by prev_pos. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert_after(const_iterator prev_pos, detail::moved_object x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } - #else - iterator insert_after(const_iterator prev_pos, value_type && 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. - //! - //! Effects: Inserts n copies of x after prev_pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - void insert_after(const_iterator prev_pos, size_type n, const value_type& x) - { this->priv_create_and_insert_nodes(prev_pos, n, x); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts the range pointed by [first, last) - //! after the p prev_pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to the number of elements inserted. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - template - void insert_after(const_iterator prev_pos, InIter first, InIter last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Linear to the elements before p. - iterator insert(const_iterator p, const value_type& x) - { return this->insert_after(previous(p), x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Linear to the elements before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return this->insert_after(previous(p), x); } - #else - iterator insert(const_iterator p, value_type && x) - { return this->insert_after(previous(p), detail::move_impl(x)); } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n plus linear to the elements before p. - void insert(const_iterator p, size_type n, const value_type& x) - { return this->insert_after(previous(p), n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last) plus - //! linear to the elements before p. - template - void insert(const_iterator p, InIter first, InIter last) - { return this->insert_after(previous(p), first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the front of the list - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - template - void emplace_front(Args&&... args) - { this->emplace_after(this->cbefore_begin(), detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Linear to the elements before p - template - iterator emplace(const_iterator p, Args&&... args) - { return this->emplace_after(this->previous(p), detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... after prev - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - iterator emplace_after(const_iterator prev, Args&&... args) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(detail::forward_impl(args)...); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert_after(prev.get(), *node)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //0 args - void emplace_front() - { this->emplace_after(this->cbefore_begin()); } - - iterator emplace(const_iterator p) - { return this->emplace_after(this->previous(p)); } - - iterator emplace_after(const_iterator prev) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(); - NodePtr node = d.get(); - d.release(); - return iterator(this->icont().insert_after(prev.get(), *node)); - } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - this->emplace \ - (this->cbegin(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - } \ - \ - template \ - iterator emplace \ - (const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return this->emplace_after \ - (this->previous(p), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - } \ - \ - template \ - iterator emplace_after \ - (const_iterator prev, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ - new ((void*)detail::get_pointer(d.get())) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - NodePtr node = d.get(); \ - d.release(); \ - return iterator(this->icont().insert_after(prev.get(), *node)); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Erases the element after the element pointed by prev_pos - //! of the list. - //! - //! Returns: the first element remaining beyond the removed elements, - //! or end() if no such element exists. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Does not invalidate iterators or references to non erased elements. - iterator erase_after(const_iterator prev_pos) - { - return iterator(this->icont().erase_after_and_dispose(prev_pos.get(), Destroyer(this->node_alloc()))); - } - - //! Effects: Erases the range (before_first, last) from - //! the list. - //! - //! Returns: the first element remaining beyond the removed elements, - //! or end() if no such element exists. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of erased elements. - //! - //! Note: Does not invalidate iterators or references to non erased elements. - iterator erase_after(const_iterator before_first, const_iterator last) - { - return iterator(this->icont().erase_after_and_dispose(before_first.get(), last.get(), Destroyer(this->node_alloc()))); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before p. - iterator erase(const_iterator p) - { return iterator(this->erase_after(previous(p))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last plus - //! linear to the elements before first. - iterator erase(const_iterator first, const_iterator last) - { return iterator(this->erase_after(previous(first), last)); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - while (++(cur_next = cur) != end_n && new_size > 0){ - --new_size; - cur = cur_next; - } - if (cur_next != end_n) - this->erase_after(const_iterator(cur), const_iterator(end_n)); - else - this->insert_after(const_iterator(cur), new_size, x); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next; - size_type len = this->size(); - size_type left = new_size; - - while (++(cur_next = cur) != end_n && left > 0){ - --left; - cur = cur_next; - } - if (cur_next != end_n){ - this->erase_after(const_iterator(cur), const_iterator(end_n)); - } - else{ - this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); - } - } - - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, after the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the elements in x. - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x) - { this->splice_after(prev_pos, x.get()); } - void splice_after(const_iterator prev_pos, slist& x) - #else - void splice_after(const_iterator prev_pos, slist&& x) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after(prev_pos.get(), x.icont()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! after the element pointed by prev_pos. - //! If prev_pos == prev or prev_pos == ++prev, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x, const_iterator prev) - { this->splice_after(prev_pos, x.get(), prev); } - void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) - #else - void splice_after(const_iterator prev_pos, slist&& x, const_iterator prev) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! before_first and before_last must be valid iterators of x. - //! prev_pos must not be contained in [before_first, before_last) range. - //! - //! Effects: Transfers the range [before_first + 1, before_last + 1) - //! from list x to this list, after the element pointed by prev_pos. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the number of transferred elements. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x, - const_iterator before_first, const_iterator before_last) - { this->splice_after(prev_pos, x.get(), before_first, before_last); } - void splice_after(const_iterator prev_pos, slist& x, - const_iterator before_first, const_iterator before_last) - #else - void splice_after(const_iterator prev_pos, slist&& x, - const_iterator before_first, const_iterator before_last) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after - (prev_pos.get(), x.icont(), before_first.get(), before_last.get()); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! before_first and before_last must be valid iterators of x. - //! prev_pos must not be contained in [before_first, before_last) range. - //! n == std::distance(before_first, before_last) - //! - //! Effects: Transfers the range [before_first + 1, before_last + 1) - //! from list x to this list, after the element pointed by prev_pos. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object x, - const_iterator before_first, const_iterator before_last, - size_type n) - { this->splice_after(prev_pos, x.get(), before_first, before_last, n); } - void splice_after(const_iterator prev_pos, slist& x, - const_iterator before_first, const_iterator before_last, - size_type n) - #else - void splice_after(const_iterator prev_pos, slist&& x, - const_iterator before_first, const_iterator before_last, - size_type n) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().splice_after - (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n); - } - else{ - throw std::runtime_error("slist::splice called with unequal allocators"); - } - } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and linear in x.size(). - //! - //! Note: Iterators of values obtained from list x now point to elements of - //! this list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x) - { this->splice(p, x.get()); } - void splice(const_iterator p, ThisType& x) - #else - void splice(const_iterator p, ThisType&& x) - #endif - { this->splice_after(this->previous(p), x); } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: Transfers the value pointed by i, from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! If p == i or p == ++i, this function is a null operation. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator i) - { this->splice(p, x.get(), i); } - void splice(const_iterator p, slist& x, const_iterator i) - #else - void splice(const_iterator p, slist&& x, const_iterator i) - #endif - { this->splice_after(previous(p), x, i); } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: Transfers the range pointed by first and last from list x to this list, - //! before the the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), - //! and in distance(first, last). - //! - //! Note: Iterators of values obtained from list x now point to elements of this - //! list. Iterators of this list and all the references are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object x, const_iterator first, const_iterator last) - { this->splice(p, x.get(), first, last); } - void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) - #else - void splice(const_iterator p, slist&& x, const_iterator first, const_iterator last) - #endif - { this->splice_after(previous(p), x, previous(first), previous(last)); } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } - - //! Effects: Removes all the elements that compare equal to value. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time. It performs exactly size() comparisons for equality. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void remove(const T& value) - { remove_if(equal_to_value(value)); } - - //! Effects: Removes all the elements for which a specified - //! predicate is satisfied. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time. It performs exactly size() calls to the predicate. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void remove_if(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that are equal from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time (size()-1 comparisons calls to pred()). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - void unique() - { this->unique(value_equal()); } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that satisfy some binary predicate from the list. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time (size()-1 comparisons equality comparisons). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void unique(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Requires: The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this according to std::less. The merge is stable; - //! that is, if an element from *this is equivalent to one from x, then the element - //! from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void merge(detail::moved_object > x) - { this->merge(x.get()); } - void merge(slist& x) - #else - void merge(slist&& x) - #endif - { this->merge(x, value_less()); } - - //! Requires: p must be a comparison function that induces a strict weak - //! ordering and both *this and x must be sorted according to that ordering - //! The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this. The merge is stable; that is, if an element from *this is - //! equivalent to one from x, then the element from *this will precede the one from x. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - template - void merge(detail::moved_object > x, StrictWeakOrdering comp) - { this->merge(x.get(), comp); } - template - void merge(slist& x, StrictWeakOrdering comp) - #else - template - void merge(slist&& x, StrictWeakOrdering comp) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().merge(x.icont(), - ValueCompareToNodeCompare(comp)); - } - else{ - throw std::runtime_error("list::merge called with unequal allocators"); - } - } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - void sort() - { this->sort(value_less()); } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - template - void sort(StrictWeakOrdering comp) - { - // nothing if the slist has length 0 or 1. - if (this->size() < 2) - return; - this->icont().sort(ValueCompareToNodeCompare(comp)); - } - - /// @cond - private: - - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); - } - - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag) - { - for (; beg != end; ++beg){ - this->icont().insert_after(prev.get(), *this->create_node_from_it(beg)); - ++prev; - } - } - - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag) - { //Just forward to the default one - priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag()); - } - - class insertion_functor; - friend class insertion_functor; - - class insertion_functor - { - Icont &icont_; - typename Icont::const_iterator prev_; - - public: - insertion_functor(Icont &icont, typename Icont::const_iterator prev) - : icont_(icont), prev_(prev) - {} - - void operator()(Node &n) - { prev_ = this->icont_.insert_after(prev_, n); } - }; - - template - void priv_create_and_insert_nodes - (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag) - { - //Optimized allocation and construction - this->allocate_many_and_construct - (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get())); - } - - //Default constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n) - { - typedef default_construct_iterator default_iterator; - this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator()); - } - - //Copy constructed version - void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x) - { - typedef constant_iterator cvalue_iterator; - this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator prev, - InputIter first, InputIter last, - detail::false_) - { this->priv_create_and_insert_nodes(prev, first, last); } - - template - void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, detail::true_) - { this->priv_create_and_insert_nodes(prev, n, x); } - - void priv_fill_assign(size_type n, const T& val) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - for ( ; node != end_n && n > 0 ; --n){ - *node = val; - prev = node; - ++node; - } - if (n > 0) - this->priv_create_and_insert_nodes(prev, n, val); - else - this->erase_after(prev, end_n); - } - - template - void priv_assign_dispatch(Int n, Int val, detail::true_) - { this->priv_fill_assign((size_type) n, (T)val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) - { - iterator end_n(this->end()); - iterator prev(this->before_begin()); - iterator node(this->begin()); - while (node != end_n && first != last){ - *node = *first; - prev = node; - ++node; - ++first; - } - if (first != last) - this->priv_create_and_insert_nodes(prev, first, last); - else - this->erase_after(prev, end_n); - } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, detail::true_) - { this->priv_create_and_insert_nodes(prev_pos, n, x); } - - template - void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, detail::false_) - { this->priv_create_and_insert_nodes(prev_pos, first, last); } - - //Functors for member algorithm defaults - struct value_less - { - bool operator()(const value_type &a, const value_type &b) const - { return a < b; } - }; - - struct value_equal - { - bool operator()(const value_type &a, const value_type &b) const - { return a == b; } - }; - - struct value_equal_to_this - { - explicit value_equal_to_this(const value_type &ref) - : m_ref(ref){} - - bool operator()(const value_type &val) const - { return m_ref == val; } - - const value_type &m_ref; - }; - /// @endcond -}; - -template -inline bool -operator==(const slist& x, const slist& y) -{ - if(x.size() != y.size()){ - return false; - } - typedef typename slist::const_iterator const_iterator; - const_iterator end1 = x.end(); - - const_iterator i1 = x.begin(); - const_iterator i2 = y.begin(); - while (i1 != end1 && *i1 == *i2){ - ++i1; - ++i2; - } - return i1 == end1; -} - -template -inline bool -operator<(const slist& sL1, const slist& sL2) -{ - return std::lexicographical_compare - (sL1.begin(), sL1.end(), sL2.begin(), sL2.end()); -} - -template -inline bool -operator!=(const slist& sL1, const slist& sL2) - { return !(sL1 == sL2); } - -template -inline bool -operator>(const slist& sL1, const slist& sL2) - { return sL2 < sL1; } - -template -inline bool -operator<=(const slist& sL1, const slist& sL2) - { return !(sL2 < sL1); } - -template -inline bool -operator>=(const slist& sL1, const slist& sL2) - { return !(sL1 < sL2); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(slist& x, slist& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, slist& y) - { x.get().swap(y); } - -template -inline void swap(slist& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(slist&&x, slist&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -/* -template -struct is_movable > -{ - enum { value = true }; -}; -*/ -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost{ namespace interprocess{ - -// Specialization of insert_iterator so that insertions will be constant -// time rather than linear time. - -///@cond - -//Ummm, I don't like to define things in namespace std, but -//there is no other way -namespace std { - -template -class insert_iterator > -{ - protected: - typedef boost::interprocess::slist Container; - Container* container; - typename Container::iterator iter; - public: - typedef Container container_type; - typedef output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - insert_iterator(Container& x, - typename Container::iterator i, - bool is_previous = false) - : container(&x), iter(is_previous ? i : x.previous(i)){ } - - insert_iterator& - operator=(const typename Container::value_type& value) - { - iter = container->insert_after(iter, value); - return *this; - } - insert_iterator& operator*(){ return *this; } - insert_iterator& operator++(){ return *this; } - insert_iterator& operator++(int){ return *this; } -}; - -} //namespace std; - -///@endcond +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_SLIST_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP diff --git a/include/boost/interprocess/containers/stable_vector.hpp b/include/boost/interprocess/containers/stable_vector.hpp new file mode 100644 index 0000000..d6c47a1 --- /dev/null +++ b/include/boost/interprocess/containers/stable_vector.hpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_STABLE_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { + namespace interprocess { + + using boost::interprocess_container::stable_vector; + + } //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 4410423..ceacbce 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -1,2491 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 comes from SGI's string file. Modified by Ion Gaztanaga 2004-2008 -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 1994 -// Hewlett-Packard Company -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Hewlett-Packard Company makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -#ifndef BOOST_INTERPROCESS_STRING_HPP -#define BOOST_INTERPROCESS_STRING_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STRING_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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -namespace detail { -/// @cond -// ------------------------------------------------------------ -// Class basic_string_base. +using boost::interprocess_container::basic_string; +using boost::interprocess_container::string; -// basic_string_base is a helper class that makes it it easier to write -// an exception-safe version of basic_string. The constructor allocates, -// but does not initialize, a block of memory. The destructor -// deallocates, but does not destroy elements within, a block of -// memory. The destructor assumes that the memory either is the internal buffer, -// or else points to a block of memory that was allocated using _String_base's -// allocator and whose size is this->m_storage. -template -class basic_string_base -{ - basic_string_base(); - public: - typedef A allocator_type; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - typedef typename A::pointer pointer; - typedef typename A::value_type value_type; - typedef typename A::size_type size_type; - - basic_string_base(const allocator_type& a) - : members_(a) - { init(); } - - basic_string_base(const allocator_type& a, std::size_t n) - : members_(a) - { - this->init(); - this->allocate_initial_block(n); - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) - basic_string_base(detail::moved_object > b) - : members_(b.get().members_) - { - init(); - this->swap(b.get()); - } - #else - basic_string_base(basic_string_base && b) - : members_(b.members_) - { - init(); - this->swap(b); - } - #endif - - ~basic_string_base() - { - this->deallocate_block(); - if(!this->is_short()){ - static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); - } - } - - private: - - //This is the structure controlling a long string - struct long_t - { - size_type is_short : 1; - size_type length : (sizeof(size_type)*CHAR_BIT - 1); - size_type storage; - pointer start; - - long_t() - {} - - long_t(const long_t &other) - { - this->is_short = other.is_short; - length = other.length; - storage = other.storage; - start = other.start; - } - - long_t &operator =(const long_t &other) - { - this->is_short = other.is_short; - length = other.length; - storage = other.storage; - start = other.start; - return *this; - } - }; - - //This basic type should have the same alignment as long_t -//iG typedef typename type_with_alignment::value>::type -// long_alignment_type; - typedef void *long_alignment_type; - BOOST_STATIC_ASSERT((detail::alignment_of::value % - detail::alignment_of::value) == 0); - - - //This type is the first part of the structure controlling a short string - //The "data" member stores - struct short_header - { - unsigned char is_short : 1; - unsigned char length : (CHAR_BIT - 1); - }; - - //This type has the same alignment and size as long_t but it's POD - //so, unlike long_t, it can be placed in a union - struct long_raw_t - { - long_alignment_type a; - unsigned char b[sizeof(long_t) - sizeof(long_alignment_type)]; - }; - - protected: - static const size_type MinInternalBufferChars = 8; - static const size_type AlignmentOfValueType = - alignment_of::value; - static const size_type ShortDataOffset = - detail::ct_rounded_size::value; - static const size_type ZeroCostInternalBufferChars = - (sizeof(long_t) - ShortDataOffset)/sizeof(value_type); - static const size_type UnalignedFinalInternalBufferChars = - (ZeroCostInternalBufferChars > MinInternalBufferChars) ? - ZeroCostInternalBufferChars : MinInternalBufferChars; - - struct short_t - { - short_header h; - value_type data[UnalignedFinalInternalBufferChars]; - }; - - union repr_t - { - long_raw_t r; - short_t s; - - short_t &short_repr() const - { return *const_cast(&s); } - - long_t &long_repr() const - { return *static_cast(const_cast(static_cast(&r))); } - }; - - struct members_holder - : public A - { - members_holder(const A &a) - : A(a) - {} - - repr_t m_repr; - } members_; - - const A &alloc() const - { return members_; } - - A &alloc() - { return members_; } - - static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type); - - private: - - static const size_type MinAllocation = InternalBufferChars*2; - - protected: - bool is_short() const - { return static_cast(this->members_.m_repr.s.h.is_short != 0); } - - void is_short(bool yes) - { - if(yes && !this->is_short()){ - static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); - } - else{ - new(static_cast(&this->members_.m_repr.r))long_t(); - } - this->members_.m_repr.s.h.is_short = yes; - } - - private: - void init() - { - this->members_.m_repr.s.h.is_short = 1; - this->members_.m_repr.s.h.length = 0; - } - - protected: - - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant::value> alloc_version; - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, pointer reuse = 0) - { - if(this->is_short() && (command & (expand_fwd | expand_bwd)) ){ - reuse = pointer(0); - command &= ~(expand_fwd | expand_bwd); - } - return this->allocation_command - (command, limit_size, preferred_size, received_size, reuse, alloc_version()); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v1) - { - (void)limit_size; - (void)reuse; - if(!(command & allocate_new)) - return std::pair(pointer(0), 0); - received_size = preferred_size; - return std::make_pair(this->alloc().allocate(received_size), false); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - pointer reuse, - allocator_v2) - { - return this->alloc().allocation_command(command, limit_size, preferred_size, - received_size, reuse); - } - - size_type next_capacity(size_type additional_objects) const - { return get_next_capacity(this->alloc().max_size(), this->priv_storage(), additional_objects); } - - void deallocate(pointer p, std::size_t n) - { - if (p && (n > InternalBufferChars)) - this->alloc().deallocate(p, n); - } - - void construct(pointer p, const value_type &value = value_type()) - { new((void*)detail::get_pointer(p)) value_type(value); } - - void destroy(pointer p, size_type n) - { - for(; n--; ++p) - detail::get_pointer(p)->~value_type(); - } - - void destroy(pointer p) - { detail::get_pointer(p)->~value_type(); } - - void allocate_initial_block(std::size_t n) - { - if (n <= this->max_size()) { - if(n > InternalBufferChars){ - size_type new_cap = this->next_capacity(n); - pointer p = this->allocation_command(allocate_new, n, new_cap, new_cap).first; - this->is_short(false); - this->priv_addr(p); - this->priv_size(0); - this->priv_storage(new_cap); - } - } - else - throw_length_error(); - } - - void deallocate_block() - { this->deallocate(this->priv_addr(), this->priv_storage()); } - - std::size_t max_size() const - { return this->alloc().max_size() - 1; } - - // Helper functions for exception handling. - void throw_length_error() const - { throw(std::length_error("basic_string")); } - - void throw_out_of_range() const - { throw(std::out_of_range("basic_string")); } - - protected: - size_type priv_capacity() const - { return this->priv_storage() - 1; } - - pointer priv_addr() const - { return this->is_short() ? pointer(&this->members_.m_repr.short_repr().data[0]) : this->members_.m_repr.long_repr().start; } - - void priv_addr(pointer addr) - { this->members_.m_repr.long_repr().start = addr; } - - size_type priv_storage() const - { return this->is_short() ? InternalBufferChars : this->members_.m_repr.long_repr().storage; } - - void priv_storage(size_type storage) - { - if(!this->is_short()) - this->members_.m_repr.long_repr().storage = storage; - } - - size_type priv_size() const - { return this->is_short() ? this->members_.m_repr.short_repr().h.length : this->members_.m_repr.long_repr().length; } - - void priv_size(size_type sz) - { - if(this->is_short()) - this->members_.m_repr.s.h.length = (unsigned char)sz; - else - this->members_.m_repr.long_repr().length = static_cast(sz); - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(basic_string_base& other) - #else - void swap(basic_string_base &&other) - #endif - { - if(this->is_short()){ - if(other.is_short()){ - std::swap(this->members_.m_repr, other.members_.m_repr); - } - else{ - repr_t copied(this->members_.m_repr); - this->members_.m_repr.long_repr() = other.members_.m_repr.long_repr(); - other.members_.m_repr = copied; - } - } - else{ - if(other.is_short()){ - repr_t copied(other.members_.m_repr); - other.members_.m_repr.long_repr() = this->members_.m_repr.long_repr(); - this->members_.m_repr = copied; - } - else{ - std::swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); - } - } - - allocator_type & this_al = this->alloc(), &other_al = other.alloc(); - if(this_al != other_al){ - detail::do_swap(this_al, other_al); - } - } -}; -/// @endcond - -} //namespace detail { - - -//! The basic_string class represents a Sequence of characters. It contains all the -//! usual operations of a Sequence, and, additionally, it contains standard string -//! operations such as search and concatenation. -//! -//! The basic_string class is parameterized by character type, and by that type's -//! Character Traits. -//! -//! This class has performance characteristics very much like vector<>, meaning, -//! for example, that it does not perform reference-count or copy-on-write, and that -//! concatenation of two strings is an O(N) operation. -//! -//! Some of basic_string's member functions use an unusual method of specifying positions -//! and ranges. In addition to the conventional method using iterators, many of -//! basic_string's member functions use a single value pos of type size_type to represent a -//! position (in which case the position is begin() + pos, and many of basic_string's -//! member functions use two values, pos and n, to represent a range. In that case pos is -//! the beginning of the range and n is its size. That is, the range is -//! [begin() + pos, begin() + pos + n). -//! -//! Note that the C++ standard does not specify the complexity of basic_string operations. -//! In this implementation, basic_string has performance characteristics very similar to -//! those of vector: access to a single character is O(1), while copy and concatenation -//! are O(N). -//! -//! In this implementation, begin(), -//! end(), rbegin(), rend(), operator[], c_str(), and data() do not invalidate iterators. -//! In this implementation, iterators are only invalidated by member functions that -//! explicitly change the string's contents. -template -class basic_string - : private detail::basic_string_base -{ - /// @cond - private: - typedef detail::basic_string_base base_t; - static const typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars; - - protected: - // A helper class to use a char_traits as a function object. - - template - struct Eq_traits - : public std::binary_function - { - bool operator()(const typename Tr::char_type& x, - const typename Tr::char_type& y) const - { return Tr::eq(x, y); } - }; - - template - struct Not_within_traits - : public std::unary_function - { - typedef const typename Tr::char_type* Pointer; - const Pointer m_first; - const Pointer m_last; - - Not_within_traits(Pointer f, Pointer l) - : m_first(f), m_last(l) {} - - bool operator()(const typename Tr::char_type& x) const - { - return std::find_if(m_first, m_last, - std::bind1st(Eq_traits(), x)) == m_last; - } - }; - /// @endcond - - public: - //! The allocator type - typedef A allocator_type; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - //! The type of object, CharT, stored in the string - typedef CharT value_type; - //! The second template parameter Traits - typedef Traits traits_type; - //! Pointer to CharT - typedef typename A::pointer pointer; - //! Const pointer to CharT - typedef typename A::const_pointer const_pointer; - //! Reference to CharT - typedef typename A::reference reference; - //! Const reference to CharT - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! Iterator used to iterate through a string. It's a Random Access Iterator - typedef pointer iterator; - //! Const iterator used to iterate through a string. It's a Random Access Iterator - typedef const_pointer const_iterator; - //! Iterator used to iterate backwards through a string - typedef std::reverse_iterator reverse_iterator; - //! Const iterator used to iterate backwards through a string - typedef std::reverse_iterator const_reverse_iterator; - //! The largest possible value of type size_type. That is, size_type(-1). - static const size_type npos; - - /// @cond - private: - typedef constant_iterator cvalue_iterator; - /// @endcond - - public: // Constructor, destructor, assignment. - /// @cond - struct reserve_t {}; - /// @endcond - - basic_string(reserve_t, std::size_t n, - const allocator_type& a = allocator_type()) - : base_t(a, n + 1) - { this->priv_terminate_string(); } - - //! Effects: Constructs a basic_string taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - explicit basic_string(const allocator_type& a = allocator_type()) - : base_t(a, InternalBufferChars) - { this->priv_terminate_string(); } - - //! Effects: Copy constructs a basic_string. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - basic_string(const basic_string& s) - : base_t(s.alloc()) - { this->priv_range_initialize(s.begin(), s.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string(detail::moved_object s) - : base_t(detail::move_impl((base_t&)s.get())) - {} - #else - basic_string(basic_string && s) - : base_t(detail::move_impl((base_t&)s)) - {} - #endif - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by a specific number of characters of the s string. - basic_string(const basic_string& s, size_type pos, size_type n = npos, - const allocator_type& a = allocator_type()) - : base_t(a) - { - if (pos > s.size()) - this->throw_out_of_range(); - else - this->priv_range_initialize - (s.begin() + pos, s.begin() + pos + min_value(n, s.size() - pos)); - } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by a specific number of characters of the s c-string. - basic_string(const CharT* s, size_type n, - const allocator_type& a = allocator_type()) - : base_t(a) - { this->priv_range_initialize(s, s + n); } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by the null-terminated s c-string. - basic_string(const CharT* s, - const allocator_type& a = allocator_type()) - : base_t(a) - { this->priv_range_initialize(s, s + Traits::length(s)); } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and is initialized by n copies of c. - basic_string(size_type n, CharT c, - const allocator_type& a = allocator_type()) - : base_t(a) - { - this->priv_range_initialize(cvalue_iterator(c, n), - cvalue_iterator()); - } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and a range of iterators. - template - basic_string(InputIterator f, InputIterator l, - const allocator_type& a = allocator_type()) - : base_t(a) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_initialize_dispatch(f, l, Result()); - } - - //! Effects: Destroys the basic_string. All used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - ~basic_string() - {} - - //! Effects: Copy constructs a string. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - basic_string& operator=(const basic_string& s) - { - if (&s != this) - this->assign(s.begin(), s.end()); - return *this; - } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& operator=(detail::moved_object ms) - { - basic_string &s = ms.get(); - if (&s != this){ - this->swap(s); - } - return *this; - } - #else - basic_string& operator=(basic_string && ms) - { - basic_string &s = ms; - if (&s != this){ - this->swap(s); - } - return *this; - } - #endif - - //! Effects: Assignment from a null-terminated c-string. - basic_string& operator=(const CharT* s) - { return this->assign(s, s + Traits::length(s)); } - - //! Effects: Assignment from character. - basic_string& operator=(CharT c) - { return this->assign(static_cast(1), c); } - - //! Effects: Returns an iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return this->priv_addr(); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->priv_addr(); } - - //! Effects: Returns an iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return this->priv_addr() + this->priv_size(); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->priv_addr() + this->priv_size(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(this->priv_addr() + this->priv_size()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(this->priv_addr()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return const_reverse_iterator(this->priv_addr()); } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return this->alloc(); } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->priv_size(); } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type length() const - { return this->size(); } - - //! Effects: Returns the largest possible size of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return base_t::max_size(); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type n, CharT c) - { - if (n <= size()) - this->erase(this->begin() + n, this->end()); - else - this->append(n - this->size(), c); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type n) - { resize(n, this->priv_null()); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - void reserve(size_type res_arg) - { - if (res_arg > this->max_size()) - this->throw_length_error(); - - if (this->capacity() < res_arg){ - size_type n = max_value(res_arg, this->size()) + 1; - size_type new_cap = this->next_capacity(n); - pointer new_start = this->allocation_command - (allocate_new, n, new_cap, new_cap).first; - size_type new_length = 0; - - new_length += priv_uninitialized_copy - (this->priv_addr(), this->priv_addr() + this->priv_size(), new_start); - this->priv_construct_null(new_start + new_length); - this->deallocate_block(); - this->is_short(false); - this->priv_addr(new_start); - this->priv_size(new_length); - this->priv_storage(new_cap); - } - } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return this->priv_capacity(); } - - //! Effects: Erases all the elements of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the vector. - void clear() - { - if (!empty()) { - Traits::assign(*this->priv_addr(), this->priv_null()); - this->priv_size(0); - } - } - - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->priv_size(); } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return *(this->priv_addr() + n); } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const - { return *(this->priv_addr() + n); } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) { - if (n >= size()) - this->throw_out_of_range(); - return *(this->priv_addr() + n); - } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const { - if (n >= size()) - this->throw_out_of_range(); - return *(this->priv_addr() + n); - } - - //! Effects: Appends string s to *this. - basic_string& operator+=(const basic_string& s) - { return this->append(s); } - - //! Effects: Appends c-string s to *this. - basic_string& operator+=(const CharT* s) - { return this->append(s); } - - //! Effects: Appends character c to *this. - basic_string& operator+=(CharT c) - { this->push_back(c); return *this; } - - //! Effects: Appends string s to *this. - basic_string& append(const basic_string& s) - { return this->append(s.begin(), s.end()); } - - //! Effects: Appends the range [pos, pos + n) from string s to *this. - basic_string& append(const basic_string& s, size_type pos, size_type n) - { - if (pos > s.size()) - this->throw_out_of_range(); - return this->append(s.begin() + pos, - s.begin() + pos + min_value(n, s.size() - pos)); - } - - //! Effects: Appends the range [s, s + n) from c-string s to *this. - basic_string& append(const CharT* s, size_type n) - { return this->append(s, s + n); } - - //! Effects: Appends the c-string s to *this. - basic_string& append(const CharT* s) - { return this->append(s, s + Traits::length(s)); } - - //! Effects: Appends the n times the character c to *this. - basic_string& append(size_type n, CharT c) - { return this->append(cvalue_iterator(c, n), cvalue_iterator()); } - - //! Effects: Appends the range [first, last) *this. - template - basic_string& append(InputIter first, InputIter last) - { this->insert(this->end(), first, last); return *this; } - - //! Effects: Inserts a copy of c at the end of the vector. - void push_back(CharT c) - { - if (this->priv_size() < this->capacity()){ - this->priv_construct_null(this->priv_addr() + (this->priv_size() + 1)); - Traits::assign(this->priv_addr()[this->priv_size()], c); - this->priv_size(this->priv_size()+1); - } - else{ - //No enough memory, insert a new object at the end - this->append((size_type)1, c); - } - } - - //! Effects: Removes the last element from the vector. - void pop_back() - { - Traits::assign(this->priv_addr()[this->priv_size()-1], this->priv_null()); - this->priv_size(this->priv_size()-1);; - } - - //! Effects: Assigns the value s to *this. - basic_string& assign(const basic_string& s) - { return this->operator=(s); } - - //! Effects: Moves the resources from ms *this. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& assign(detail::moved_object ms) - { return this->operator=(ms);} - #else - basic_string& assign(basic_string && ms) - { return this->operator=(ms);} - #endif - - //! Effects: Assigns the range [pos, pos + n) from s to *this. - basic_string& assign(const basic_string& s, - size_type pos, size_type n) { - if (pos > s.size()) - this->throw_out_of_range(); - return this->assign(s.begin() + pos, - s.begin() + pos + min_value(n, s.size() - pos)); - } - - //! Effects: Assigns the range [s, s + n) from s to *this. - basic_string& assign(const CharT* s, size_type n) - { return this->assign(s, s + n); } - - //! Effects: Assigns the c-string s to *this. - basic_string& assign(const CharT* s) - { return this->assign(s, s + Traits::length(s)); } - - //! Effects: Assigns the character c n-times to *this. - basic_string& assign(size_type n, CharT c) - { return this->assign(cvalue_iterator(c, n), cvalue_iterator()); } - - //! Effects: Assigns the range [first, last) to *this. - template - basic_string& assign(InputIter first, InputIter last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - return this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Assigns the range [f, l) to *this. - basic_string& assign(const CharT* f, const CharT* l) - { - const std::ptrdiff_t n = l - f; - if (static_cast(n) <= size()) { - Traits::copy(detail::get_pointer(this->priv_addr()), f, n); - this->erase(this->priv_addr() + n, this->priv_addr() + this->priv_size()); - } - else { - Traits::copy(detail::get_pointer(this->priv_addr()), f, this->priv_size()); - this->append(f + this->priv_size(), l); - } - return *this; - } - - //! Effects: Inserts the string s before pos. - basic_string& insert(size_type pos, const basic_string& s) - { - if (pos > size()) - this->throw_out_of_range(); - if (this->size() > this->max_size() - s.size()) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, s.begin(), s.end()); - return *this; - } - - //! Effects: Inserts the range [pos, pos + n) from string s before pos. - basic_string& insert(size_type pos, const basic_string& s, - size_type beg, size_type n) - { - if (pos > this->size() || beg > s.size()) - this->throw_out_of_range(); - size_type len = min_value(n, s.size() - beg); - if (this->size() > this->max_size() - len) - this->throw_length_error(); - const CharT *beg_ptr = detail::get_pointer(s.begin()) + beg; - const CharT *end_ptr = beg_ptr + len; - this->insert(this->priv_addr() + pos, beg_ptr, end_ptr); - return *this; - } - - //! Effects: Inserts the range [s, s + n) before pos. - basic_string& insert(size_type pos, const CharT* s, size_type n) - { - if (pos > this->size()) - this->throw_out_of_range(); - if (this->size() > this->max_size() - n) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, s, s + n); - return *this; - } - - //! Effects: Inserts the c-string s before pos. - basic_string& insert(size_type pos, const CharT* s) - { - if (pos > size()) - this->throw_out_of_range(); - size_type len = Traits::length(s); - if (this->size() > this->max_size() - len) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, s, s + len); - return *this; - } - - //! Effects: Inserts the character c n-times before pos. - basic_string& insert(size_type pos, size_type n, CharT c) - { - if (pos > this->size()) - this->throw_out_of_range(); - if (this->size() > this->max_size() - n) - this->throw_length_error(); - this->insert(this->priv_addr() + pos, n, c); - return *this; - } - - //! Effects: Inserts the character c before position. - iterator insert(iterator position, CharT c) - { - size_type new_offset = position - this->priv_addr() + 1; - this->insert(position, cvalue_iterator(c, 1), - cvalue_iterator()); - return this->priv_addr() + new_offset; - } - - //! Effects: Inserts the character c n-times before position. - void insert(iterator position, std::size_t n, CharT c) - { - this->insert(position, cvalue_iterator(c, n), - cvalue_iterator()); - } - - //! Effects: Inserts the range [first, last) before position. - template - void insert(iterator p, InputIter first, InputIter last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - //! Effects: Inserts the range [pos, pos + n). - basic_string& erase(size_type pos = 0, size_type n = npos) - { - if (pos > size()) - this->throw_out_of_range(); - erase(this->priv_addr() + pos, this->priv_addr() + pos + min_value(n, size() - pos)); - return *this; - } - - //! Effects: Erases the character pointed by position. - iterator erase(iterator position) - { - // The move includes the terminating null. - Traits::move(detail::get_pointer(position), - detail::get_pointer(position + 1), - this->priv_size() - (position - this->priv_addr())); - this->priv_size(this->priv_size()-1); - return position; - } - - //! Effects: Erases the range [first, last). - iterator erase(iterator first, iterator last) - { - if (first != last) { // The move includes the terminating null. - size_type num_erased = last - first; - Traits::move(detail::get_pointer(first), - detail::get_pointer(last), - (this->priv_size() + 1)-(last - this->priv_addr())); - size_type new_length = this->priv_size() - num_erased; - this->priv_size(new_length); - } - return first; - } - - //! Effects: Replaces a substring of *this with the string s. - basic_string& replace(size_type pos, size_type n, - const basic_string& s) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n, size() - pos); - if (this->size() - len >= this->max_size() - s.size()) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, - s.begin(), s.end()); - } - - //! Effects: Replaces a substring of *this with a substring of s. - basic_string& replace(size_type pos1, size_type n1, - const basic_string& s, - size_type pos2, size_type n2) - { - if (pos1 > size() || pos2 > s.size()) - this->throw_out_of_range(); - const size_type len1 = min_value(n1, size() - pos1); - const size_type len2 = min_value(n2, s.size() - pos2); - if (this->size() - len1 >= this->max_size() - len2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len1, - s.priv_addr() + pos2, s.priv_addr() + pos2 + len2); - } - - //! Effects: Replaces a substring of *this with the first n1 characters of s. - basic_string& replace(size_type pos, size_type n1, - const CharT* s, size_type n2) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n1, size() - pos); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, - s, s + n2); - } - - //! Effects: Replaces a substring of *this with a null-terminated character array. - basic_string& replace(size_type pos, size_type n1, - const CharT* s) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n1, size() - pos); - const size_type n2 = Traits::length(s); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, - s, s + Traits::length(s)); - } - - //! Effects: Replaces a substring of *this with n1 copies of c. - basic_string& replace(size_type pos, size_type n1, - size_type n2, CharT c) - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n1, size() - pos); - if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); - return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, n2, c); - } - - //! Effects: Replaces a substring of *this with the string s. - basic_string& replace(iterator first, iterator last, - const basic_string& s) - { return this->replace(first, last, s.begin(), s.end()); } - - //! Effects: Replaces a substring of *this with the first n characters of s. - basic_string& replace(iterator first, iterator last, - const CharT* s, size_type n) - { return this->replace(first, last, s, s + n); } - - //! Effects: Replaces a substring of *this with a null-terminated character array. - basic_string& replace(iterator first, iterator last, - const CharT* s) - { return this->replace(first, last, s, s + Traits::length(s)); } - - //! Effects: Replaces a substring of *this with n copies of c. - basic_string& replace(iterator first, iterator last, - size_type n, CharT c) - { - const size_type len = static_cast(last - first); - if (len >= n) { - Traits::assign(detail::get_pointer(first), n, c); - erase(first + n, last); - } - else { - Traits::assign(detail::get_pointer(first), len, c); - insert(last, n - len, c); - } - return *this; - } - - //! Effects: Replaces a substring of *this with the range [f, l) - template - basic_string& replace(iterator first, iterator last, - InputIter f, InputIter l) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - return this->priv_replace_dispatch(first, last, f, l, Result()); - } - - //! Effects: Copies a substring of *this to a buffer. - size_type copy(CharT* s, size_type n, size_type pos = 0) const - { - if (pos > size()) - this->throw_out_of_range(); - const size_type len = min_value(n, size() - pos); - Traits::copy(s, detail::get_pointer(this->priv_addr() + pos), len); - return len; - } - - //! Effects: Swaps the contents of two strings. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(basic_string& x) - #else - void swap(basic_string &&x) - #endif - { base_t::swap(x); } - - //! Returns: Returns a pointer to a null-terminated array of characters - //! representing the string's contents. For any string s it is guaranteed - //! that the first s.size() characters in the array pointed to by s.c_str() - //! are equal to the character in s, and that s.c_str()[s.size()] is a null - //! character. Note, however, that it not necessarily the first null character. - //! Characters within a string are permitted to be null. - const CharT* c_str() const - { return detail::get_pointer(this->priv_addr()); } - - //! Returns: Returns a pointer to an array of characters, not necessarily - //! null-terminated, representing the string's contents. data() is permitted, - //! but not required, to be identical to c_str(). The first size() characters - //! of that array are guaranteed to be identical to the characters in *this. - //! The return value of data() is never a null pointer, even if size() is zero. - const CharT* data() const - { return detail::get_pointer(this->priv_addr()); } - - //! Effects: Searches for s as a substring of *this, beginning at - //! character pos of *this. - size_type find(const basic_string& s, size_type pos = 0) const - { return find(s.c_str(), pos, s.size()); } - - //! Effects: Searches for a null-terminated character array as a - //! substring of *this, beginning at character pos of *this. - size_type find(const CharT* s, size_type pos = 0) const - { return find(s, pos, Traits::length(s)); } - - //! Effects: Searches for the first n characters of s as a substring - //! of *this, beginning at character pos of *this. - size_type find(const CharT* s, size_type pos, size_type n) const - { - if (pos + n > size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const const_iterator result = - std::search(detail::get_pointer(this->priv_addr() + pos), - detail::get_pointer(finish), - s, s + n, Eq_traits()); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches for the character c, beginning at character - //! position pos. - size_type find(CharT c, size_type pos = 0) const - { - if (pos >= size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const const_iterator result = - std::find_if(this->priv_addr() + pos, finish, - std::bind2nd(Eq_traits(), c)); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches backward for s as a substring of *this, - //! beginning at character position min(pos, size()) - size_type rfind(const basic_string& s, size_type pos = npos) const - { return rfind(s.c_str(), pos, s.size()); } - - //! Effects: Searches backward for a null-terminated character array - //! as a substring of *this, beginning at character min(pos, size()) - size_type rfind(const CharT* s, size_type pos = npos) const - { return rfind(s, pos, Traits::length(s)); } - - //! Effects: Searches backward for the first n characters of s as a - //! substring of *this, beginning at character position min(pos, size()). - size_type rfind(const CharT* s, size_type pos, size_type n) const - { - const std::size_t len = size(); - - if (n > len) - return npos; - else if (n == 0) - return min_value(len, pos); - else { - const const_iterator last = begin() + min_value(len - n, pos) + n; - const const_iterator result = find_end(begin(), last, - s, s + n, - Eq_traits()); - return result != last ? result - begin() : npos; - } - } - - //! Effects: Searches backward for a null-terminated character array - //! as a substring of *this, beginning at character min(pos, size()). - size_type rfind(CharT c, size_type pos = npos) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = begin() + min_value(len - 1, pos) + 1; - const_reverse_iterator rresult = - std::find_if(const_reverse_iterator(last), rend(), - std::bind2nd(Eq_traits(), c)); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to any character within s. - size_type find_first_of(const basic_string& s, size_type pos = 0) const - { return find_first_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to any character within s. - size_type find_first_of(const CharT* s, size_type pos = 0) const - { return find_first_of(s, pos, Traits::length(s)); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to any character within the first n characters of s. - size_type find_first_of(const CharT* s, size_type pos, - size_type n) const - { - if (pos >= size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result = std::find_first_of(this->priv_addr() + pos, finish, - s, s + n, - Eq_traits()); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is equal to c. - size_type find_first_of(CharT c, size_type pos = 0) const - { return find(c, pos); } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is equal to any character within s. - size_type find_last_of(const basic_string& s, - size_type pos = npos) const - { return find_last_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches backward *this, beginning at min(pos, size()), for - //! the first character that is equal to any character within s. - size_type find_last_of(const CharT* s, size_type pos = npos) const - { return find_last_of(s, pos, Traits::length(s)); } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is equal to any character within the first n - //! characters of s. - size_type find_last_of(const CharT* s, size_type pos, size_type n) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = this->priv_addr() + min_value(len - 1, pos) + 1; - const const_reverse_iterator rresult = - std::find_first_of(const_reverse_iterator(last), rend(), - s, s + n, - Eq_traits()); - return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; - } - } - - //! Effects: Searches backward *this, beginning at min(pos, size()), for - //! the first character that is equal to c. - size_type find_last_of(CharT c, size_type pos = npos) const - { return rfind(c, pos); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to any character within s. - size_type find_first_not_of(const basic_string& s, - size_type pos = 0) const - { return find_first_not_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to any character within s. - size_type find_first_not_of(const CharT* s, size_type pos = 0) const - { return find_first_not_of(s, pos, Traits::length(s)); } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to any character within the first n - //! characters of s. - size_type find_first_not_of(const CharT* s, size_type pos, - size_type n) const - { - if (pos > size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result = std::find_if(this->priv_addr() + pos, finish, - Not_within_traits(s, s + n)); - return result != finish ? result - this->priv_addr() : npos; - } - } - - //! Effects: Searches within *this, beginning at pos, for the first - //! character that is not equal to c. - size_type find_first_not_of(CharT c, size_type pos = 0) const - { - if (pos > size()) - return npos; - else { - pointer finish = this->priv_addr() + this->priv_size(); - const_iterator result - = std::find_if(this->priv_addr() + pos, finish, - std::not1(std::bind2nd(Eq_traits(), c))); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is not equal to any character within s. - size_type find_last_not_of(const basic_string& s, - size_type pos = npos) const - { return find_last_not_of(s.c_str(), pos, s.size()); } - - //! Effects: Searches backward *this, beginning at min(pos, size()), - //! for the first character that is not equal to any character within s. - size_type find_last_not_of(const CharT* s, size_type pos = npos) const - { return find_last_not_of(s, pos, Traits::length(s)); } - - //! Effects: Searches backward within *this, beginning at min(pos, size()), - //! for the first character that is not equal to any character within the first - //! n characters of s. - size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = begin() + min_value(len - 1, pos) + 1; - const const_reverse_iterator rresult = - std::find_if(const_reverse_iterator(last), rend(), - Not_within_traits(s, s + n)); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: Searches backward *this, beginning at min(pos, size()), - //! for the first character that is not equal to c. - size_type find_last_not_of(CharT c, size_type pos = npos) const - { - const size_type len = size(); - - if (len < 1) - return npos; - else { - const const_iterator last = begin() + min_value(len - 1, pos) + 1; - const_reverse_iterator rresult = - std::find_if(const_reverse_iterator(last), rend(), - std::not1(std::bind2nd(Eq_traits(), c))); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: Returns a substring of *this. - basic_string substr(size_type pos = 0, size_type n = npos) const - { - if (pos > size()) - this->throw_out_of_range(); - return basic_string(this->priv_addr() + pos, - this->priv_addr() + pos + min_value(n, size() - pos), this->alloc()); - } - - //! Effects: Three-way lexicographical comparison of s and *this. - int compare(const basic_string& s) const - { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s.priv_addr(), s.priv_addr() + s.priv_size()); } - - //! Effects: Three-way lexicographical comparison of s and a substring - //! of *this. - int compare(size_type pos1, size_type n1, const basic_string& s) const - { - if (pos1 > size()) - this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + min_value(n1, size() - pos1), - s.priv_addr(), s.priv_addr() + s.priv_size()); - } - - //! Effects: Three-way lexicographical comparison of a substring of s - //! and a substring of *this. - int compare(size_type pos1, size_type n1, - const basic_string& s, - size_type pos2, size_type n2) const { - if (pos1 > size() || pos2 > s.size()) - this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + min_value(n1, size() - pos1), - s.priv_addr() + pos2, - s.priv_addr() + pos2 + min_value(n2, size() - pos2)); - } - - //! Effects: Three-way lexicographical comparison of s and *this. - int compare(const CharT* s) const - { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s, s + Traits::length(s)); } - - - //! Effects: Three-way lexicographical comparison of the first - //! min(len, traits::length(s) characters of s and a substring of *this. - int compare(size_type pos1, size_type n1, const CharT* s, - size_type n2 = npos) const - { - if (pos1 > size()) - this->throw_out_of_range(); - return s_compare(this->priv_addr() + pos1, - this->priv_addr() + pos1 + min_value(n1, size() - pos1), - s, s + n2); - } - - /// @cond - private: - static int s_compare(const_pointer f1, const_pointer l1, - const_pointer f2, const_pointer l2) - { - const std::ptrdiff_t n1 = l1 - f1; - const std::ptrdiff_t n2 = l2 - f2; - const int cmp = Traits::compare(detail::get_pointer(f1), - detail::get_pointer(f2), - min_value(n1, n2)); - return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); - } - - void priv_construct_null(pointer p) - { this->construct(p, 0); } - - static CharT priv_null() - { return (CharT) 0; } - - // Helper functions used by constructors. It is a severe error for - // any of them to be called anywhere except from within constructors. - void priv_terminate_string() - { this->priv_construct_null(this->priv_addr() + this->priv_size()); } - - template - void priv_range_initialize(InputIter f, InputIter l, - std::input_iterator_tag) - { - this->allocate_initial_block(InternalBufferChars); - this->priv_construct_null(this->priv_addr() + this->priv_size()); - this->append(f, l); - } - - template - void priv_range_initialize(ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - this->allocate_initial_block(max_value(n+1, InternalBufferChars)); - priv_uninitialized_copy(f, l, this->priv_addr()); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_range_initialize(InputIter f, InputIter l) - { - typedef typename std::iterator_traits::iterator_category Category; - this->priv_range_initialize(f, l, Category()); - } - - template - void priv_initialize_dispatch(Integer n, Integer x, detail::true_) - { - this->allocate_initial_block(max_value(n+1, InternalBufferChars)); - priv_uninitialized_fill_n(this->priv_addr(), n, x); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_initialize_dispatch(InputIter f, InputIter l, detail::false_) - { this->priv_range_initialize(f, l); } - - template inline - void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val) - { - //Save initial position - FwdIt init = first; - - BOOST_TRY{ - //Construct objects - for (; count--; ++first){ - this->construct(first, val); - } - } - BOOST_CATCH(...){ - //Call destructors - for (; init != first; ++init){ - this->destroy(init); - } - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template inline - size_type priv_uninitialized_copy(InpIt first, InpIt last, FwdIt dest) - { - //Save initial destination position - FwdIt dest_init = dest; - size_type constructed = 0; - - BOOST_TRY{ - //Try to build objects - for (; first != last; ++dest, ++first, ++constructed){ - this->construct(dest, *first); - } - } - BOOST_CATCH(...){ - //Call destructors - for (; constructed--; ++dest_init){ - this->destroy(dest_init); - } - BOOST_RETHROW - } - BOOST_CATCH_END - return (constructed); - } - - template - basic_string& priv_assign_dispatch(Integer n, Integer x, detail::true_) - { return this->assign((size_type) n, (CharT) x); } - - template - basic_string& priv_assign_dispatch(InputIter f, InputIter l, - detail::false_) - { - size_type cur = 0; - CharT *ptr = detail::get_pointer(this->priv_addr()); - while (f != l && cur != this->priv_size()) { - Traits::assign(*ptr, *f); - ++f; - ++cur; - ++ptr; - } - if (f == l) - this->erase(this->priv_addr() + cur, this->priv_addr() + this->priv_size()); - else - this->append(f, l); - return *this; - } - - template - void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) - { - for ( ; first != last; ++first, ++p) { - p = this->insert(p, *first); - } - } - - template - void priv_insert(iterator position, ForwardIter first, - ForwardIter last, std::forward_iterator_tag) - { - if (first != last) { - size_type n = std::distance(first, last); - size_type remaining = this->capacity() - this->priv_size(); - const size_type old_size = this->size(); - pointer old_start = this->priv_addr(); - bool enough_capacity = false; - std::pair allocation_ret; - size_type new_cap = 0; - - //Check if we have enough capacity - if (remaining >= n){ - enough_capacity = true; - } - else { - //Otherwise expand current buffer or allocate new storage - new_cap = this->next_capacity(n); - allocation_ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, old_size + n + 1, - new_cap, new_cap, old_start); - - //Check forward expansion - if(old_start == allocation_ret.first){ - enough_capacity = true; - this->priv_storage(new_cap); - } - } - - //Reuse same buffer - if(enough_capacity){ - const size_type elems_after = - this->priv_size() - (position - this->priv_addr()); - size_type old_length = this->priv_size(); - if (elems_after >= n) { - pointer pointer_past_last = this->priv_addr() + this->priv_size() + 1; - priv_uninitialized_copy(this->priv_addr() + (this->priv_size() - n + 1), - pointer_past_last, pointer_past_last); - - this->priv_size(this->priv_size()+n); - Traits::move(detail::get_pointer(position + n), - detail::get_pointer(position), - (elems_after - n) + 1); - this->priv_copy(first, last, position); - } - else { - ForwardIter mid = first; - std::advance(mid, elems_after + 1); - - priv_uninitialized_copy(mid, last, this->priv_addr() + this->priv_size() + 1); - this->priv_size(this->priv_size() + (n - elems_after)); - priv_uninitialized_copy - (position, this->priv_addr() + old_length + 1, - this->priv_addr() + this->priv_size()); - this->priv_size(this->priv_size() + elems_after); - this->priv_copy(first, mid, position); - } - } - else{ - pointer new_start = allocation_ret.first; - if(!allocation_ret.second){ - //Copy data to new buffer - size_type new_length = 0; - //This can't throw, since characters are POD - new_length += priv_uninitialized_copy - (this->priv_addr(), position, new_start); - new_length += priv_uninitialized_copy - (first, last, new_start + new_length); - new_length += priv_uninitialized_copy - (position, this->priv_addr() + this->priv_size(), - new_start + new_length); - this->priv_construct_null(new_start + new_length); - - this->deallocate_block(); - this->is_short(false); - this->priv_addr(new_start); - this->priv_size(new_length); - this->priv_storage(new_cap); - } - else{ - //value_type is POD, so backwards expansion is much easier - //than with vector - value_type *oldbuf = detail::get_pointer(old_start); - value_type *newbuf = detail::get_pointer(new_start); - value_type *pos = detail::get_pointer(position); - size_type before = pos - oldbuf; - - //First move old data - Traits::move(newbuf, oldbuf, before); - Traits::move(newbuf + before + n, pos, old_size - before); - //Now initialize the new data - priv_uninitialized_copy(first, last, new_start + before); - this->priv_construct_null(new_start + (old_size + n)); - this->is_short(false); - this->priv_addr(new_start); - this->priv_size(old_size + n); - this->priv_storage(new_cap); - } - } - } - } - - template - void priv_insert_dispatch(iterator p, Integer n, Integer x, - detail::true_) - { insert(p, (size_type) n, (CharT) x); } - - template - void priv_insert_dispatch(iterator p, InputIter first, InputIter last, - detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - priv_insert(p, first, last, Category()); - } - - template - void priv_copy(InputIterator first, InputIterator last, iterator result) - { - for ( ; first != last; ++first, ++result) - Traits::assign(*result, *first); - } - - void priv_copy(const CharT* first, const CharT* last, CharT* result) - { Traits::copy(result, first, last - first); } - - template - basic_string& priv_replace_dispatch(iterator first, iterator last, - Integer n, Integer x, - detail::true_) - { return this->replace(first, last, (size_type) n, (CharT) x); } - - template - basic_string& priv_replace_dispatch(iterator first, iterator last, - InputIter f, InputIter l, - detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - return this->priv_replace(first, last, f, l, Category()); - } - - - template - basic_string& priv_replace(iterator first, iterator last, - InputIter f, InputIter l, std::input_iterator_tag) - { - for ( ; first != last && f != l; ++first, ++f) - Traits::assign(*first, *f); - - if (f == l) - this->erase(first, last); - else - this->insert(last, f, l); - return *this; - } - - template - basic_string& priv_replace(iterator first, iterator last, - ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - const difference_type len = last - first; - if (len >= n) { - this->priv_copy(f, l, first); - this->erase(first + n, last); - } - else { - ForwardIter m = f; - std::advance(m, len); - this->priv_copy(f, m, first); - this->insert(last, m, l); - } - return *this; - } - /// @endcond -}; - -template -const typename basic_string::size_type -basic_string::npos - = (typename basic_string::size_type) -1; - -// ------------------------------------------------------------ -// Non-member functions. - -// Operator+ - -template -inline basic_string -operator+(const basic_string& x, - const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, x.size() + y.size(), x.alloc()); - result.append(x); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const basic_string& y) -{ - mx.get() += y; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, - const basic_string& y) -{ - mx += y; - return detail::move_impl(mx); -} -#endif - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(const basic_string& x, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), x); -} -#else -template -inline basic_string && -operator+(const basic_string& x, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), x); -} -#endif - -template -inline basic_string -operator+(const CharT* s, const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - const std::size_t n = Traits::length(s); - str_t result(reserve, n + y.size()); - result.append(s, s + n); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(const CharT* s, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), s); -} -#else -template -inline basic_string && -operator+(const CharT* s, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); -} -#endif - -template -inline basic_string -operator+(CharT c, const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, 1 + y.size()); - result.push_back(c); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(CharT c, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), &c, &c + 1); -} -#else -template -inline basic_string && -operator+(CharT c, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), &c, &c + 1); -} -#endif - -template -inline basic_string -operator+(const basic_string& x, const CharT* s) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - const std::size_t n = Traits::length(s); - str_t result(reserve, x.size() + n, x.alloc()); - result.append(x); - result.append(s, s + n); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const CharT* s) -{ - mx.get() += s; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, - const CharT* s) -{ - mx += s; - return detail::move_impl(mx); -} -#endif - -template -inline basic_string -operator+(const basic_string& x, const CharT c) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, x.size() + 1, x.alloc()); - result.append(x); - result.push_back(c); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const CharT c) -{ - mx.get() += c; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, const CharT c) -{ - mx += c; - return detail::move_impl(mx); -} -#endif - -// Operator== and operator!= - -template -inline bool -operator==(const basic_string& x, - const basic_string& y) -{ - return x.size() == y.size() && - Traits::compare(x.data(), y.data(), x.size()) == 0; -} - -template -inline bool -operator==(const CharT* s, const basic_string& y) -{ - std::size_t n = Traits::length(s); - return n == y.size() && Traits::compare(s, y.data(), n) == 0; -} - -template -inline bool -operator==(const basic_string& x, const CharT* s) -{ - std::size_t n = Traits::length(s); - return x.size() == n && Traits::compare(x.data(), s, n) == 0; -} - -template -inline bool -operator!=(const basic_string& x, - const basic_string& y) - { return !(x == y); } - -template -inline bool -operator!=(const CharT* s, const basic_string& y) - { return !(s == y); } - -template -inline bool -operator!=(const basic_string& x, const CharT* s) - { return !(x == s); } - - -// Operator< (and also >, <=, and >=). - -template -inline bool -operator<(const basic_string& x, - const basic_string& y) -{ - return x.compare(y) < 0; -// return basic_string -// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; -} - -template -inline bool -operator<(const CharT* s, const basic_string& y) -{ - return y.compare(s) > 0; -// std::size_t n = Traits::length(s); -// return basic_string -// ::s_compare(s, s + n, y.begin(), y.end()) < 0; -} - -template -inline bool -operator<(const basic_string& x, - const CharT* s) -{ - return x.compare(s) < 0; -// std::size_t n = Traits::length(s); -// return basic_string -// ::s_compare(x.begin(), x.end(), s, s + n) < 0; -} - -template -inline bool -operator>(const basic_string& x, - const basic_string& y) { - return y < x; -} - -template -inline bool -operator>(const CharT* s, const basic_string& y) { - return y < s; -} - -template -inline bool -operator>(const basic_string& x, const CharT* s) -{ - return s < x; -} - -template -inline bool -operator<=(const basic_string& x, - const basic_string& y) -{ - return !(y < x); -} - -template -inline bool -operator<=(const CharT* s, const basic_string& y) - { return !(y < s); } - -template -inline bool -operator<=(const basic_string& x, const CharT* s) - { return !(s < x); } - -template -inline bool -operator>=(const basic_string& x, - const basic_string& y) - { return !(x < y); } - -template -inline bool -operator>=(const CharT* s, const basic_string& y) - { return !(s < y); } - -template -inline bool -operator>=(const basic_string& x, const CharT* s) - { return !(x < s); } - -// Swap. -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline void swap(basic_string& x, basic_string& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > mx, basic_string& y) -{ mx.get().swap(y); } - -template -inline void swap(basic_string& x, detail::moved_object > my) -{ x.swap(my.get()); } -#else -template -inline void swap(basic_string && x, basic_string &&y) -{ x.swap(y); } -#endif - -/// @cond -// I/O. -namespace detail { - -template -inline bool -interprocess_string_fill(std::basic_ostream& os, - std::basic_streambuf* buf, - std::size_t n) -{ - CharT f = os.fill(); - std::size_t i; - bool ok = true; - - for (i = 0; i < n; i++) - ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); - return ok; -} - -} //namespace detail { -/// @endcond - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - const basic_string& s) - #else - const basic_string&&s) - #endif -{ - typename std::basic_ostream::sentry sentry(os); - bool ok = false; - - if (sentry) { - ok = true; - std::size_t n = s.size(); - std::size_t pad_len = 0; - const bool left = (os.flags() & std::ios::left) != 0; - const std::size_t w = os.width(0); - std::basic_streambuf* buf = os.rdbuf(); - - if (w != 0 && n < w) - pad_len = w - n; - - if (!left) - ok = detail::interprocess_string_fill(os, buf, pad_len); - - ok = ok && - buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); - - if (left) - ok = ok && detail::interprocess_string_fill(os, buf, pad_len); - } - - if (!ok) - os.setstate(std::ios_base::failbit); - - return os; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - detail::moved_object > ms) -{ return os << ms.get(); } -#endif - - -template -std::basic_istream& -operator>>(std::basic_istream& is, - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& s) - #else - basic_string&&s) - #endif -{ - typename std::basic_istream::sentry sentry(is); - - if (sentry) { - std::basic_streambuf* buf = is.rdbuf(); - const std::ctype& ctype = std::use_facet >(is.getloc()); - - s.clear(); - std::size_t n = is.width(0); - if (n == 0) - n = static_cast(-1); - else - s.reserve(n); - - while (n-- > 0) { - typename Traits::int_type c1 = buf->sbumpc(); - - if (Traits::eq_int_type(c1, Traits::eof())) { - is.setstate(std::ios_base::eofbit); - break; - } - else { - CharT c = Traits::to_char_type(c1); - - if (ctype.is(std::ctype::space, c)) { - if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) - is.setstate(std::ios_base::failbit); - break; - } - else - s.push_back(c); - } - } - - // If we have read no characters, then set failbit. - if (s.size() == 0) - is.setstate(std::ios_base::failbit); - } - else - is.setstate(std::ios_base::failbit); - - return is; -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -std::basic_istream& -operator>>(std::basic_istream& is, - detail::moved_object > ms) -{ return is >> ms.get(); } -#endif - -template -std::basic_istream& -getline(std::istream& is, - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& s, - #else - basic_string&&s, - #endif - CharT delim) -{ - std::size_t nread = 0; - typename std::basic_istream::sentry sentry(is, true); - if (sentry) { - std::basic_streambuf* buf = is.rdbuf(); - s.clear(); - - int c1; - while (nread < s.max_size()) { - int c1 = buf->sbumpc(); - if (Traits::eq_int_type(c1, Traits::eof())) { - is.setstate(std::ios_base::eofbit); - break; - } - else { - ++nread; - CharT c = Traits::to_char_type(c1); - if (!Traits::eq(c, delim)) - s.push_back(c); - else - break; // Character is extracted but not appended. - } - } - } - if (nread == 0 || nread >= s.max_size()) - is.setstate(std::ios_base::failbit); - - return is; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -std::basic_istream& -getline(std::istream& is, - detail::moved_object > ms, - CharT delim) -{ return getline(is, ms.get(), delim); } -#endif - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline std::basic_istream& -getline(std::basic_istream& is, - basic_string& s) -{ - return getline(is, s, '\n'); -} - -template -std::basic_istream& -getline(std::istream& is, - detail::moved_object > ms) -{ return getline(is, ms.get()); } -#else -template -std::basic_istream& -getline(std::istream& is, - basic_string && ms) -{ return getline(is, ms); } -#endif - -template -inline std::size_t hash_value(basic_string, A> const& v) -{ - return hash_range(v.begin(), v.end()); -} - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess +} //namespace interprocess { +} //namespace boost { #include -#endif // BOOST_INTERPROCESS_STRING_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 680bb82..d6f31c2 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -1,1998 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. 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 comes from SGI's stl_vector.h file. Modified by Ion Gaztanaga. -// Renaming, isolating and porting to generic algorithms. Pointer typedef -// set to allocator::pointer to allow placing it in shared memory. -// -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 1994 -// Hewlett-Packard Company -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Hewlett-Packard Company makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -// -// -// Copyright (c) 1996 -// Silicon Graphics Computer Systems, Inc. -// -// Permission to use, copy, modify, distribute and sell this software -// and its documentation for any purpose is hereby granted without fee, -// provided that the above copyright notice appear in all copies and -// that both that copyright notice and this permission notice appear -// in supporting documentation. Silicon Graphics makes no -// representations about the suitability of this software for any -// purpose. It is provided "as is" without express or implied warranty. -#ifndef BOOST_INTERPROCESS_VECTOR_HPP -#define BOOST_INTERPROCESS_VECTOR_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_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 -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond - -namespace detail { - -//! Const vector_iterator used to iterate through a vector. -template -class vector_const_iterator - : public std::iterator::value_type - ,typename std::iterator_traits::difference_type - ,typename pointer_to_other - ::value_type - >::type - ,const typename std::iterator_traits::value_type &> -{ - public: - typedef const typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename pointer_to_other::type pointer; - typedef value_type& reference; - - /// @cond - protected: - Pointer m_ptr; - - public: - Pointer get_ptr() const { return m_ptr; } - explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){} - /// @endcond - - public: - - //Constructors - vector_const_iterator() : m_ptr(0){} - - //Pointer like operators - reference operator*() const - { return *m_ptr; } - - const value_type * operator->() const - { return detail::get_pointer(m_ptr); } - - reference operator[](difference_type off) const - { return m_ptr[off]; } - - //Increment / Decrement - vector_const_iterator& operator++() - { ++m_ptr; return *this; } - - vector_const_iterator operator++(int) - { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } - - vector_const_iterator& operator--() - { --m_ptr; return *this; } - - vector_const_iterator operator--(int) - { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } - - //Arithmetic - vector_const_iterator& operator+=(difference_type off) - { m_ptr += off; return *this; } - - vector_const_iterator operator+(difference_type off) const - { return vector_const_iterator(m_ptr+off); } - - friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) - { return vector_const_iterator(off + right.m_ptr); } - - vector_const_iterator& operator-=(difference_type off) - { m_ptr -= off; return *this; } - - vector_const_iterator operator-(difference_type off) const - { return vector_const_iterator(m_ptr-off); } - - difference_type operator-(const vector_const_iterator& right) const - { return m_ptr - right.m_ptr; } - - //Comparison operators - bool operator== (const vector_const_iterator& r) const - { return m_ptr == r.m_ptr; } - - bool operator!= (const vector_const_iterator& r) const - { return m_ptr != r.m_ptr; } - - bool operator< (const vector_const_iterator& r) const - { return m_ptr < r.m_ptr; } - - bool operator<= (const vector_const_iterator& r) const - { return m_ptr <= r.m_ptr; } - - bool operator> (const vector_const_iterator& r) const - { return m_ptr > r.m_ptr; } - - bool operator>= (const vector_const_iterator& r) const - { return m_ptr >= r.m_ptr; } -}; - -//! Iterator used to iterate through a vector -template -class vector_iterator - : public vector_const_iterator -{ - public: - explicit vector_iterator(Pointer ptr) - : vector_const_iterator(ptr) - {} - - public: - typedef typename std::iterator_traits::value_type value_type; - typedef typename vector_const_iterator::difference_type difference_type; - typedef Pointer pointer; - typedef value_type& reference; - - //Constructors - vector_iterator() - {} - - //Pointer like operators - reference operator*() const - { return *this->m_ptr; } - - value_type* operator->() const - { return detail::get_pointer(this->m_ptr); } - - reference operator[](difference_type off) const - { return this->m_ptr[off]; } - - //Increment / Decrement - vector_iterator& operator++() - { ++this->m_ptr; return *this; } - - vector_iterator operator++(int) - { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } - - vector_iterator& operator--() - { --this->m_ptr; return *this; } - - vector_iterator operator--(int) - { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } - - // Arithmetic - vector_iterator& operator+=(difference_type off) - { this->m_ptr += off; return *this; } - - vector_iterator operator+(difference_type off) const - { return vector_iterator(this->m_ptr+off); } - - friend vector_iterator operator+(difference_type off, const vector_iterator& right) - { return vector_iterator(off + right.m_ptr); } - - vector_iterator& operator-=(difference_type off) - { this->m_ptr -= off; return *this; } - - vector_iterator operator-(difference_type off) const - { return vector_iterator(this->m_ptr-off); } - - difference_type operator-(const vector_const_iterator& right) const - { return static_cast&>(*this) - right; } -}; - -template -struct vector_value_traits -{ - typedef T value_type; - typedef A allocator_type; - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::value; - - //This is the anti-exception array destructor - //to deallocate values already constructed - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type OldArrayDestructor; - //This is the anti-exception array destructor - //to destroy objects created with copy construction - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type UCopiedArrayDestructor; - //This is the anti-exception array deallocator - typedef typename detail::if_c - - ,detail::scoped_array_deallocator - >::type UCopiedArrayDeallocator; - - //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 - ,const T* - ,detail::move_iterator - >::type copy_move_it; - - //This is the optimized move iterator for assignments - //so that std::uninitialized_copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,const T* - ,detail::move_iterator - >::type assign_move_it; -}; - -//!This struct deallocates and allocated memory -template -struct vector_alloc_holder -{ - typedef typename A::pointer pointer; - typedef typename A::size_type size_type; - typedef typename A::value_type value_type; - typedef vector_value_traits value_traits; - - //Constructor, does not throw - vector_alloc_holder(const A &a) - : members_(a) - {} - - //Constructor, does not throw - vector_alloc_holder(const vector_alloc_holder &h) - : members_(h.alloc()) - {} - - //Destructor - ~vector_alloc_holder() - { - this->prot_destroy_all(); - this->prot_deallocate(); - } - - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant::value> alloc_version; - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, const pointer &reuse = 0) - { - return allocation_command(command, limit_size, preferred_size, - received_size, reuse, alloc_version()); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v1) - { - (void)limit_size; - (void)reuse; - if(!(command & allocate_new)) - return std::pair(pointer(0), 0); - received_size = preferred_size; - return std::make_pair(this->alloc().allocate(received_size), false); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v2) - { - return this->alloc().allocation_command - (command, limit_size, preferred_size, received_size, reuse); - } - - size_type next_capacity(size_type additional_objects) const - { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); } - - struct members_holder - : public A - { - private: - members_holder(const members_holder&); - - public: - members_holder(const A &alloc) - : A(alloc), m_start(0), m_size(0), m_capacity(0) - {} - - pointer m_start; - size_type m_size; - size_type m_capacity; - } members_; - - protected: - void prot_deallocate() - { - if(!this->members_.m_capacity) return; - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - this->members_.m_start = 0; - this->members_.m_size = 0; - this->members_.m_capacity = 0; - } - - void destroy(value_type* p) - { - if(!value_traits::trivial_dctr) - detail::get_pointer(p)->~value_type(); - } - - void destroy_n(value_type* p, size_type n) - { - if(!value_traits::trivial_dctr) - for(; n--; ++p) p->~value_type(); - } - - void prot_destroy_all() - { - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->members_.m_size = 0; - } - - A &alloc() - { return members_; } - - const A &alloc() const - { return members_; } -}; - -} //namespace detail { -/// @endcond - -//! A vector is a sequence that supports random access to elements, constant -//! time insertion and removal of elements at the end, and linear time insertion -//! and removal of elements at the beginning or in the middle. The number of -//! elements in a vector may vary dynamically; memory management is automatic. -//! boost::interprocess::vector is similar to std::vector but it's compatible -//! with shared memory and memory mapped files. -template -class vector : private detail::vector_alloc_holder -{ - /// @cond - typedef vector self_t; - typedef detail::vector_alloc_holder base_t; - /// @endcond - public: - //! The type of object, T, stored in the vector - typedef T value_type; - //! Pointer to T - typedef typename A::pointer pointer; - //! Const pointer to T - typedef typename A::const_pointer const_pointer; - //! Reference to T - typedef typename A::reference reference; - //! Const reference to T - typedef typename A::const_reference const_reference; - //! An unsigned integral type - typedef typename A::size_type size_type; - //! A signed integral type - typedef typename A::difference_type difference_type; - //! The allocator type - typedef A allocator_type; - //! The random access iterator - typedef detail::vector_iterator iterator; - //! The random access const_iterator - typedef detail::vector_const_iterator const_iterator; - - //! Iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - reverse_iterator; - //! Const iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - const_reverse_iterator; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - - /// @cond - private: - typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; - typedef detail::vector_value_traits value_traits; - - typedef typename base_t::allocator_v1 allocator_v1; - typedef typename base_t::allocator_v2 allocator_v2; - typedef typename base_t::alloc_version alloc_version; - - typedef constant_iterator cvalue_iterator; - typedef repeat_iterator repeat_it; - typedef detail::move_iterator repeat_move_it; - /// @endcond - - public: - - //! Effects: Constructs a vector taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit vector(const A& a = A()) - : base_t(a) - {} - - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - vector(size_type n, const T& value = T(), - const allocator_type& a = allocator_type()) - : base_t(a) - { this->insert(this->cend(), n, value); } - - //! Effects: Copy constructs a vector. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - vector(const vector& x) - : base_t((base_t&)x) - { *this = x; } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - vector(detail::moved_object > mx) - : base_t(mx.get()) - { this->swap(mx.get()); } - #else - vector(vector && mx) - : base_t(detail::move_impl(mx)) - { this->swap(mx); } - #endif - - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the vector. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - vector(InIt first, InIt last, const allocator_type& a = allocator_type()) - : base_t(a) - { this->assign(first, last); } - - //! Effects: Destroys the vector. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~vector() - {} //vector_alloc_holder clears the data - - //! Effects: Returns an iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return const_iterator(this->members_.m_start); } - - //! Effects: Returns an iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->members_.m_start + this->members_.m_size); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(this->end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin()const - { return this->crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(this->begin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return this->crend(); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->members_.m_start + this->members_.m_size); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin()const - { return const_reverse_iterator(this->end());} - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return const_reverse_iterator(this->begin()); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - pointer data() - { return this->members_.m_start; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_pointer data() const - { return this->members_.m_start; } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->members_.m_size; } - - //! Effects: Returns the largest possible size of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return this->alloc().max_size(); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return this->members_.m_capacity; } - - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->members_.m_size; } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const - { return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return this->alloc(); } - - const stored_allocator_type &get_stored_allocator() const - { return this->alloc(); } - - stored_allocator_type &get_stored_allocator() - { return this->alloc(); } - - //! Effects: If n is less than or equal to capacity(), this call has no - //! effect. Otherwise, it is a request for allocation of additional memory. - //! If the request is successful, then capacity() is greater than or equal to - //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - void reserve(size_type new_cap) - { - if (this->capacity() < new_cap){ - //There is not enough memory, allocate a new - //buffer or expand the old one. - bool same_buffer_start; - size_type real_cap = 0; - std::pair ret = - this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - new_cap, new_cap, real_cap, this->members_.m_start); - - //Check for forward expansion - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->members_.m_capacity = real_cap; - } - //If there is no forward expansion, move objects - else{ - //We will reuse insert code, so create a dummy input iterator - typename value_traits::copy_move_it dummy_it(detail::get_pointer(this->members_.m_start)); - detail::advanced_insert_aux_proxy - proxy(dummy_it, dummy_it); - //Backwards (and possibly forward) expansion - if(ret.second){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(this->members_.m_start) - , 0 - , proxy); - } - //New buffer - else{ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(this->members_.m_start) - , 0 - , proxy); - } - } - } - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - vector& operator=(const vector& x) - { - if (&x != this){ - this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - vector& operator=(detail::moved_object > mx) - { - vector &x = mx.get(); - #else - vector& operator=(vector && x) - { - #endif - if (&x != this){ - this->swap(x); - x.clear(); - } - return *this; - } - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const value_type& val) - { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Inserts a copy of x at the end of the vector. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_back(const T& x) - { - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)(detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); - ++this->members_.m_size; - } - else{ - this->insert(this->cend(), x); - } - } - - //! Effects: Constructs a new element in the end of the vector - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back(detail::moved_object mx) - { - value_type &x = mx.get(); - #else - void push_back(T && x) - { - #endif - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(detail::move_impl(x)); - ++this->members_.m_size; - } - else{ - this->insert(this->cend(), detail::move_impl(x)); - } - } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the vector. - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: Amortized constant time. - template - void emplace_back(Args &&...args) - { - T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)(back_pos))value_type(detail::forward_impl(args)...); - ++this->members_.m_size; - } - else{ - detail::advanced_insert_aux_emplace proxy - (detail::forward_impl(args)...); - priv_range_insert(back_pos, 1, proxy); - } - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before position - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - template - iterator emplace(const_iterator position, Args && ...args) - { - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - detail::advanced_insert_aux_emplace proxy - (detail::forward_impl(args)...); - priv_range_insert(position.get_ptr(), 1, proxy); - return iterator(this->members_.m_start + pos_n); - } - - #else - - void emplace_back() - { - T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - if (this->members_.m_size < this->members_.m_capacity){ - //There is more memory, just construct a new object at the end - new((void*)(back_pos))value_type(); - ++this->members_.m_size; - } - else{ - detail::advanced_insert_aux_emplace proxy; - priv_range_insert(back_pos, 1, proxy); - } - } - - iterator emplace(const_iterator position) - { - size_type pos_n = position - cbegin(); - detail::advanced_insert_aux_emplace proxy; - priv_range_insert(detail::get_pointer(position.get_ptr()), 1, proxy); - return iterator(this->members_.m_start + pos_n); - } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; \ - if (this->members_.m_size < this->members_.m_capacity){ \ - new((void*)(back_pos))value_type \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - ++this->members_.m_size; \ - } \ - else{ \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_range_insert(back_pos, 1, proxy); \ - } \ - } \ - \ - template \ - iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - size_type pos_n = pos - cbegin(); \ - detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_range_insert(detail::get_pointer(pos.get_ptr()), 1, proxy); \ - return iterator(this->members_.m_start + pos_n); \ - } \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(vector& x) - #else - void swap(vector &&x) - #endif - { - allocator_type &this_al = this->alloc(), &other_al = x.alloc(); - //Just swap internals - detail::do_swap(this->members_.m_start, x.members_.m_start); - detail::do_swap(this->members_.m_size, x.members_.m_size); - detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); - - if (this_al != other_al){ - detail::do_swap(this_al, other_al); - } - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before position. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator position, const T& x) - { - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - this->insert(position, (size_type)1, x); - return iterator(this->members_.m_start + pos_n); - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object mx) - { - value_type &x = mx.get(); - #else - iterator insert(const_iterator position, T &&x) - { - #endif - //Just call more general insert(pos, size, value) and return iterator - size_type pos_n = position - cbegin(); - this->insert(position - ,repeat_move_it(repeat_it(x, 1)) - ,repeat_move_it(repeat_it())); - return iterator(this->members_.m_start + pos_n); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws or T's copy constructor throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator pos, InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } - - //! Effects: Removes the last element from the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_back() - { - //Destroy last element - --this->members_.m_size; - this->destroy(detail::get_pointer(this->members_.m_start) + this->members_.m_size); - } - - //! Effects: Erases the element at position pos. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the elements between pos and the - //! last element. Constant if pos is the first or the last element. - iterator erase(const_iterator position) - { - T *pos = detail::get_pointer(position.get_ptr()); - T *beg = detail::get_pointer(this->members_.m_start); - typedef typename value_traits::assign_move_it assign_move_it; - std::copy(assign_move_it(pos + 1), assign_move_it(beg + this->members_.m_size), pos); - --this->members_.m_size; - //Destroy last element - base_t::destroy(detail::get_pointer(this->members_.m_start) + this->members_.m_size); - return iterator(position.get_ptr()); - } - - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last. - iterator erase(const_iterator first, const_iterator last) - { - typedef typename value_traits::assign_move_it assign_move_it; - if (first != last){ // worth doing, copy down over hole - T* end_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - T* ptr = detail::get_pointer(std::copy - (assign_move_it(detail::get_pointer(last.get_ptr())) - ,assign_move_it(end_pos) - ,detail::get_pointer(first.get_ptr()) - )); - size_type destroyed = (end_pos - ptr); - this->destroy_n(ptr, destroyed); - this->members_.m_size -= destroyed; - } - return iterator(first.get_ptr()); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const T& x) - { - pointer finish = this->members_.m_start + this->members_.m_size; - if (new_size < size()){ - //Destroy last elements - this->erase(const_iterator(this->members_.m_start + new_size), this->end()); - } - else{ - //Insert new elements at the end - this->insert(const_iterator(finish), new_size - this->size(), x); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - if (new_size < this->size()){ - //Destroy last elements - this->erase(const_iterator(this->members_.m_start + new_size), this->end()); - } - else{ - size_type n = new_size - this->size(); - this->reserve(new_size); - detail::default_construct_aux_proxy proxy(n); - priv_range_insert(this->cend().get_ptr(), n, proxy); - } - } - - //! Effects: Erases all the elements of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the vector. - void clear() - { this->prot_destroy_all(); } - - /// @cond - - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { priv_shrink_to_fit(alloc_version()); } - - private: - void priv_shrink_to_fit(allocator_v1) - { - if(this->members_.m_capacity){ - if(!size()){ - this->prot_deallocate(); - } - else{ - //This would not work with stateful allocators - vector(*this).swap(*this); - } - } - } - - void priv_shrink_to_fit(allocator_v2) - { - if(this->members_.m_capacity){ - if(!size()){ - this->prot_deallocate(); - } - else{ - size_type received_size; - 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 - } - } - } - } - - template - void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { - if(first != last){ - const size_type n = std::distance(first, last); - detail::advanced_insert_aux_proxy proxy(first, last); - priv_range_insert(pos, n, proxy); - } - } - - void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf) - { - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair ret; - size_type real_cap = this->members_.m_capacity; - - //Check if we already have room - if (n <= remaining){ - same_buffer_start = true; - } - else{ - //There is not enough memory, allocate a new - //buffer or expand the old one. - size_type new_cap = this->next_capacity(n); - ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->members_.m_size + n, new_cap, real_cap, this->members_.m_start); - - //Check for forward expansion - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - this->members_.m_capacity = real_cap; - } - } - - //If we had room or we have expanded forward - if (same_buffer_start){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->priv_range_insert_expand_forward - (detail::get_pointer(pos), n, interf); - } - //Backwards (and possibly forward) expansion - else if(ret.second){ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(pos) - , n - , interf); - } - //New buffer - else{ - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( detail::get_pointer(ret.first) - , real_cap - , detail::get_pointer(pos) - , n - , interf); - } - } - - void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf) - { - typedef typename value_traits::copy_move_it copy_move_it; - typedef typename value_traits::assign_move_it assign_move_it; - //There is enough memory - T* old_finish = detail::get_pointer(this->members_.m_start) + this->members_.m_size; - const size_type elems_after = old_finish - pos; - - if (elems_after > n){ - //New elements can be just copied. - //Move to uninitialized memory last objects - 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(pos), assign_move_it(old_finish - n), old_finish); - //Insert new objects in the pos - interf.copy_all_to(pos); - } - else { - //The new elements don't fit in the [pos, end()) range. Copy - //to the beginning of the unallocated zone the last new elements. - interf.uninitialized_copy_some_and_update(old_finish, elems_after, false); - this->members_.m_size += n - elems_after; - //Copy old [pos, end()) elements to the uninitialized memory - std::uninitialized_copy - ( 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 - interf.copy_all_to(pos); - } - } - - void priv_range_insert_new_allocation - (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf) - { - typedef typename value_traits::copy_move_it copy_move_it; - T* new_finish = new_start; - T *old_finish; - //Anti-exception rollbacks - typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); - typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u); - - //Initialize with [begin(), pos) old buffer - //the start of the new buffer - new_finish = std::uninitialized_copy - ( copy_move_it(detail::get_pointer(this->members_.m_start)) - , copy_move_it(pos) - , old_finish = new_finish); - constructed_values_destroyer.increment_size(new_finish - old_finish); - //Initialize new objects, starting from previous point - interf.uninitialized_copy_all_to(old_finish = new_finish); - new_finish += n; - constructed_values_destroyer.increment_size(new_finish - old_finish); - //Initialize from the rest of the old buffer, - //starting from previous point - new_finish = std::uninitialized_copy - ( copy_move_it(pos) - , copy_move_it(detail::get_pointer(this->members_.m_start) + this->members_.m_size) - , new_finish); - - //All construction successful, disable rollbacks - constructed_values_destroyer.release(); - scoped_alloc.release(); - //Destroy and deallocate old elements - //If there is allocated memory, destroy and deallocate - if(this->members_.m_start != 0){ - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - } - this->members_.m_start = new_start; - this->members_.m_size = new_finish - new_start; - this->members_.m_capacity = new_cap; - } - - void priv_range_insert_expand_backwards - (T* new_start, size_type new_capacity, - T* pos, const size_type n, advanced_insert_aux_int_t &interf) - { - typedef typename value_traits::copy_move_it copy_move_it; - typedef typename value_traits::assign_move_it assign_move_it; - - //Backup old data - T* old_start = detail::get_pointer(this->members_.m_start); - T* old_finish = old_start + this->members_.m_size; - size_type old_size = this->members_.m_size; - - //We can have 8 possibilities: - const size_type elemsbefore = (size_type)(pos - old_start); - const size_type s_before = (size_type)(old_start - new_start); - - //Update the vector buffer information to a safe state - this->members_.m_start = new_start; - this->members_.m_capacity = new_capacity; - this->members_.m_size = 0; - - //If anything goes wrong, this object will destroy - //all the old objects to fulfill previous vector state - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); - //Check if s_before is big enough to hold the beginning of old data + new data - if(difference_type(s_before) >= difference_type(elemsbefore + n)){ - //Copy first old values before pos, after that the new objects - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(pos), new_start); - this->members_.m_size = elemsbefore; - interf.uninitialized_copy_all_to(new_start + elemsbefore); - this->members_.m_size += n; - //Check if s_before is so big that even copying the old data + new data - //there is a gap between the new data and the old data - if(s_before >= (old_size + n)){ - //Old situation: - // _________________________________________________________ - //| raw_mem | old_begin | old_end | - //| __________________________________|___________|_________| - // - //New situation: - // _________________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|________________________| - // - //Now initialize the rest of memory with the last old values - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(old_finish), new_start + elemsbefore + n); - //All new elements correctly constructed, avoid new element destruction - this->members_.m_size = old_size + n; - //Old values destroyed automatically with "old_values_destroyer" - //when "old_values_destroyer" goes out of scope unless the have trivial - //destructor after move. - if(value_traits::trivial_dctr_after_move) - old_values_destroyer.release(); - } - //s_before is so big that divides old_end - else{ - //Old situation: - // __________________________________________________ - //| raw_mem | old_begin | old_end | - //| ___________________________|___________|_________| - // - //New situation: - // __________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|_________________| - // - //Now initialize the rest of memory with the last old values - //All new elements correctly constructed, avoid new element destruction - 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(pos), copy_move_it(pos + raw_gap), new_start + elemsbefore + n); - //Update size since we have a contiguous buffer - this->members_.m_size = old_size + s_before; - //All new elements correctly constructed, avoid old element destruction - old_values_destroyer.release(); - //Now copy remaining last objects in the old buffer begin - 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; - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(to_destroy, n_destroy); - this->members_.m_size -= n_destroy; - } - } - else{ - //Check if we have to do the insertion in two phases - //since maybe s_before is not big enough and - //the buffer was expanded both sides - // - //Old situation: - // _________________________________________________ - //| raw_mem | old_begin + old_end | raw_mem | - //|_________|_____________________|_________________| - // - //New situation with do_after: - // _________________________________________________ - //| old_begin + new + old_end | raw_mem | - //|___________________________________|_____________| - // - //New without do_after: - // _________________________________________________ - //| old_begin + new + old_end | raw_mem | - //|____________________________|____________________| - // - bool do_after = n > s_before; - - //Now we can have two situations: the raw_mem of the - //beginning divides the old_begin, or the new elements: - if (s_before <= elemsbefore) { - //The raw memory divides the old_begin group: - // - //If we need two phase construction (do_after) - //new group is divided in new = new_beg + new_end groups - //In this phase only new_beg will be inserted - // - //Old situation: - // _________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|_________|___________|_________|_________________| - // - //New situation with do_after(1): - //This is not definitive situation, the second phase - //will include - // _________________________________________________ - //| old_begin | new_beg | old_end | raw_mem | - //|___________|_________|_________|_________________| - // - //New situation without do_after: - // _________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|_____|_________|_____________________| - // - //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), 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(pos), old_start); - if(do_after){ - //Now copy the new_beg elements - interf.copy_some_and_update(next, s_before, true); - } - else{ - //Now copy the all the new elements - interf.copy_all_to(next); - T* move_start = next + n; - //Now displace old_end elements - 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; - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(move_end, n_destroy); - this->members_.m_size -= n_destroy; - } - } - else { - //If we have to expand both sides, - //we will play if the first new values so - //calculate the upper bound of new values - - //The raw memory divides the new elements - // - //If we need two phase construction (do_after) - //new group is divided in new = new_beg + new_end groups - //In this phase only new_beg will be inserted - // - //Old situation: - // _______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|_______________|___________|_________|_________________| - // - //New situation with do_after(): - // ____________________________________________________ - //| old_begin | new_beg | old_end | raw_mem | - //|___________|_______________|_________|______________| - // - //New situation without do_after: - // ______________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|_____|_________|__________________________| - // - //First copy whole old_begin and part of new to raw_mem - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(pos), new_start); - this->members_.m_size = elemsbefore; - - const size_type mid_n = difference_type(s_before) - elemsbefore; - interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true); - this->members_.m_size = old_size + s_before; - //The buffer is all constructed until old_end, - //release destroyer and update size - old_values_destroyer.release(); - - if(do_after){ - //Copy new_beg part - interf.copy_some_and_update(old_start, s_before - mid_n, true); - } - else{ - //Copy all new elements - interf.copy_all_to(old_start); - T* move_start = old_start + (n-mid_n); - //Displace old_end - 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; - if(!value_traits::trivial_dctr_after_move) - this->destroy_n(move_end, n_destroy); - this->members_.m_size -= n_destroy; - } - } - - //This is only executed if two phase construction is needed - //This can be executed without exception handling since we - //have to just copy and append in raw memory and - //old_values_destroyer has been released in phase 1. - if(do_after){ - //The raw memory divides the new elements - // - //Old situation: - // ______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|______________| - // - //New situation with do_after(1): - // _______________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_________|________|_________| - // - //New situation with do_after(2): - // ______________________________________________________ - //| old_begin + new | old_end |raw | - //|_______________________________________|_________|____| - // - const size_type n_after = n - s_before; - const difference_type elemsafter = old_size - elemsbefore; - - //We can have two situations: - if (elemsafter > difference_type(n_after)){ - //The raw_mem from end will divide displaced old_end - // - //Old situation: - // ______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|______________| - // - //New situation with do_after(1): - // _______________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_________|________|_________| - // - //First copy the part of old_end raw_mem - T* finish_n = old_finish - difference_type(n_after); - std::uninitialized_copy - (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(pos), assign_move_it(finish_n), old_finish); - //Now overwrite with new_end - //The new_end part is [first + (n - n_after), last) - interf.copy_all_to(pos); - } - else { - //The raw_mem from end will divide new_end part - // - //Old situation: - // _____________________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|_____________________| - // - //New situation with do_after(2): - // _____________________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_______________|________|_________| - // - size_type mid_last_dist = n_after - elemsafter; - //First initialize data in raw memory - //The new_end part is [first + (n - n_after), last) - interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); - this->members_.m_size += mid_last_dist; - std::uninitialized_copy(copy_move_it(pos), copy_move_it(old_finish), old_finish + mid_last_dist); - this->members_.m_size += n_after - mid_last_dist; - //Now copy the part of new_end over constructed elements - interf.copy_all_to(pos); - } - } - } - } - - template - void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, detail::move_impl(value_type(*first))); - } - } - - template - void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) - { - //Overwrite all elements we can from [first, last) - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ - *cur = *first; - } - - if (first == last){ - //There are no more elements in the sequence, erase remaining - this->erase(cur, cend()); - } - else{ - //There are more elements in the range, insert the remaining ones - this->insert(this->cend(), first, last); - } - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, - std::forward_iterator_tag) - { - size_type n = std::distance(first, last); - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair ret; - size_type real_cap = this->members_.m_capacity; - - if (n <= remaining){ - same_buffer_start = true; - } - else{ - //There is not enough memory, allocate a new buffer - size_type new_cap = this->next_capacity(n); - ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->size() + n, new_cap, real_cap, this->members_.m_start); - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - this->members_.m_capacity = real_cap; - } - } - - if(same_buffer_start){ - T *start = detail::get_pointer(this->members_.m_start); - if (this->size() >= n){ - //There is memory, but there are more old elements than new ones - //Overwrite old elements with new ones - std::copy(first, last, start); - //Destroy remaining old elements - this->destroy_n(start + n, this->members_.m_size - n); - this->members_.m_size = n; - } - else{ - //There is memory, but there are less old elements than new ones - //First overwrite some old elements with new ones - FwdIt mid = first; - std::advance(mid, this->size()); - T *end = std::copy(first, mid, start); - //Initialize the remaining new elements in the uninitialized memory - std::uninitialized_copy(mid, last, end); - this->members_.m_size = n; - } - } - else if(!ret.second){ - typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); - std::uninitialized_copy(first, last, detail::get_pointer(ret.first)); - scoped_alloc.release(); - //Destroy and deallocate old buffer - if(this->members_.m_start != 0){ - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - } - this->members_.m_start = ret.first; - this->members_.m_size = n; - this->members_.m_capacity = real_cap; - } - else{ - //Backwards expansion - //If anything goes wrong, this object will destroy old objects - T *old_start = detail::get_pointer(this->members_.m_start); - size_type old_size = this->members_.m_size; - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size); - //If something goes wrong size will be 0 - //but holding the whole buffer - this->members_.m_size = 0; - this->members_.m_start = ret.first; - this->members_.m_capacity = real_cap; - - //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 = first; - std::advance(mid, first_count); - std::uninitialized_copy(first, mid, detail::get_pointer(ret.first)); - - if(old_offset > n){ - //All old elements will be destroyed by "old_values_destroyer" - this->members_.m_size = n; - } - else{ - //We have constructed objects from the new begin until - //the old end so release the rollback destruction - old_values_destroyer.release(); - this->members_.m_start = ret.first; - this->members_.m_size = first_count + old_size; - //Now overwrite the old values - size_type second_count = min_value(old_size, n - first_count); - FwdIt mid2 = mid; - std::advance(mid2, second_count); - std::copy(mid, mid2, old_start); - - //Check if we still have to append elements in the - //uninitialized end - if(second_count == old_size){ - std::copy(mid2, last, old_start + old_size); - } - else{ - //We have to destroy some old values - this->destroy_n - (old_start + second_count, old_size - second_count); - this->members_.m_size = n; - } - this->members_.m_size = n; - } - } - } - - template - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InIt first, InIt last, detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, detail::true_) - { this->insert(pos, (size_type)n, (T)val); } - - template - void priv_insert_dispatch(const_iterator pos, InIt first, - InIt last, detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); - } - - void priv_check_range(size_type n) const - { - //If n is out of range, throw an out_of_range exception - if (n >= size()) - throw std::out_of_range("vector::at"); - } - - #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS - 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_shrink = 0; } - #endif - /// @endcond -}; - -template -inline bool -operator==(const vector& x, const vector& y) -{ - //Check first size and each element if needed - return x.size() == y.size() && - std::equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool -operator!=(const vector& x, const vector& y) -{ - //Check first size and each element if needed - return x.size() != y.size() || - !std::equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool -operator<(const vector& x, const vector& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), - y.begin(), y.end()); -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(vector& x, vector& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, vector& y) -{ x.get().swap(y); } - -template -inline void swap(vector &x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(vector&&x, vector&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::vector; } //namespace interprocess { } //namespace boost { #include -#endif // #ifndef BOOST_INTERPROCESS_VECTOR_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP diff --git a/include/boost/interprocess/containers/version_type.hpp b/include/boost/interprocess/containers/version_type.hpp new file mode 100644 index 0000000..06e7419 --- /dev/null +++ b/include/boost/interprocess/containers/version_type.hpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. 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_CONTAINERS_VERSION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::interprocess_container::containers_detail::version_type; +using boost::interprocess_container::containers_detail::version; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + diff --git a/include/boost/interprocess/detail/atomic.hpp b/include/boost/interprocess/detail/atomic.hpp index 094bc0c..b8a8086 100644 --- a/include/boost/interprocess/detail/atomic.hpp +++ b/include/boost/interprocess/detail/atomic.hpp @@ -48,7 +48,7 @@ inline boost::uint32_t atomic_cas32 } //namespace interprocess{ } //namespace boost{ -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) #include diff --git a/include/boost/interprocess/detail/file_wrapper.hpp b/include/boost/interprocess/detail/file_wrapper.hpp index 22f92e9..091a14f 100644 --- a/include/boost/interprocess/detail/file_wrapper.hpp +++ b/include/boost/interprocess/detail/file_wrapper.hpp @@ -24,7 +24,12 @@ namespace detail{ class file_wrapper { + /// @cond + file_wrapper(file_wrapper&); + file_wrapper & operator=(file_wrapper&); + /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_wrapper) //!Default constructor. //!Represents an empty file_wrapper. @@ -49,34 +54,18 @@ class file_wrapper //!Moves the ownership of "moved"'s file to *this. //!After the call, "moved" does not represent any file. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_wrapper - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - file_wrapper(file_wrapper &&moved) + file_wrapper(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s file to *this. //!After the call, "moved" does not represent any file. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_wrapper &operator= - (detail::moved_object moved) + file_wrapper &operator=(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved) { - file_wrapper tmp(moved); + file_wrapper tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - file_wrapper &operator=(file_wrapper &&moved) - { - file_wrapper tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif //!Swaps to file_wrappers. //!Does not throw diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index ab0744c..72645e2 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -98,7 +98,7 @@ class basic_managed_memory_impl segment_manager::char_ptr_holder_t char_ptr_holder_t; //Experimental. Don't use. - typedef typename segment_manager::multiallocation_iterator multiallocation_iterator; + typedef typename segment_manager::multiallocation_chain multiallocation_chain; /// @endcond @@ -291,7 +291,7 @@ class basic_managed_memory_impl template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0) { @@ -310,21 +310,25 @@ class basic_managed_memory_impl //Experimental. Don't use. //!Allocates n_elements of elem_size bytes. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) { return mp_header->allocate_many(elem_bytes, num_elements); } //!Allocates n_elements, each one of elem_sizes[i] bytes. - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements) + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements) { return mp_header->allocate_many(elem_sizes, n_elements); } //!Allocates n_elements of elem_size bytes. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t nothrow) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t nothrow) { return mp_header->allocate_many(elem_bytes, num_elements, nothrow); } //!Allocates n_elements, each one of elem_sizes[i] bytes. - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow) + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow) { return mp_header->allocate_many(elem_sizes, n_elements, nothrow); } + //!Allocates n_elements, each one of elem_sizes[i] bytes. + void deallocate_many(multiallocation_chain chain) + { return mp_header->deallocate_many(boost::interprocess::move(chain)); } + /// @endcond //!Marks previously allocated memory as free. Never throws. diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp index 3a3b0c9..948e865 100644 --- a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -315,21 +315,21 @@ class basic_managed_multi_shared_memory case create_open_func::DoCreate: { managed_impl shm(create_only, name, size, read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; case create_open_func::DoOpen: { managed_impl shm(open_only, name,read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; case create_open_func::DoOpenOrCreate: { managed_impl shm(open_or_create, name, size, read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; @@ -339,7 +339,7 @@ class basic_managed_multi_shared_memory } //This can throw. - m_shmem_list.push_back(detail::move_impl(mshm)); + m_shmem_list.push_back(boost::interprocess::move(mshm)); return true; } BOOST_CATCH(const std::bad_alloc&){ 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 caa7741..d71ec1b 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -37,8 +37,8 @@ template class managed_open_or_create_impl { //Non-copyable - managed_open_or_create_impl(const managed_open_or_create_impl &); - managed_open_or_create_impl &operator=(const managed_open_or_create_impl &); + managed_open_or_create_impl(managed_open_or_create_impl &); + managed_open_or_create_impl &operator=(managed_open_or_create_impl &); enum { @@ -49,6 +49,7 @@ class managed_open_or_create_impl }; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(managed_open_or_create_impl) static const std::size_t ManagedOpenOrCreateUserOffset = @@ -154,34 +155,16 @@ class managed_open_or_create_impl , construct_func); } - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - 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(BOOST_INTERPROCESS_RV_REF(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=(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved) { - managed_open_or_create_impl tmp(moved); + managed_open_or_create_impl tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved) - { - managed_open_or_create_impl tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif - ~managed_open_or_create_impl() {} @@ -437,20 +420,6 @@ inline void swap(managed_open_or_create_impl &x } //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/move.hpp b/include/boost/interprocess/detail/move.hpp index ca5c0e2..7fcead5 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -1,175 +1,749 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// 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. +// See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// +// +// Parts of this file come from Adobe's Move library: +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt +// or a copy at http://stlab.adobe.com/licenses.html) +// +////////////////////////////////////////////////////////////////////////////// + +//! \file #ifndef BOOST_INTERPROCESS_MOVE_HPP #define BOOST_INTERPROCESS_MOVE_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include -#include - -//!\file -//!Describes a function and a type to emulate move semantics. +#include +#include //copy, copy_backward +#include //uninitialized_copy +#include //std::iterator +#include +#include +#include namespace boost { namespace interprocess { +namespace move_detail { -//!Trait class to detect if a type is -//!movable template -struct is_movable +struct identity { - enum { value = false }; + typedef T type; }; +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; +}; + +} //namespace move_detail { } //namespace interprocess { } //namespace boost { -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - -#include -#include +#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) namespace boost { namespace interprocess { -namespace detail { -//!An object that represents a -//!moved object. -template -struct moved_object -{ - moved_object(const T &obj) - : m_obj(const_cast(&obj)) - {} - - T &get() const - { return *m_obj; } - - private: - T *m_obj; -}; - -// Metafunction that, given movable T, provides move_source, else T&. -template -struct move_type +////////////////////////////////////////////////////////////////////////////// +// +// struct rv +// +////////////////////////////////////////////////////////////////////////////// +template +class rv : public T { - public: // metafunction result - typedef typename if_, moved_object, T&>::type type; -}; - -template -class move_return -{ - typedef moved_object moved_type; - private: - mutable T m_moved; - + rv(); + ~rv(); + rv(rv const&); + void operator=(rv const&); public: - typedef T type; - - move_return(const T& returned) - : m_moved(moved_object(returned)) - {} - - move_return(const move_return& operand) - : m_moved(const_cast(operand)) - {} - - operator moved_type() const - { return moved_type(m_moved); } + //T &get() { return *this; } }; -template -struct return_type +////////////////////////////////////////////////////////////////////////////// +// +// move_detail::is_rv +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { + +template +struct is_rv { - public: // metafunction result - - typedef typename if_, move_return, T>::type type; + static const bool value = false; }; -} //namespace detail { -} //namespace interprocess { -} //namespace boost { +template +struct is_rv< rv > +{ + static const bool value = true; +}; -namespace boost { -namespace interprocess { +} //namespace move_detail { -namespace detail{ +////////////////////////////////////////////////////////////////////////////// +// +// is_movable +// +////////////////////////////////////////////////////////////////////////////// +template +class is_movable +{ + public: + static const bool value = move_detail::is_convertible&>::value; +}; -//!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_impl(const Object &object) -{ - typedef typename detail::move_type::type type; - return type(object); +template +class is_movable< rv > +{ + public: + static const bool value = false; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// move() +// +////////////////////////////////////////////////////////////////////////////// +template +typename boost::disable_if, T&>::type move(T& x) +{ + return x; } template -inline const T& forward_impl(const T &t) -{ return t; } +typename enable_if, rv&>::type move(T& x) +{ + return static_cast& >(x); +} template -inline T& forward_impl(T &t) -{ return t; } +typename enable_if, rv&>::type move(const rv& x) +{ + return const_cast& >(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// forward() +// +////////////////////////////////////////////////////////////////////////////// template -inline detail::moved_object forward_impl(detail::moved_object &t) -{ return t; } +typename enable_if, T &>::type + forward(const typename move_detail::identity::type &x) +{ + return const_cast(x); +} -} //namespace detail { +/* +template +typename enable_if, T &>::type +forward(typename move_detail::identity::type &x) +{ + return x; +} -//!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); } +template +typename disable_if, T &>::type + forward(typename move_detail::identity::type &x) +{ + return x; +} +*/ +template +typename disable_if, const T &>::type + forward(const typename move_detail::identity::type &x) +{ + return x; +} +////////////////////////////////////////////////////////////////////////////// +// +// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ + operator boost::interprocess::rv&() \ + { return static_cast& >(*this); }\ + operator const boost::interprocess::rv&() \ + { return static_cast& >(*this); }\ +// + + +#define BOOST_INTERPROCESS_RV_REF(TYPE)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_FWD_REF(TYPE)\ + const TYPE & \ +// } //namespace interprocess { -} //namespace boost { +} //namespace boost -#else //#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#else //BOOST_HAS_RVALUE_REFS -#include +#include namespace boost { namespace interprocess { -namespace detail { +////////////////////////////////////////////////////////////////////////////// +// +// is_movable +// +////////////////////////////////////////////////////////////////////////////// -template -inline typename detail::remove_reference::type&& move_impl(T&& t) +//! For compilers with rvalue references, this traits class returns true +//! if T && is convertible to T. +//! +//! For other compilers returns true if T is convertible to boost::interprocess::rv& +template +class is_movable +{ + public: + static const bool value = move_detail::is_convertible::value; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +//! This function provides a way to convert a reference into a rvalue reference +//! in compilers with rvalue reference. For other compilers converts T & into +//! boost::interprocess::rv & so that move emulation is activated. +template inline +rvalue_reference move (input_reference); +#else +template inline +typename remove_reference::type&& move(T&& t) { return t; } +#endif -template -inline T&& forward_impl(typename detail::identity::type&& t) +////////////////////////////////////////////////////////////////////////////// +// +// forward +// +////////////////////////////////////////////////////////////////////////////// + + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +//! This function provides limited form of forwarding that is usually enough for +//! in-place construction and avoids the exponential overloading necessary for +//! perfect forwarding in C++03. +//! +//! For compilers with rvalue references this function provides perfect forwarding. +//! +//! Otherwise: +//! * If input_reference binds to const boost::interprocess::rv & then it output_reference is +//! boost::rev & +//! +//! * Else, input_reference is equal to output_reference is equal to input_reference. +template inline output_reference forward(input_reference); +#else +template inline +T&& forward (typename move_detail::identity::type&& t) { return t; } +#endif -} //namespace detail { +////////////////////////////////////////////////////////////////////////////// +// +// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION +// +////////////////////////////////////////////////////////////////////////////// -template -inline typename detail::remove_reference::type&& move(T&& t) -{ return t; } +//! This macro expands to nothing for compilers with rvalue references. +//! Otherwise expands to: +//! \code +//! operator boost::interprocess::rv&() +//! { return static_cast& >(*this); } +//! \endcode +#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ +// + +#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ + TYPE && \ +// + +#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ + TYPE && \ +// + +//! This macro expands to T&& for compilers with rvalue references. +//! Otherwise expands to boost::interprocess::rv &. +#define BOOST_INTERPROCESS_RV_REF(TYPE)\ + TYPE && \ +// + +//! This macro expands to T&& for compilers with rvalue references. +//! Otherwise expands to const T &. +#define BOOST_INTERPROCESS_FWD_REF(TYPE)\ + TYPE && \ +// } //namespace interprocess { } //namespace boost { -#endif //#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#endif //BOOST_HAS_RVALUE_REFS -#include +namespace boost { +namespace interprocess { -#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP +////////////////////////////////////////////////////////////////////////////// +// +// move_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! Class template move_iterator is an iterator adaptor with the same behavior +//! as the underlying iterator except that its dereference operator implicitly +//! converts the value returned by the underlying iterator's dereference operator +//! to an rvalue reference. Some generic algorithms can be called with move +//! iterators to replace copying with moving. +template +class move_iterator +{ + public: + typedef It iterator_type; + typedef typename std::iterator_traits::value_type value_type; + #if defined(BOOST_HAS_RVALUE_REFS) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + typedef value_type && reference; + #else + typedef typename boost::mpl::if_ + < boost::interprocess::is_movable + , boost::interprocess::rv& + , value_type & >::type reference; + #endif + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::iterator_category iterator_category; + + move_iterator() + {} + + explicit move_iterator(It i) + : m_it(i) + {} + + template + move_iterator(const move_iterator& u) + : m_it(u.base()) + {} + + iterator_type base() const + { return m_it; } + + reference operator*() const + { + #if defined(BOOST_HAS_RVALUE_REFS) + return *m_it; + #else + return boost::interprocess::move(*m_it); + #endif + } + + pointer operator->() const + { return m_it; } + + move_iterator& operator++() + { ++m_it; return *this; } + + move_iterator operator++(int) + { move_iterator tmp(*this); ++(*this); return tmp; } + + move_iterator& operator--() + { --m_it; return *this; } + + move_iterator operator--(int) + { move_iterator tmp(*this); --(*this); return tmp; } + + move_iterator operator+ (difference_type n) const + { return move_iterator(m_it + n); } + + move_iterator& operator+=(difference_type n) + { m_it += n; return *this; } + + move_iterator operator- (difference_type n) const + { return move_iterator(m_it - n); } + + move_iterator& operator-=(difference_type n) + { m_it -= n; return *this; } + + reference operator[](difference_type n) const + { + #if defined(BOOST_HAS_RVALUE_REFS) + return m_it[n]; + #else + return boost::interprocess::move(m_it[n]); + #endif + } + + friend bool operator==(const move_iterator& x, const move_iterator& y) + { return x.base() == y.base(); } + + friend bool operator!=(const move_iterator& x, const move_iterator& y) + { return x.base() != y.base(); } + + friend bool operator< (const move_iterator& x, const move_iterator& y) + { return x.base() < y.base(); } + + friend bool operator<=(const move_iterator& x, const move_iterator& y) + { return x.base() <= y.base(); } + + friend bool operator> (const move_iterator& x, const move_iterator& y) + { return x.base() > y.base(); } + + friend bool operator>=(const move_iterator& x, const move_iterator& y) + { return x.base() >= y.base(); } + + friend difference_type operator-(const move_iterator& x, const move_iterator& y) + { return x.base() - y.base(); } + + friend move_iterator operator+(difference_type n, const move_iterator& x) + { return move_iterator(x.base() + n); } + + private: + It m_it; +}; + + +//is_move_iterator +namespace move_detail { + +template +struct is_move_iterator +{ + static const bool value = false; +}; + +template +struct is_move_iterator< ::boost::interprocess::move_iterator > +{ + static const bool value = true; +}; + +} //namespace move_detail { + +////////////////////////////////////////////////////////////////////////////// +// +// move_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! +//! Returns: move_iterator(i). +template +move_iterator make_move_iterator(const It &it) +{ return move_iterator(it); } + +////////////////////////////////////////////////////////////////////////////// +// +// back_move_insert_iterator +// +////////////////////////////////////////////////////////////////////////////// + + +//! A move insert iterator that move constructs elements at the +//! back of a container +template // C models Container +class back_move_insert_iterator + : public std::iterator +{ + C* container_m; + + public: + typedef C container_type; + + explicit back_move_insert_iterator(C& x) : container_m(&x) { } + + back_move_insert_iterator& operator=(typename C::reference x) + { container_m->push_back(boost::interprocess::move(x)); return *this; } + + back_move_insert_iterator& operator*() { return *this; } + back_move_insert_iterator& operator++() { return *this; } + back_move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: back_move_insert_iterator(x). +template // C models Container +inline back_move_insert_iterator back_move_inserter(C& x) +{ + return back_move_insert_iterator(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// front_move_insert_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! A move insert iterator that move constructs elements int the +//! front of a container +template // C models Container +class front_move_insert_iterator + : public std::iterator +{ + C* container_m; + +public: + typedef C container_type; + + explicit front_move_insert_iterator(C& x) : container_m(&x) { } + + front_move_insert_iterator& operator=(typename C::reference x) + { container_m->push_front(boost::interprocess::move(x)); return *this; } + + front_move_insert_iterator& operator*() { return *this; } + front_move_insert_iterator& operator++() { return *this; } + front_move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: front_move_insert_iterator(x). +template // C models Container +inline front_move_insert_iterator front_move_inserter(C& x) +{ + return front_move_insert_iterator(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// insert_move_iterator +// +////////////////////////////////////////////////////////////////////////////// +template // C models Container +class move_insert_iterator + : public std::iterator +{ + C* container_m; + typename C::iterator pos_; + + public: + typedef C container_type; + + explicit move_insert_iterator(C& x, typename C::iterator pos) + : container_m(&x), pos_(pos) + {} + + move_insert_iterator& operator=(typename C::reference x) + { + pos_ = container_m->insert(pos_, boost::interprocess::move(x)); + ++pos_; + return *this; + } + + move_insert_iterator& operator*() { return *this; } + move_insert_iterator& operator++() { return *this; } + move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: move_insert_iterator(x, it). +template // C models Container +inline move_insert_iterator move_inserter(C& x, typename C::iterator it) +{ + return move_insert_iterator(x, it); +} + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + + +//! Effects: Moves elements in the range [first,last) into the range [result,result + (last - +//! first)) starting from first and proceeding to last. For each non-negative integer n < (last-first), +//! performs *(result + n) = boost::interprocess::move (*(first + n)). +//! +//! Effects: result + (last - first). +//! +//! Requires: result shall not be in the range [first,last). +//! +//! Complexity: Exactly last - first move assignments. +template // O models OutputIterator +O move(I f, I l, O result) +{ + while (f != l) { + *result = boost::interprocess::move(*f); + ++f; ++result; + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// +// move_backward +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: Moves elements in the range [first,last) into the range +//! [result - (last-first),result) starting from last - 1 and proceeding to +//! first. For each positive integer n <= (last - first), +//! performs *(result - n) = boost::interprocess::move(*(last - n)). +//! +//! Requires: result shall not be in the range [first,last). +//! +//! Returns: result - (last - first). +//! +//! Complexity: Exactly last - first assignments. +template // O models BidirectionalIterator +O move_backward(I f, I l, O result) +{ + while (f != l) { + --l; --result; + *result = boost::interprocess::move(*l); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_move +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: +//! \code +//! for (; first != last; ++result, ++first) +//! new (static_cast(&*result)) +//! typename iterator_traits::value_type(boost::interprocess::move(*first)); +//! \endcode +//! +//! Returns: result +template + // F models ForwardIterator +F uninitialized_move(I f, I l, F r + /// @cond + ,typename enable_if::value_type> >::type* = 0 + /// @endcond + ) +{ + typedef typename std::iterator_traits::value_type input_value_type; + while (f != l) { + ::new(static_cast(&*r)) input_value_type(boost::interprocess::move(*f)); + ++f; ++r; + } + return r; +} + +/// @cond + +template + // F models ForwardIterator +F uninitialized_move(I f, I l, F r, + typename disable_if::value_type> >::type* = 0) +{ + return std::uninitialized_copy(f, l, r); +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_copy_or_move +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { + +template + // F models ForwardIterator +F uninitialized_move_move_iterator(I f, I l, F r, + typename enable_if< is_movable >::type* = 0) +{ + return boost::interprocess::uninitialized_move(f, l, r); +} + +template + // F models ForwardIterator +F uninitialized_move_move_iterator(I f, I l, F r, + typename disable_if< is_movable >::type* = 0) +{ + return std::uninitialized_copy(f.base(), l.base(), r); +} + +} //namespace move_detail { + +template + // F models ForwardIterator +F uninitialized_copy_or_move(I f, I l, F r, + typename enable_if< move_detail::is_move_iterator >::type* = 0) +{ + return boost::interprocess::move_detail::uninitialized_move_move_iterator(f, l, r); +} + +/// @endcond + +//! Effects: +//! \code +//! for (; first != last; ++result, ++first) +//! new (static_cast(&*result)) +//! typename iterator_traits::value_type(*first); +//! \endcode +//! +//! Returns: result +//! +//! Note: This function is provided because +//! std::uninitialized_copy from some STL implementations +//! is not compatible with move_iterator +template + // F models ForwardIterator +F uninitialized_copy_or_move(I f, I l, F r + /// @cond + ,typename disable_if< move_detail::is_move_iterator >::type* = 0 + /// @endcond + ) +{ + return std::uninitialized_copy(f, l, r); +} + +///has_trivial_destructor_after_move<> == true_type +///specialization for optimizations +template +struct has_trivial_destructor_after_move + : public boost::has_trivial_destructor +{}; + +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP diff --git a/include/boost/interprocess/detail/move_iterator.hpp b/include/boost/interprocess/detail/move_iterator.hpp deleted file mode 100644 index 4c9f282..0000000 --- a/include/boost/interprocess/detail/move_iterator.hpp +++ /dev/null @@ -1,138 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/interprocess for documentation. -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED -#define BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED - -#include -#include - -namespace boost{ -namespace interprocess{ -namespace detail{ - -template -class move_iterator -{ - public: - typedef It iterator_type; - typedef typename std::iterator_traits::value_type value_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef typename move_type::type reference; - #else - typedef value_type && reference; - #endif - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::iterator_category iterator_category; - - move_iterator() - {} - - explicit move_iterator(It i) - : m_it(i) - {} - - template - move_iterator(const move_iterator& u) - : m_it(u.base()) - {} - - const iterator_type &base() const - { return m_it; } - - iterator_type &base() - { return m_it; } - - reference operator*() const - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - { return detail::move_impl(*m_it); } - #else - { return *m_it; } - #endif - - pointer operator->() const - { return m_it; } - - move_iterator& operator++() - { ++m_it; return *this; } - - move_iterator operator++(int) - { move_iterator tmp(*this); ++(*this); return tmp; } - - move_iterator& operator--() - { --m_it; return *this; } - - move_iterator operator--(int) - { move_iterator tmp(*this); --(*this); return tmp; } - - move_iterator operator+ (difference_type n) const - { return move_iterator(m_it + n); } - - move_iterator& operator+=(difference_type n) - { m_it += n; return *this; } - - move_iterator operator- (difference_type n) const - { return move_iterator(m_it - n); } - - move_iterator& operator-=(difference_type n) - { m_it -= n; return *this; } - - reference operator[](difference_type n) const - { return detail::move_impl(m_it[n]); } - - private: - It m_it; -}; - -template inline -bool operator==(const move_iterator& x, const move_iterator& y) -{ return x.base() == y.base(); } - -template inline -bool operator!=(const move_iterator& x, const move_iterator& y) -{ return x.base() != y.base(); } - -template inline -bool operator< (const move_iterator& x, const move_iterator& y) -{ return x.base() < y.base(); } - -template inline -bool operator<=(const move_iterator& x, const move_iterator& y) -{ return x.base() <= y.base(); } - -template inline -bool operator> (const move_iterator& x, const move_iterator& y) -{ return x.base() > y.base(); } - -template inline -bool operator>=(const move_iterator& x, const move_iterator& y) -{ return x.base() >= y.base(); } - -template inline -typename move_iterator::difference_type - operator-(const move_iterator& x, const move_iterator& y) -{ return x.base() - y.base(); } - -template inline -move_iterator - operator+(typename move_iterator::difference_type n - ,const move_iterator& x) -{ return move_iterator(x.base() + n); } - -template -move_iterator make_move_iterator(const It &it) -{ return move_iterator(it); } - -} //namespace detail{ -} //namespace interprocess{ -} //namespace boost{ - -#endif //#ifndef BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index dfdd38c..364a54d 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -59,6 +59,9 @@ struct enable_if_c {}; template struct enable_if : public enable_if_c {}; +template +struct disable_if : public enable_if_c {}; + template class is_convertible { @@ -105,7 +108,8 @@ template struct select1st // : public std::unary_function { - const typename Pair::first_type& operator()(const Pair& x) const + template + const typename Pair::first_type& operator()(const OtherPair& x) const { return x.first; } const typename Pair::first_type& operator()(const typename Pair::first_type& x) const diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index b4df4da..b16cf1d 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -72,11 +72,11 @@ struct CtorNArg : public placement_destroy private: template void construct(void *mem, detail::true_, const index_tuple&) - { new((void*)mem)T(*detail::forward_impl(get(args_))...); } + { new((void*)mem)T(*boost::interprocess::forward(get(args_))...); } template void construct(void *mem, detail::false_, const index_tuple&) - { new((void*)mem)T(detail::forward_impl(get(args_))...); } + { new((void*)mem)T(boost::interprocess::forward(get(args_))...); } template void do_increment(detail::true_, const index_tuple&) @@ -120,7 +120,7 @@ class named_proxy template T *operator()(Args &&...args) const { - CtorNArg ctor_obj(detail::forward_impl(args)...); + CtorNArg ctor_obj(boost::interprocess::forward(args)...); return mp_mngr->template generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); } @@ -211,7 +211,7 @@ struct Ctor0Arg : public placement_destroy //be able to bind temporaries. After that we will un-const them. //This cast is ugly but it is necessary until "perfect forwarding" //is achieved in C++0x. Meanwhile, if we want to be able to -//bind rvalues with non-const references, we have to be ugly +//bind lvalues with non-const references, we have to be ugly #define BOOST_PP_LOCAL_MACRO(n) \ template \ struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp index 83f8c7e..78bbe96 100644 --- a/include/boost/interprocess/detail/os_file_functions.hpp +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -13,9 +13,9 @@ #include #include -//#include +#include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -35,11 +35,11 @@ namespace boost { namespace interprocess { -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) typedef void * file_handle_t; typedef long long offset_t; -typedef struct{ +typedef struct mapping_handle_impl_t{ void * handle; bool is_shm; } mapping_handle_t; @@ -65,6 +65,14 @@ inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) return ret; } +inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = true; + return ret; +} + inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) { return hnd.handle; } @@ -99,10 +107,7 @@ inline file_handle_t open_existing_file } inline bool delete_file(const char *name) -{ return winapi::delete_file(name); } - -inline bool delete_file_on_reboot_if_possible(const char *filename) -{ return winapi::move_file_ex(filename, 0, winapi::movefile_delay_until_reboot); } +{ return winapi::unlink_file(name); } inline bool truncate_file (file_handle_t hnd, std::size_t size) { @@ -191,16 +196,89 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) return (acquired = true); } - - inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +inline bool delete_subdirectories_recursive + (const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count) +{ + bool bSubdirectory = false; // Flag, indicating whether + // subdirectories have been found + void * hFile; // Handle to directory + std::string strFilePath; // Filepath + std::string strPattern; // Pattern + winapi::win32_find_data_t FileInformation; // File information + + //Find all files and directories + strPattern = refcstrRootDirectory + "\\*.*"; + hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation); + if(hFile != winapi::invalid_handle_value){ + do{ + //If it's not "." or ".." or the pointed root_level dont_delete_this erase it + if(FileInformation.cFileName[0] != '.' && + !(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){ + strFilePath.erase(); + strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName; + + //If it's a directory, go recursive + if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){ + // Delete subdirectory + if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1)) + return false; + } + //If it's a file, just delete it + else{ + // Set file attributes + //if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0) + //return winapi::get_last_error(); + // Delete file + if(winapi::delete_file(strFilePath.c_str()) == 0) + return false; + } + } + //Go to the next file + } while(winapi::find_next_file(hFile, &FileInformation) == 1); + + // Close handle + winapi::find_close(hFile); + + //See if the loop has ended with an error or just because we've traversed all the files + if(winapi::get_last_error() != winapi::error_no_more_files){ + return false; + } + else + { + //Erase empty subdirectories or original refcstrRootDirectory + if(!bSubdirectory && count) + { + // Set directory attributes + //if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0) + //return ::GetLastError(); + // Delete directory + if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0) + return false; + } + } + } + return true; +} + +//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this" +inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this) +{ + return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u); +} + +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) typedef int file_handle_t; typedef off_t offset_t; -typedef file_handle_t mapping_handle_t; + +typedef struct mapping_handle_impl_t +{ + file_handle_t handle; + bool is_xsi; +} mapping_handle_t; typedef enum { read_only = O_RDONLY , read_write = O_RDWR @@ -216,10 +294,15 @@ typedef enum { file_begin = SEEK_SET namespace detail{ inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) -{ return hnd; } +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_xsi = false; + return ret; +} inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) -{ return hnd; } +{ return hnd.handle; } inline bool create_directory(const char *path) { return ::mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0; } @@ -263,12 +346,6 @@ inline file_handle_t open_existing_file inline bool delete_file(const char *name) { return ::unlink(name) == 0; } - -inline bool delete_file_on_reboot_if_possible(const char *) -{ //Function not implemented in POSIX functions - return false; -} - inline bool truncate_file (file_handle_t hnd, std::size_t size) { return 0 == ::ftruncate(hnd, size); } @@ -365,7 +442,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) } //namespace detail{ } //namespace interprocess { diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp index eee090e..4d2e3dd 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -14,7 +14,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -30,7 +30,7 @@ namespace boost { namespace interprocess { namespace detail{ -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) typedef unsigned long OS_process_id_t; typedef unsigned long OS_thread_id_t; @@ -40,6 +40,9 @@ typedef OS_thread_id_t OS_systemwide_thread_id_t; inline OS_process_id_t get_current_process_id() { return winapi::get_current_process_id(); } +inline OS_process_id_t get_invalid_process_id() +{ return OS_process_id_t(0); } + //thread inline OS_thread_id_t get_current_thread_id() { return winapi::get_current_thread_id(); } @@ -59,6 +62,12 @@ inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() return get_current_thread_id(); } +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to = from; +} + inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) { return equal_thread_id(id1, id2); @@ -69,24 +78,56 @@ inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() return get_invalid_thread_id(); } -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) typedef pthread_t OS_thread_id_t; typedef pid_t OS_process_id_t; struct OS_systemwide_thread_id_t { + OS_systemwide_thread_id_t() + : pid(), tid() + {} + OS_systemwide_thread_id_t(pid_t p, pthread_t t) : pid(p), tid(t) {} + + OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + void operator=(const OS_systemwide_thread_id_t &x) volatile + { pid = x.pid; tid = x.tid; } + pid_t pid; pthread_t tid; }; +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to.pid = from.pid; + to.tid = from.tid; +} + //process inline OS_process_id_t get_current_process_id() { return ::getpid(); } +inline OS_process_id_t get_invalid_process_id() +{ return pid_t(0); } + //thread inline OS_thread_id_t get_current_thread_id() { return ::pthread_self(); } @@ -116,10 +157,10 @@ inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, con inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() { - return OS_systemwide_thread_id_t(pid_t(0), get_invalid_thread_id()); + return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id()); } -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) } //namespace detail{ } //namespace interprocess { diff --git a/include/boost/interprocess/detail/preprocessor.hpp b/include/boost/interprocess/detail/preprocessor.hpp index 45afb67..b7cb8fd 100644 --- a/include/boost/interprocess/detail/preprocessor.hpp +++ b/include/boost/interprocess/detail/preprocessor.hpp @@ -36,7 +36,7 @@ //This cast is ugly but it is necessary until "perfect forwarding" //is achieved in C++0x. Meanwhile, if we want to be able to //bind rvalues with non-const references, we have to be ugly -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ //! @@ -46,7 +46,7 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_PARAM(U, u) \ U && u \ //! @@ -56,7 +56,7 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \ BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ //! @@ -70,7 +70,7 @@ BOOST_PP_CAT(++m_p, n) \ //! -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \ BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ //! @@ -80,25 +80,13 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ - detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ - //! -#else - #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ - BOOST_PP_CAT(p, n) \ - //! -#endif +#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ - detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ - //! -#else - #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ - BOOST_PP_CAT(m_p, n) \ - //! -#endif +#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! #define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ BOOST_PP_CAT(*m_p, n) \ diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index ffbe9fb..0301dfe 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -27,6 +29,8 @@ #include //char_traits #include //std::nothrow #include //std::pair +#include //assert +#include //unary_function #ifndef BOOST_NO_EXCEPTIONS #include #endif @@ -75,7 +79,7 @@ struct block_header block_header(std::size_t value_bytes ,std::size_t value_alignment - ,std::size_t allocation_type + ,std::size_t alloc_type ,std::size_t sizeof_char ,std::size_t num_char ) @@ -83,7 +87,7 @@ struct block_header , m_num_char(num_char) , m_value_alignment(value_alignment) , m_alloc_type_sizeof_char - ( ((unsigned char)allocation_type << 5u) | + ( ((unsigned char)alloc_type << 5u) | ((unsigned char)sizeof_char & 0x1F) ) {}; @@ -94,7 +98,7 @@ struct block_header std::size_t total_size() const { - if(allocation_type() != anonymous_type){ + if(alloc_type() != anonymous_type){ return name_offset() + (m_num_char+1)*sizeof_char(); } else{ @@ -114,7 +118,7 @@ struct block_header + total_size(); } - std::size_t allocation_type() const + std::size_t alloc_type() const { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; } std::size_t sizeof_char() const @@ -252,6 +256,7 @@ struct char_if_void typedef instance_t anonymous_instance_t; typedef instance_t unique_instance_t; + template struct intrusive_value_type_impl : public Hook @@ -325,7 +330,7 @@ class char_ptr_holder template struct index_key { - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_char_ptr_t; typedef CharT char_type; @@ -471,6 +476,26 @@ struct segment_manager_iterator_transform } //namespace detail { +//These pointers are the ones the user will use to +//indicate previous allocation types +static const detail::anonymous_instance_t * anonymous_instance = 0; +static const detail::unique_instance_t * unique_instance = 0; + +namespace detail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)anonymous_instance; + (void)unique_instance; + } +}; + +} //detail_really_deep_namespace + }} //namespace boost { namespace interprocess #include diff --git a/include/boost/interprocess/detail/tmp_dir_helpers.hpp b/include/boost/interprocess/detail/tmp_dir_helpers.hpp index 34db635..2c0ccc5 100644 --- a/include/boost/interprocess/detail/tmp_dir_helpers.hpp +++ b/include/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -18,10 +18,87 @@ #include #include +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#endif + namespace boost { namespace interprocess { namespace detail { +#if (defined BOOST_INTERPROCESS_WINDOWS) + +inline void tmp_filename(const char *filename, std::string &tmp_name) +{ + const char *tmp_dir = get_temporary_path(); + if(!tmp_dir){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + tmp_name = tmp_dir; + + //Remove final null. + tmp_name += "/boost_interprocess/"; + + char bootstamp[winapi::BootstampLength*2+1]; + std::size_t bootstamp_length = winapi::BootstampLength*2; + winapi::get_boot_time_str(bootstamp, bootstamp_length); + bootstamp[winapi::BootstampLength*2] = 0; + tmp_name += bootstamp; + tmp_name += '/'; + tmp_name += filename; +} + +inline void create_tmp_dir_and_get_filename(const char *filename, std::string &tmp_name) +{ + //First get the temp directory + const char *tmp_path = get_temporary_path(); + if(!tmp_path){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + //Create Boost.Interprocess dir + tmp_name = tmp_path; + tmp_name += "/boost_interprocess"; + + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + //Obtain bootstamp string + char bootstamp[winapi::BootstampLength*2+1]; + std::size_t bootstamp_length = winapi::BootstampLength*2; + winapi::get_boot_time_str(bootstamp, bootstamp_length); + bootstamp[winapi::BootstampLength*2] = 0; + + //Create a new subdirectory with the bootstamp + std::string root_tmp_name = tmp_name; + tmp_name += '/'; + tmp_name += bootstamp; + + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + //Now erase all old directories created in the previous boot sessions + delete_subdirectories(root_tmp_name, bootstamp); + + //Add filename + tmp_name += '/'; + tmp_name += filename; +} + +#else //POSIX SYSTEMS + inline void tmp_filename(const char *filename, std::string &tmp_name) { const char *tmp_dir = get_temporary_path(); @@ -61,6 +138,8 @@ inline void create_tmp_dir_and_get_filename(const char *filename, std::string &t tmp_name += filename; } +#endif + inline void add_leading_slash(const char *name, std::string &new_name) { if(name[0] != '/'){ diff --git a/include/boost/interprocess/detail/transform_iterator.hpp b/include/boost/interprocess/detail/transform_iterator.hpp new file mode 100644 index 0000000..eb081c2 --- /dev/null +++ b/include/boost/interprocess/detail/transform_iterator.hpp @@ -0,0 +1,180 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// 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_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include + +namespace boost { +namespace interprocess { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + +/* + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } +*/ + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + diff --git a/include/boost/interprocess/detail/type_traits.hpp b/include/boost/interprocess/detail/type_traits.hpp index 44066b7..d4ee029 100644 --- a/include/boost/interprocess/detail/type_traits.hpp +++ b/include/boost/interprocess/detail/type_traits.hpp @@ -120,13 +120,13 @@ struct add_reference template<> struct add_reference { - typedef nat& type; + typedef nat &type; }; template<> struct add_reference { - typedef const nat& type; + typedef const nat &type; }; template diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index a96215e..166cf2e 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -26,11 +26,10 @@ #include #include #include -#include -#include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include -#endif +#include +#include +#include +#include #include #include @@ -70,321 +69,6 @@ inline void do_swap(T& x, T& y) swap(x, y); } -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template -struct scoped_ptr_dealloc_functor -{ - typedef typename Allocator::pointer pointer; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - - private: - void priv_deallocate(const typename Allocator::pointer &p, allocator_v1) - { m_alloc.deallocate(p, 1); } - - void priv_deallocate(const typename Allocator::pointer &p, allocator_v2) - { m_alloc.deallocate_one(p); } - - public: - Allocator& m_alloc; - - scoped_ptr_dealloc_functor(Allocator& a) - : m_alloc(a) {} - - void operator()(pointer ptr) - { if (ptr) priv_deallocate(ptr, alloc_version()); } -}; - -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template -struct scoped_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - - private: - void priv_deallocate(allocator_v1) - { m_alloc.deallocate(m_ptr, 1); } - - void priv_deallocate(allocator_v2) - { m_alloc.deallocate_one(m_ptr); } - - scoped_deallocator(const scoped_deallocator &); - scoped_deallocator& operator=(const scoped_deallocator &); - - public: - pointer m_ptr; - Allocator& m_alloc; - - scoped_deallocator(pointer p, Allocator& a) - : m_ptr(p), m_alloc(a) {} - - ~scoped_deallocator() - { if (m_ptr)priv_deallocate(alloc_version()); } - - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_deallocator(scoped_deallocator &&o) - : m_ptr(o.m_ptr), m_alloc(o.m_alloc) - { - #else - scoped_deallocator(moved_object mo) - : m_ptr(mo.get().m_ptr), m_alloc(mo.get().m_alloc) - { - scoped_deallocator &o = mo.get(); - #endif - o.release(); - } - - pointer get() const - { return m_ptr; } - - void release() - { m_ptr = 0; } -}; - -} //namespace detail { - -template -struct is_movable > -{ - static const bool value = true; -}; - -namespace detail { - -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an array of objects using a STL allocator. -template -struct scoped_array_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::size_type size_type; - - scoped_array_deallocator(pointer p, Allocator& a, size_type length) - : m_ptr(p), m_alloc(a), m_length(length) {} - - ~scoped_array_deallocator() - { if (m_ptr) m_alloc.deallocate(m_ptr, m_length); } - - void release() - { m_ptr = 0; } - - private: - pointer m_ptr; - Allocator& m_alloc; - size_type m_length; -}; - -template -struct null_scoped_array_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::size_type size_type; - - null_scoped_array_deallocator(pointer, Allocator&, size_type) - {} - - void release() - {} -}; - -//!A deleter for scoped_ptr that destroys -//!an object using a STL allocator. -template -struct scoped_destructor_n -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::value_type value_type; - typedef typename Allocator::size_type size_type; - - pointer m_p; - size_type m_n; - - scoped_destructor_n(pointer p, size_type n) - : m_p(p), m_n(n) - {} - - void release() - { m_p = 0; } - - void increment_size(size_type inc) - { m_n += inc; } - - ~scoped_destructor_n() - { - if(!m_p) return; - value_type *raw_ptr = detail::get_pointer(m_p); - for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr) - raw_ptr->~value_type(); - } -}; - -//!A deleter for scoped_ptr that destroys -//!an object using a STL allocator. -template -struct null_scoped_destructor_n -{ - typedef typename Allocator::pointer pointer; - typedef typename Allocator::size_type size_type; - - null_scoped_destructor_n(pointer, size_type) - {} - - void increment_size(size_type) - {} - - void release() - {} -}; - -template -class allocator_destroyer -{ - typedef typename A::value_type value_type; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - - private: - A & a_; - - private: - void priv_deallocate(const typename A::pointer &p, allocator_v1) - { a_.deallocate(p, 1); } - - void priv_deallocate(const typename A::pointer &p, allocator_v2) - { a_.deallocate_one(p); } - - public: - allocator_destroyer(A &a) - : a_(a) - {} - - void operator()(const typename A::pointer &p) - { - detail::get_pointer(p)->~value_type(); - priv_deallocate(p, alloc_version()); - } -}; - -template -class allocator_destroyer_and_chain_builder -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - - A & a_; - multiallocation_chain &c_; - - public: - allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) - : a_(a), c_(c) - {} - - void operator()(const typename A::pointer &p) - { - value_type *vp = detail::get_pointer(p); - vp->~value_type(); - c_.push_back(vp); - } -}; - -template -class allocator_multialloc_chain_node_deallocator -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_node_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_node_deallocator() - { - multiallocation_iterator it(c_.get_it()); - if(it != multiallocation_iterator()) - a_.deallocate_individual(it); - } -}; - -template -class allocator_multialloc_chain_array_deallocator -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_array_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_array_deallocator() - { - multiallocation_iterator it(c_.get_it()); - if(it != multiallocation_iterator()) - a_.deallocate_many(it); - } -}; - -//!A class used for exception-safe multi-allocation + construction. -template -struct multiallocation_destroy_dealloc -{ - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; - typedef typename Allocator::value_type value_type; - - multiallocation_iterator m_itbeg; - Allocator& m_alloc; - - multiallocation_destroy_dealloc(multiallocation_iterator itbeg, Allocator& a) - : m_itbeg(itbeg), m_alloc(a) {} - - ~multiallocation_destroy_dealloc() - { - multiallocation_iterator endit; - while(m_itbeg != endit){ - detail::get_pointer(&*m_itbeg)->~value_type(); - m_alloc.deallocate(&*m_itbeg, 1); - ++m_itbeg; - } - } - - void next() - { ++m_itbeg; } - - void release() - { m_itbeg = multiallocation_iterator(); } -}; - //Rounds "orig_size" by excess to round_to bytes inline std::size_t get_rounded_size(std::size_t orig_size, std::size_t round_to) { @@ -415,18 +99,6 @@ struct ct_rounded_size enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; }; -template -struct ct_min -{ - enum { value = (Value1 < Value2)? Value1 : Value2 }; -}; - -template -struct ct_max -{ - enum { value = (Value1 > Value2)? Value1 : Value2 }; -}; - // Gennaro Prota wrote this. Thanks! template struct ct_max_pow2_less @@ -443,38 +115,6 @@ struct ct_max_pow2_less<0, 0> static const std::size_t value = 0; }; -//!Obtains a generic pointer of the same type that -//!can point to other pointed type: Ptr -> Ptr -template -struct pointer_to_other; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template -struct pointer_to_other< T*, U > -{ - typedef U* type; -}; - } //namespace detail { //!Trait class to detect if an index is a node @@ -486,7 +126,6 @@ struct is_node_index enum { value = false }; }; - //!Trait class to detect if an index is an intrusive //!index. This will embed the derivation hook in each //!allocation header, to provide memory for the intrusive @@ -497,334 +136,6 @@ struct is_intrusive_index enum { value = false }; }; -template -SizeType - get_next_capacity(const SizeType max_size - ,const SizeType capacity - ,const SizeType n) -{ -// if (n > max_size - capacity) -// throw std::length_error("get_next_capacity"); - - const SizeType m3 = max_size/3; - - if (capacity < m3) - return capacity + max_value(3*(capacity+1)/5, n); - - if (capacity < m3*2) - return capacity + max_value((capacity+1)/2, n); - - return max_size; -} - -namespace detail { - -template -struct pair -{ - typedef T1 first_type; - typedef T2 second_type; - - T1 first; - T2 second; - - //std::pair compatibility - template - pair(const std::pair& p) - : first(p.first), second(p.second) - {} - - //To resolve ambiguity with the variadic constructor of 1 argument - //and the previous constructor - pair(std::pair& x) - : first(x.first), second(x.second) - {} - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - template - pair(std::pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - pair() - : first(), second() - {} - - pair(const pair& x) - : first(x.first), second(x.second) - {} - - //To resolve ambiguity with the variadic constructor of 1 argument - //and the copy constructor - pair(pair& x) - : first(x.first), second(x.second) - {} - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - pair(pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - template - pair(pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - pair(U &&u, Args &&... args) - : first(detail::forward_impl(u)) - , second(detail::forward_impl(args)...) - {} - - #else - - template - pair(BOOST_INTERPROCESS_PARAM(U, u)) - : first(detail::forward_impl(u)) - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - pair(BOOST_INTERPROCESS_PARAM(U, u) \ - ,BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : first(detail::forward_impl(u)) \ - , second(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ - {} \ - //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) - #include BOOST_PP_LOCAL_ITERATE() - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - pair& operator=(pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - pair& operator=(std::pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - template - pair& operator=(std::pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object p) - { std::swap(*this, p.get()); } - - void swap(pair& p) - { std::swap(*this, p); } - - #else - void swap(pair &&p) - { std::swap(*this, p); } - #endif -}; - -template -inline bool operator==(const pair& x, const pair& y) -{ return static_cast(x.first == y.first && x.second == y.second); } - -template -inline bool operator< (const pair& x, const pair& y) -{ return static_cast(x.first < y.first || - (!(y.first < x.first) && x.second < y.second)); } - -template -inline bool operator!=(const pair& x, const pair& y) -{ return static_cast(!(x == y)); } - -template -inline bool operator> (const pair& x, const pair& y) -{ return y < x; } - -template -inline bool operator>=(const pair& x, const pair& y) -{ return static_cast(!(x < y)); } - -template -inline bool operator<=(const pair& x, const pair& y) -{ return static_cast(!(y < x)); } - -template -inline pair make_pair(T1 x, T2 y) -{ return pair(x, y); } - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline void swap(detail::moved_object > &x, pair y) -{ - swap(x.get().first, y.first); - swap(x.get().second, y.second); -} - -template -inline void swap(pair& x, detail::moved_object > y) -{ - swap(x.first, y.get().first); - swap(x.second, y.get().second); -} - -template -inline void swap(pair& x, pair& y) -{ - swap(x.first, y.first); - swap(x.second, y.second); -} - -#else -template -inline void swap(pair&&x, pair&&y) -{ - swap(x.first, y.first); - swap(x.second, y.second); -} -#endif - -template -struct cast_functor -{ - typedef typename detail::add_reference::type result_type; - result_type operator()(char &ptr) const - { return *static_cast(static_cast(&ptr)); } -}; - -template -class multiallocation_chain_adaptor -{ - private: - MultiallocChain chain_; - - multiallocation_chain_adaptor - (const multiallocation_chain_adaptor &); - multiallocation_chain_adaptor &operator= - (const multiallocation_chain_adaptor &); - - public: - typedef transform_iterator - < typename MultiallocChain:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - - multiallocation_chain_adaptor() - : chain_() - {} - - void push_back(T *mem) - { chain_.push_back(mem); } - - void push_front(T *mem) - { chain_.push_front(mem); } - - void swap(multiallocation_chain_adaptor &other_chain) - { chain_.swap(other_chain.chain_); } - - void splice_back(multiallocation_chain_adaptor &other_chain) - { chain_.splice_back(other_chain.chain_); } - - T *pop_front() - { return static_cast(chain_.pop_front()); } - - bool empty() const - { return chain_.empty(); } - - multiallocation_iterator get_it() const - { return multiallocation_iterator(chain_.get_it()); } - - std::size_t size() const - { return chain_.size(); } -}; - -template -struct value_init -{ - value_init() - : m_t() - {} - - T m_t; -}; - -} //namespace detail { - -//!The pair is movable if any of its members is movable -template -struct is_movable > -{ - enum { value = is_movable::value || is_movable::value }; -}; - -//!The pair is movable if any of its members is movable -template -struct is_movable > -{ - enum { value = is_movable::value || is_movable::value }; -}; - -///has_trivial_destructor_after_move<> == true_type -///specialization for optimizations -template -struct has_trivial_destructor_after_move - : public boost::has_trivial_destructor -{}; - template T* addressof(T& v) { @@ -850,36 +161,6 @@ class value_eraser 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 fa26ee9..cfe0afc 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -14,13 +14,15 @@ #include #include #include +#include +#include #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once # pragma comment( lib, "advapi32.lib" ) #endif -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include # include #else @@ -37,6 +39,7 @@ namespace winapi { static const unsigned long infinite_time = 0xFFFFFFFF; static const unsigned long error_already_exists = 183L; static const unsigned long error_file_not_found = 2u; +static const unsigned long error_no_more_files = 18u; static const unsigned long semaphore_all_access = (0x000F0000L)|(0x00100000L)|0x3; static const unsigned long mutex_all_access = (0x000F0000L)|(0x00100000L)|0x0001; @@ -62,6 +65,15 @@ static const unsigned long file_map_copy = section_query; static const unsigned long file_map_write = section_map_write; static const unsigned long file_map_read = section_map_read; static const unsigned long file_map_all_access = section_all_access; +static const unsigned long delete_access = 0x00010000L; +static const unsigned long file_flag_backup_semantics = 0x02000000; +static const long file_flag_delete_on_close = 0x04000000; + +//Native API constants +static const unsigned long file_open_for_backup_intent = 0x00004000; +static const int file_share_valid_flags = 0x00000007; +static const long file_delete_on_close = 0x00001000L; +static const long obj_case_insensitive = 0x00000040L; static const unsigned long movefile_copy_allowed = 0x02; static const unsigned long movefile_delay_until_reboot = 0x04; @@ -74,6 +86,15 @@ static const unsigned long file_share_read = 0x00000001; static const unsigned long file_share_write = 0x00000002; static const unsigned long file_share_delete = 0x00000004; +static const unsigned long file_attribute_readonly = 0x00000001; +static const unsigned long file_attribute_hidden = 0x00000002; +static const unsigned long file_attribute_system = 0x00000004; +static const unsigned long file_attribute_directory = 0x00000010; +static const unsigned long file_attribute_archive = 0x00000020; +static const unsigned long file_attribute_device = 0x00000040; +static const unsigned long file_attribute_normal = 0x00000080; +static const unsigned long file_attribute_temporary = 0x00000100; + static const unsigned long generic_read = 0x80000000L; static const unsigned long generic_write = 0x40000000L; @@ -109,8 +130,6 @@ static const unsigned long open_existing = 3; static const unsigned long open_always = 4; static const unsigned long truncate_existing = 5; -static const unsigned long file_attribute_temporary = 0x00000100; - static const unsigned long file_begin = 0; static const unsigned long file_current = 1; static const unsigned long file_end = 2; @@ -120,6 +139,13 @@ static const unsigned long lockfile_exclusive_lock = 2; static const unsigned long error_lock_violation = 33; static const unsigned long security_descriptor_revision = 1; +//Own defines +static const long SystemTimeOfDayInfoLength = 48; +static const long BootAndSystemstampLength = 16; +static const long BootstampLength = 8; +static const unsigned long MaxPath = 260; + + } //namespace winapi { } //namespace interprocess { } //namespace boost { @@ -151,6 +177,20 @@ struct interprocess_filetime unsigned long dwHighDateTime; }; +struct win32_find_data_t +{ + unsigned long dwFileAttributes; + interprocess_filetime ftCreationTime; + interprocess_filetime ftLastAccessTime; + interprocess_filetime ftLastWriteTime; + unsigned long nFileSizeHigh; + unsigned long nFileSizeLow; + unsigned long dwReserved0; + unsigned long dwReserved1; + char cFileName[MaxPath]; + char cAlternateFileName[14]; +}; + struct interprocess_security_attributes { unsigned long nLength; @@ -208,6 +248,126 @@ typedef struct _interprocess_security_descriptor interprocess_acl *Dacl; } interprocess_security_descriptor; +enum file_information_class_t { + file_directory_information = 1, + file_full_directory_information, + file_both_directory_information, + file_basic_information, + file_standard_information, + file_internal_information, + file_ea_information, + file_access_information, + file_name_information, + file_rename_information, + file_link_information, + file_names_information, + file_disposition_information, + file_position_information, + file_full_ea_information, + file_mode_information, + file_alignment_information, + file_all_information, + file_allocation_information, + file_end_of_file_information, + file_alternate_name_information, + file_stream_information, + file_pipe_information, + file_pipe_local_information, + file_pipe_remote_information, + file_mailslot_query_information, + file_mailslot_set_information, + file_compression_information, + file_copy_on_write_information, + file_completion_information, + file_move_cluster_information, + file_quota_information, + file_reparse_point_information, + file_network_open_information, + file_object_id_information, + file_tracking_information, + file_ole_directory_information, + file_content_index_information, + file_inherit_content_index_information, + file_ole_information, + file_maximum_information +}; + +struct file_name_information_t { + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct file_rename_information_t { + int Replace; + void *RootDir; + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct unicode_string_t { + unsigned short Length; + unsigned short MaximumLength; + wchar_t *Buffer; +}; + +struct object_attributes_t { + unsigned long Length; + void * RootDirectory; + unicode_string_t *ObjectName; + unsigned long Attributes; + void *SecurityDescriptor; + void *SecurityQualityOfService; +}; + +struct io_status_block_t { + union { + long Status; + void *Pointer; + }; + + unsigned long *Information; +}; + +union system_timeofday_information +{ + struct data_t + { + __int64 liKeBootTime; + __int64 liKeSystemTime; + __int64 liExpTimeZoneBias; + unsigned long uCurrentTimeZoneId; + unsigned long dwReserved; + } data; + unsigned char Reserved1[SystemTimeOfDayInfoLength]; +}; + +enum system_information_class { + system_basic_information = 0, + system_performance_information = 2, + system_time_of_day_information = 3, + system_process_information = 5, + system_processor_performance_information = 8, + system_interrupt_information = 23, + system_exception_information = 33, + system_registry_quota_information = 37, + system_lookaside_information = 45 +}; + +enum object_information_class +{ + object_basic_information, + object_name_information, + object_type_information, + object_all_information, + object_data_information +}; + +struct object_name_information_t +{ + unicode_string_t Name; + wchar_t NameBuffer[1]; +}; + //Some windows API declarations extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); @@ -220,6 +380,9 @@ extern "C" __declspec(dllimport) int __stdcall DuplicateHandle , void *hTargetProcessHandle, void **lpTargetHandle , unsigned long dwDesiredAccess, int bInheritHandle , unsigned long dwOptions); +extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindClose(void *hFindFile); extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(interprocess_filetime*); extern "C" __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const interprocess_filetime *in, const interprocess_filetime *out); extern "C" __declspec(dllimport) void * __stdcall CreateMutexA(interprocess_security_attributes*, int, const char *); @@ -245,6 +408,7 @@ extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA std::va_list *Arguments); extern "C" __declspec(dllimport) void *__stdcall LocalFree (void *); extern "C" __declspec(dllimport) int __stdcall CreateDirectoryA(const char *, interprocess_security_attributes*); +extern "C" __declspec(dllimport) int __stdcall RemoveDirectoryA(const char *lpPathName); extern "C" __declspec(dllimport) int __stdcall GetTempPathA(unsigned long length, char *buffer); extern "C" __declspec(dllimport) int __stdcall CreateDirectory(const char *, interprocess_security_attributes*); extern "C" __declspec(dllimport) int __stdcall SetFileValidData(void *, __int64 size); @@ -257,6 +421,25 @@ extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned extern "C" __declspec(dllimport) int __stdcall WriteFile(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped); extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision); extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted); +extern "C" __declspec(dllimport) void *__stdcall LoadLibraryA(const char *); +extern "C" __declspec(dllimport) int __stdcall FreeLibrary(void *); +extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*); +extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*); + +//API function typedefs +//Pointer to functions +typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); +typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass ); +typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); +typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); +typedef long (__stdcall *NtClose_t) (void*); +typedef long (__stdcall *RtlCreateUnicodeStringFromAsciiz_t)(unicode_string_t *, const char *); +typedef void (__stdcall *RtlFreeUnicodeString_t)(unicode_string_t *); +typedef void (__stdcall *RtlInitUnicodeString_t)( unicode_string_t *, const wchar_t * ); +typedef long (__stdcall *RtlAppendUnicodeToString_t)(unicode_string_t *Destination, const wchar_t *Source); +typedef long (__stdcall * NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); +typedef long (__stdcall * NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef unsigned long (__stdcall * GetMappedFileName_t)(void *, void *, wchar_t *, unsigned long); } //namespace winapi { } //namespace interprocess { @@ -298,6 +481,15 @@ static inline unsigned long get_current_process_id() static inline unsigned int close_handle(void* handle) { return CloseHandle(handle); } +static inline void * find_first_file(const char *lpFileName, win32_find_data_t *lpFindFileData) +{ return FindFirstFileA(lpFileName, lpFindFileData); } + +static inline bool find_next_file(void *hFindFile, win32_find_data_t *lpFindFileData) +{ return FindNextFileA(hFindFile, lpFindFileData) != 0; } + +static inline bool find_close(void *handle) +{ return FindClose(handle) != 0; } + static inline bool duplicate_current_process_handle (void *hSourceHandle, void **lpTargetHandle) { @@ -384,6 +576,9 @@ static inline bool get_file_size(void *handle, __int64 &size) static inline bool create_directory(const char *name, interprocess_security_attributes* security) { return 0 != CreateDirectoryA(name, security); } +static inline bool remove_directory(const char *lpPathName) +{ return 0 != RemoveDirectoryA(lpPathName); } + static inline unsigned long get_temp_path(unsigned long length, char *buffer) { return GetTempPathA(length, buffer); } @@ -417,6 +612,274 @@ static inline long interlocked_exchange_add(long volatile* addend, long value) static inline long interlocked_exchange(long volatile* addend, long value) { return BOOST_INTERLOCKED_EXCHANGE(const_cast(addend), value); } +//Forward functions +static inline void *load_library(const char *name) +{ return LoadLibraryA(name); } + +static inline bool free_library(void *module) +{ return 0 != FreeLibrary(module); } + +static inline void *get_proc_address(void *module, const char *name) +{ return GetProcAddress(module, name); } + +static inline void *get_current_process() +{ return GetCurrentProcess(); } + +static inline void *get_module_handle(const char *name) +{ return GetModuleHandleA(name); } + +static inline void initialize_object_attributes +( object_attributes_t *pobject_attr, unicode_string_t *name + , unsigned long attr, void *rootdir, void *security_descr) + +{ + pobject_attr->Length = sizeof(object_attributes_t); + pobject_attr->RootDirectory = rootdir; + pobject_attr->Attributes = attr; + pobject_attr->ObjectName = name; + pobject_attr->SecurityDescriptor = security_descr; + pobject_attr->SecurityQualityOfService = 0; +} + +static inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, unsigned short bufSize) +{ + ucStr->Buffer = buf; + ucStr->Length = 0; + ucStr->MaximumLength = bufSize; +} + +//Complex winapi based functions... + +//pszFilename must have room for at least MaxPath+1 characters +static inline bool get_file_name_from_handle_function + (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length) +{ + if(length <= MaxPath){ + return false; + } + + void *hiPSAPI = load_library("PSAPI.DLL"); + if (0 == hiPSAPI) + return 0; + + class library_unloader + { + void *lib_; + + public: + library_unloader(void *module) : lib_(module){} + ~library_unloader(){ free_library(lib_); } + } unloader(hiPSAPI); + + // Pointer to function getMappedFileName() in PSAPI.DLL + GetMappedFileName_t pfGMFN = + (GetMappedFileName_t)get_proc_address(hiPSAPI, "GetMappedFileNameW"); + if (! pfGMFN){ + return 0; // Failed: unexpected error + } + + bool bSuccess = false; + + // Create a file mapping object. + void * hFileMap = create_file_mapping(hFile, page_readonly, 0, 1, 0); + if(hFileMap) + { + // Create a file mapping to get the file name. + void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 0, 1, 0); + + if (pMem){ + out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath); + if(out_length){ + bSuccess = true; + } + unmap_view_of_file(pMem); + } + close_handle(hFileMap); + } + + return(bSuccess); +} + +static inline bool get_system_time_of_day_information(system_timeofday_information &info) +{ + NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t) + get_proc_address(get_module_handle("ntdll.dll"), "NtQuerySystemInformation"); + unsigned long res; + long status = pNtQuerySystemInformation(system_time_of_day_information, &info, sizeof(info), &res); + if(status){ + return false; + } + return true; +} + +static inline bool get_boot_time(unsigned char (&bootstamp) [BootstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootstamp[0], &info.Reserved1, sizeof(bootstamp)); + return true; +} + +static inline bool get_boot_and_system_time(unsigned char (&bootsystemstamp) [BootAndSystemstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootsystemstamp[0], &info.Reserved1, sizeof(bootsystemstamp)); + return true; +} + +static inline bool get_boot_time_str(char *bootstamp_str, std::size_t &s) //will write BootstampLength chars +{ + if(s < (BootstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + std::size_t char_counter = 0; + for(std::size_t i = 0; i != static_cast(BootstampLength); ++i){ + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootstampLength*2; + return true; +} + +static inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t &s) //will write BootAndSystemstampLength chars +{ + if(s < (BootAndSystemstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + const wchar_t Characters [] = + { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7' + , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' }; + std::size_t char_counter = 0; + for(std::size_t i = 0; i != static_cast(BootAndSystemstampLength); ++i){ + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootAndSystemstampLength*2; + return true; +} + +static inline bool unlink_file(const char *filename) +{ + try{ + NtSetInformationFile_t pNtSetInformationFile = + (NtSetInformationFile_t)get_proc_address(get_module_handle("ntdll.dll"), "NtSetInformationFile"); + if(!pNtSetInformationFile){ + return false; + } + + NtQueryObject_t pNtQueryObject = + (NtQueryObject_t)get_proc_address(get_module_handle("ntdll.dll"), "NtQueryObject"); + + //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths + void *fh = create_file(filename, generic_read | delete_access, open_existing, + file_flag_backup_semantics | file_flag_delete_on_close); + if(fh == invalid_handle_value){ + return false; + } + + class handle_closer + { + void *handle_; + public: + handle_closer(void *handle) : handle_(handle){} + ~handle_closer(){ close_handle(handle_); } + } handle_closer(fh); + + const std::size_t CharArraySize = 32767; //Max name length + + union mem_t + { + object_name_information_t name; + struct ren_t + { + file_rename_information_t info; + wchar_t buf[CharArraySize]; + } ren; + }; + + class auto_ptr + { + public: + explicit auto_ptr(mem_t *ptr) : ptr_(ptr){} + ~auto_ptr(){ delete ptr_; } + mem_t *get() const{ return (ptr_); } + mem_t *operator->() const{ return this->get(); } + private: + mem_t *ptr_; + } pmem(new mem_t); + + file_rename_information_t *pfri = (file_rename_information_t*)&pmem->ren.info; + const std::size_t RenMaxNumChars = + ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + + //Obtain file name + unsigned long size; + if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(mem_t), &size)){ + return false; + } + + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + + //Second step: obtain the complete native-nt filename + //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ + //return 0; + //} + + //Add trailing mark + if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ + return false; + } + + //Search '\\' character to replace it + for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ + if(pmem->ren.info.FileName[--i] == L'\\') + break; + } + + //Add random number + std::size_t s = RenMaxNumChars - filename_string_length; + if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ + return false; + } + filename_string_length += s; + + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; + + //Final step: change the name of the in-use file: + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(mem_t::ren_t), file_rename_information)){ + return false; + } + return true; + } + catch(...){ + return false; + } +} + } //namespace winapi } //namespace interprocess } //namespace boost diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index e21164d..80168c7 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -13,7 +13,19 @@ #include -#if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) +#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) + +#define BOOST_INTERPROCESS_WINDOWS + +/* +#if !defined(_MSC_EXTENSIONS) +#error "Turn on Microsoft language extensions (_MSC_EXTENSIONS) to be able to call Windows API functions" +#endif +*/ + +#endif + +#if !(defined BOOST_INTERPROCESS_WINDOWS) #include @@ -30,10 +42,12 @@ # endif #if ((_POSIX_SEMAPHORES - 0) > 0) - # define BOOST_INTERPROCESS_POSIX_SEMAPHORES + # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES # if defined(__CYGWIN__) #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK # endif + #elif defined(__APPLE__) + # define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES #endif #if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ @@ -51,10 +65,15 @@ #if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS #else + //VMS and MACOS don't define it but the have shm_open/close interface # if defined(__vms) # if __CRTL_VER >= 70200000 # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS # endif + # define BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS + //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX + //# elif defined (__APPLE__) + //# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS # endif #endif @@ -76,7 +95,7 @@ #endif #endif - #ifdef BOOST_INTERPROCESS_POSIX_SEMAPHORES + #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES) #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES #endif @@ -88,34 +107,20 @@ #endif -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) -// C++0x features are only enabled when -std=c++0x or -std=gnu++0x are -// passed on the command line, which in turn defines -// __GXX_EXPERIMENTAL_CXX0X__. Note: __GXX_EXPERIMENTAL_CPP0X__ is -// 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 -# if defined(__GLIBCPP__) || defined(__GLIBCXX__) -# define BOOST_INTERPROCESS_RVALUE_PAIR -# endif -# endif -#endif - -#if defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && defined(BOOST_INTERPROCESS_VARIADIC_TEMPLATES) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) #define BOOST_INTERPROCESS_PERFECT_FORWARDING #endif //Now declare some Boost.Interprocess features depending on the implementation -#if defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #endif -#if defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index 8c17c2c..cdd4208 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -33,7 +33,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -42,7 +42,7 @@ # else //ifdef BOOST_HAS_UNISTD_H # error Unknown platform # endif //ifdef BOOST_HAS_UNISTD_H -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) //!\file //!Describes the error numbering of interprocess classes @@ -52,7 +52,7 @@ namespace interprocess { /// @cond static inline int system_error_code() // artifact of POSIX and WINDOWS error reporting { - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) return winapi::get_last_error(); #else return errno; // GCC 3.1 won't accept ::errno @@ -60,7 +60,7 @@ static inline int system_error_code() // artifact of POSIX and WINDOWS error rep } -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) inline void fill_system_message(int sys_err_code, std::string &str) { void *lpMsgBuf; @@ -110,7 +110,9 @@ enum error_code_t sem_error, mode_error, size_error, - corrupted_error + corrupted_error, + not_such_file_or_directory, + invalid_argument }; typedef int native_error_t; @@ -124,7 +126,7 @@ struct ec_xlate static const ec_xlate ec_table[] = { - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) { /*ERROR_ACCESS_DENIED*/5L, security_error }, { /*ERROR_INVALID_ACCESS*/12L, security_error }, { /*ERROR_SHARING_VIOLATION*/32L, security_error }, @@ -156,7 +158,7 @@ static const ec_xlate ec_table[] = { /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error }, { /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error }, { /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error } - #else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #else //#if (defined BOOST_INTERPROCESS_WINDOWS) { EACCES, security_error }, { EROFS, read_only_error }, { EIO, io_error }, @@ -171,8 +173,10 @@ static const ec_xlate ec_table[] = { EISDIR, is_directory_error }, { ENOSPC, out_of_space_error }, { ENOMEM, out_of_memory_error }, - { EMFILE, out_of_resource_error } - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + { EMFILE, out_of_resource_error }, + { ENOENT, not_such_file_or_directory }, + { EINVAL, invalid_argument } + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) }; static inline error_code_t lookup_error(native_error_t err) diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index 37391e2..6dbefb4 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -21,8 +21,6 @@ #include #include #include //std::string -#include //std::remove -#include //!\file //!Describes file_mapping and mapped region classes @@ -30,31 +28,19 @@ namespace boost { namespace interprocess { -///@cond - -class file_mapping; - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - -///@endcond - //!A class that wraps a file-mapping that can be used to //!create mapped regions from the mapped files class file_mapping { /// @cond //Non-copyable and non-assignable - file_mapping(const file_mapping &); - file_mapping &operator=(const file_mapping &); + file_mapping(file_mapping &); + file_mapping &operator=(file_mapping &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_mapping) + //!Constructs an empty file mapping. //!Does not throw file_mapping(); @@ -68,41 +54,23 @@ class file_mapping //!Moves the ownership of "moved"'s file mapping object to *this. //!After the call, "moved" does not represent any file mapping object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_mapping(detail::moved_object moved) - : m_handle(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - file_mapping(file_mapping &&moved) + file_mapping(BOOST_INTERPROCESS_RV_REF(file_mapping) moved) : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s file mapping to *this. //!After the call, "moved" does not represent any file mapping. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_mapping &operator=(detail::moved_object m_other) - { - file_mapping &moved = m_other.get(); - #else - file_mapping &operator=(file_mapping &&moved) - { - #endif - file_mapping tmp(detail::move_impl(moved)); + file_mapping &operator=(BOOST_INTERPROCESS_RV_REF(file_mapping) moved) + { + file_mapping tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } //!Swaps to file_mappings. //!Does not throw. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(file_mapping &other); - #else - void swap(file_mapping &&other); - #endif //!Returns access mode //!used in the constructor @@ -120,6 +88,12 @@ class file_mapping //!used in the constructor. const char *get_name() const; + //!Removes the file named "filename" even if it's been memory mapped. + //!Returns true on success. + //!The function might fail in some operating systems if the file is + //!being used other processes and no deletion permission was shared. + static bool remove(const char *filename); + /// @cond private: //!Closes a previously opened file mapping. Never throws. @@ -140,11 +114,7 @@ inline file_mapping::~file_mapping() inline const char *file_mapping::get_name() const { return m_filename.c_str(); } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void file_mapping::swap(file_mapping &other) -#else -inline void file_mapping::swap(file_mapping &&other) -#endif { std::swap(m_handle, other.m_handle); std::swap(m_mode, other.m_mode); @@ -179,6 +149,9 @@ inline file_mapping::file_mapping m_mode = mode; } +inline bool file_mapping::remove(const char *filename) +{ return detail::delete_file(filename); } + ///@cond inline void file_mapping::priv_close() @@ -192,7 +165,7 @@ inline void file_mapping::priv_close() ///@endcond //!A class that stores the name of a file -//!and call std::remove(name) in its destructor +//!and tries to remove it in its destructor //!Useful to remove temporary files in the presence //!of exceptions class remove_file_on_destroy @@ -204,7 +177,7 @@ class remove_file_on_destroy {} ~remove_file_on_destroy() - { std::remove(m_name); } + { detail::delete_file(m_name); } }; } //namespace interprocess { diff --git a/include/boost/interprocess/indexes/iunordered_set_index.hpp b/include/boost/interprocess/indexes/iunordered_set_index.hpp index 1b059a3..522ab4a 100644 --- a/include/boost/interprocess/indexes/iunordered_set_index.hpp +++ b/include/boost/interprocess/indexes/iunordered_set_index.hpp @@ -176,7 +176,7 @@ class iunordered_set_index return old_size; std::size_t received_size; if(!alloc.allocation_command - (try_shrink_in_place | nothrow_allocation, old_size, new_size, received_size, buckets).first){ + (boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, new_size, received_size, buckets).first){ return old_size; } @@ -188,7 +188,7 @@ class iunordered_set_index } bucket_ptr shunk_p = alloc.allocation_command - (shrink_in_place | nothrow_allocation, received_size, received_size, received_size, buckets).first; + (boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, received_size, buckets).first; BOOST_ASSERT(buckets == shunk_p); bucket_ptr buckets_init = buckets + received_size; @@ -205,7 +205,7 @@ class iunordered_set_index std::size_t received_size; std::pair ret = alloc.allocation_command - (expand_fwd | allocate_new, new_num, new_num, received_size, old_buckets); + (boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, new_num, received_size, old_buckets); if(ret.first == old_buckets){ bucket_ptr buckets_init = old_buckets + old_num; for(std::size_t i = 0; i < (new_num - old_num); ++i){ diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index aca3960..575a2a9 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -11,12 +11,12 @@ #ifndef BOOST_INTERPROCESS_FWD_HPP #define BOOST_INTERPROCESS_FWD_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined (_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -//#include -//#include +#include +#include #include @@ -61,9 +61,9 @@ namespace boost { namespace interprocess { class shared_memory_object; -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if defined (BOOST_INTERPROCESS_WINDOWS) class windows_shared_memory; -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) ////////////////////////////////////////////////////////////////////////////// // mapped file/mapped region/mapped_file @@ -113,6 +113,9 @@ class scoped_lock; template class sharable_lock; +template +class upgradable_lock; + ////////////////////////////////////////////////////////////////////////////// // STL compatible allocators ////////////////////////////////////////////////////////////////////////////// @@ -230,7 +233,7 @@ wmanaged_shared_memory; // Windows shared memory managed memory classes ////////////////////////////////////////////////////////////////////////////// -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if defined (BOOST_INTERPROCESS_WINDOWS) template wmanaged_windows_shared_memory; -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else + +template class IndexType> +class basic_managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +wmanaged_xsi_shared_memory; + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) ////////////////////////////////////////////////////////////////////////////// // Fixed address shared memory @@ -382,98 +404,12 @@ class weak_ptr; class message_queue; -////////////////////////////////////////////////////////////////////////////// -// Containers -////////////////////////////////////////////////////////////////////////////// - -//vector class -template > -class vector; - -//vector class -template > -class deque; - -//list class -template > -class list; - -//slist class -template > -class slist; - -//set class -template - ,class Alloc = std::allocator > -class set; - -//multiset class -template - ,class Alloc = std::allocator > -class multiset; - -//map class -template - ,class Alloc = std::allocator > > -class map; - -//multimap class -template - ,class Alloc = std::allocator > > -class multimap; - -//flat_set class -template - ,class Alloc = std::allocator > -class flat_set; - -//flat_multiset class -template - ,class Alloc = std::allocator > -class flat_multiset; - -//flat_map class -template - ,class Alloc = std::allocator > > -class flat_map; - -//flat_multimap class -template - ,class Alloc = std::allocator > > -class flat_multimap; - -//basic_string class -template - ,class Alloc = std::allocator > -class basic_string; - -//string class -typedef basic_string - - ,std::allocator > -string; - }} //namespace boost { namespace interprocess { -//#include +////////////////////////////////////////////////////////////////////////////// +// CONTAINERS +////////////////////////////////////////////////////////////////////////////// + +#include #endif //#ifndef BOOST_INTERPROCESS_FWD_HPP - diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index 88550f6..30b822a 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -43,9 +43,12 @@ class basic_managed_external_buffer /// @cond typedef detail::basic_managed_memory_impl base_t; + basic_managed_external_buffer(basic_managed_external_buffer&); + basic_managed_external_buffer & operator=(basic_managed_external_buffer&); /// @endcond - + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_external_buffer) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -75,25 +78,15 @@ class basic_managed_external_buffer } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_external_buffer(detail::moved_object mother) + basic_managed_external_buffer(BOOST_INTERPROCESS_RV_REF(basic_managed_external_buffer) moved) { - basic_managed_external_buffer &moved = mother.get(); - #else - basic_managed_external_buffer(basic_managed_external_buffer &&moved) - { - #endif this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_external_buffer &operator=(detail::moved_object moved) - #else - basic_managed_external_buffer &operator=(basic_managed_external_buffer &&moved) - #endif + basic_managed_external_buffer &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_external_buffer) moved) { - basic_managed_external_buffer tmp(detail::move_impl(moved)); + basic_managed_external_buffer tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -103,36 +96,10 @@ class basic_managed_external_buffer //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_external_buffer &other) - #else - void swap(basic_managed_external_buffer &&other) - #endif { base_t::swap(other); } }; -///@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 87a5452..5bc4509 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -46,9 +46,12 @@ class basic_managed_heap_memory typedef detail::basic_managed_memory_impl base_t; + basic_managed_heap_memory(basic_managed_heap_memory&); + basic_managed_heap_memory & operator=(basic_managed_heap_memory&); /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_heap_memory) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -71,26 +74,13 @@ class basic_managed_heap_memory } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_heap_memory - (detail::moved_object mother) - { - basic_managed_heap_memory &moved = mother.get(); - #else - basic_managed_heap_memory(basic_managed_heap_memory &&moved) - { - #endif - this->swap(moved); - } + basic_managed_heap_memory(BOOST_INTERPROCESS_RV_REF(basic_managed_heap_memory) moved) + { this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_heap_memory &operator=(detail::moved_object moved) - #else - basic_managed_heap_memory &operator=(basic_managed_heap_memory &&moved) - #endif + basic_managed_heap_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_heap_memory) moved) { - basic_managed_heap_memory tmp(detail::move_impl(moved)); + basic_managed_heap_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -125,13 +115,7 @@ class basic_managed_heap_memory //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_heap_memory &other) - #else - void swap(basic_managed_heap_memory &&other) - #endif { base_t::swap(other); m_heapmem.swap(other.m_heapmem); @@ -150,27 +134,8 @@ 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 { #include diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index dee8488..065c424 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -47,6 +47,8 @@ class basic_managed_mapped_file ::ManagedOpenOrCreateUserOffset> base_t; typedef detail::file_wrapper device_type; + basic_managed_mapped_file(basic_managed_mapped_file&); + basic_managed_mapped_file & operator=(basic_managed_mapped_file&); private: @@ -61,6 +63,7 @@ class basic_managed_mapped_file /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_mapped_file) //!Creates mapped file and creates and places the segment manager. //!This can throw. @@ -118,27 +121,16 @@ class basic_managed_mapped_file //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_mapped_file - (detail::moved_object mother) + basic_managed_mapped_file(BOOST_INTERPROCESS_RV_REF(basic_managed_mapped_file) moved) { - basic_managed_mapped_file &moved = mother.get(); - #else - basic_managed_mapped_file(basic_managed_mapped_file &&moved) - { - #endif this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_mapped_file &operator=(detail::moved_object moved) - #else - basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved) - #endif + basic_managed_mapped_file &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_mapped_file) moved) { - basic_managed_mapped_file tmp(detail::move_impl(moved)); + basic_managed_mapped_file tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -154,14 +146,7 @@ class basic_managed_mapped_file //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } - void swap(basic_managed_mapped_file &other) - #else - void swap(basic_managed_mapped_file &&other) - #endif { base_t::swap(other); m_mfile.swap(other.m_mfile); @@ -214,27 +199,7 @@ class basic_managed_mapped_file /// @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 { #include diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index a726e06..990585e 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -60,9 +60,12 @@ class basic_managed_shared_memory private: typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + basic_managed_shared_memory(basic_managed_shared_memory&); + basic_managed_shared_memory & operator=(basic_managed_shared_memory&); /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_shared_memory) //!Destroys *this and indicates that the calling process is finished using //!the resource. The destructor function will deallocate @@ -134,14 +137,8 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_shared_memory(detail::moved_object mother) + basic_managed_shared_memory(BOOST_INTERPROCESS_RV_REF(basic_managed_shared_memory) moved) { - basic_managed_shared_memory &moved = mother.get(); - #else - basic_managed_shared_memory(basic_managed_shared_memory &&moved) - { - #endif basic_managed_shared_memory tmp; this->swap(moved); tmp.swap(moved); @@ -149,26 +146,16 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_shared_memory &operator=(detail::moved_object moved) - #else - basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved) - #endif + basic_managed_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_shared_memory) moved) { - basic_managed_shared_memory tmp(detail::move_impl(moved)); + basic_managed_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } //!Swaps the ownership of the managed shared memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_shared_memory &other) - #else - void swap(basic_managed_shared_memory &&other) - #endif { base_t::swap(other); base2_t::swap(other); @@ -179,20 +166,20 @@ class basic_managed_shared_memory //! //!This function is not synchronized so no other thread or process should //!be reading or writing the file - static bool grow(const char *filename, std::size_t extra_bytes) + static bool grow(const char *shmname, std::size_t extra_bytes) { return base_t::template grow - (filename, extra_bytes); + (shmname, extra_bytes); } //!Tries to resize the managed shared memory to minimized the size of the file. //! //!This function is not synchronized so no other thread or process should //!be reading or writing the file - static bool shrink_to_fit(const char *filename) + static bool shrink_to_fit(const char *shmname) { return base_t::template shrink_to_fit - (filename); + (shmname); } /// @cond @@ -214,25 +201,6 @@ class basic_managed_shared_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_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index a0e9a92..144352b 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -60,9 +60,13 @@ class basic_managed_windows_shared_memory private: typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + basic_managed_windows_shared_memory(basic_managed_windows_shared_memory&); + basic_managed_windows_shared_memory & operator=(basic_managed_windows_shared_memory&); + /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_windows_shared_memory) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -121,24 +125,15 @@ class basic_managed_windows_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_managed_windows_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - basic_managed_windows_shared_memory(basic_managed_windows_shared_memory &&moved) + (BOOST_INTERPROCESS_RV_REF(basic_managed_windows_shared_memory) moved) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_windows_shared_memory &operator=(detail::moved_object moved) - #else - basic_managed_windows_shared_memory &operator=(basic_managed_windows_shared_memory &&moved) - #endif + basic_managed_windows_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_windows_shared_memory) moved) { - basic_managed_windows_shared_memory tmp(detail::move_impl(moved)); + basic_managed_windows_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -153,19 +148,14 @@ class basic_managed_windows_shared_memory //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_windows_shared_memory &other) - #else - void swap(basic_managed_windows_shared_memory &&other) - #endif { base_t::swap(other); 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. @@ -185,25 +175,6 @@ class basic_managed_windows_shared_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/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 115b25d..f571272 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -22,7 +22,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -31,11 +31,13 @@ # include # include # include +# include +# include # else # error Unknown platform # endif -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) //!\file //!Describes memory_mappable and mapped region classes @@ -55,11 +57,12 @@ class mapped_region { /// @cond //Non-copyable - mapped_region(const mapped_region &); - mapped_region &operator=(const mapped_region &); + mapped_region(mapped_region &); + mapped_region &operator=(mapped_region &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(mapped_region) //!Creates a mapping region of the mapped memory "mapping", starting in //!offset "offset", and the mapping's size will be "size". The mapping @@ -78,11 +81,7 @@ class mapped_region //!Move constructor. *this will be constructed taking ownership of "other"'s //!region and "other" will be left in default constructor state. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - mapped_region(detail::moved_object other); - #else - mapped_region(mapped_region &&other); - #endif + mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other); //!Destroys the mapped region. //!Does not throw @@ -90,11 +89,7 @@ class mapped_region //!Move assignment. If *this owns a memory mapped region, it will be //!destroyed and it will take ownership of "other"'s memory mapped region. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - mapped_region &operator=(detail::moved_object other); - #else - mapped_region &operator=(mapped_region &&other); - #endif + mapped_region &operator=(BOOST_INTERPROCESS_RV_REF(mapped_region) other); //!Returns the size of the mapping. Note for windows users: If //!windows_shared_memory is mapped using 0 as the size, it returns 0 @@ -119,13 +114,7 @@ class mapped_region //!Swaps the mapped_region with another //!mapped region - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(mapped_region &other); - #else - void swap(mapped_region &&other); - #endif //!Returns the size of the page. This size is the minimum memory that //!will be used by the system when mapping a memory mappable source. @@ -148,8 +137,10 @@ class mapped_region 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; + #if (defined BOOST_INTERPROCESS_WINDOWS) + file_handle_t m_file_mapping_hnd; + #else + bool m_is_xsi; #endif friend class detail::interprocess_tester; @@ -163,14 +154,9 @@ class mapped_region inline void swap(mapped_region &x, mapped_region &y) { x.swap(y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region &mapped_region::operator=(detail::moved_object moved) +inline mapped_region &mapped_region::operator=(BOOST_INTERPROCESS_RV_REF(mapped_region) moved) { -#else -inline mapped_region &mapped_region::operator=(mapped_region &&moved) -{ -#endif - mapped_region tmp(detail::move_impl(moved)); + mapped_region tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -190,28 +176,19 @@ inline mode_t mapped_region::get_mode() const inline void* mapped_region::get_address() const { return m_base; } -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) inline mapped_region::mapped_region() : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) {} -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -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) +inline mapped_region::mapped_region(BOOST_INTERPROCESS_RV_REF(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 template inline std::size_t mapped_region::page_size_holder::get_page_size() @@ -264,7 +241,9 @@ inline mapped_region::mapped_region //Update mapping size if the user does not specify it if(size == 0){ __int64 total_size; - if(!winapi::get_file_size(detail::file_handle_from_mapping_handle(mapping.get_mapping_handle()), total_size)){ + if(!winapi::get_file_size + (detail::file_handle_from_mapping_handle + (mapping.get_mapping_handle()), total_size)){ error_info err(winapi::get_last_error()); throw interprocess_exception(err); } @@ -382,11 +361,10 @@ inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbyte inline void mapped_region::priv_close() { if(m_base){ - this->flush(); winapi::unmap_view_of_file(static_cast(m_base) - m_extra_offset); m_base = 0; } - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) if(m_file_mapping_hnd != detail::invalid_file()){ winapi::close_handle(m_file_mapping_hnd); m_file_mapping_hnd = detail::invalid_file(); @@ -397,22 +375,15 @@ inline void mapped_region::priv_close() inline void mapped_region::dont_close_on_destruction() {} -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) inline mapped_region::mapped_region() - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false) {} -#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_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_mode(read_only) - , m_extra_offset(0) +inline mapped_region::mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false) { this->swap(other); } -#endif template inline std::size_t mapped_region::page_size_holder::get_page_size() @@ -425,13 +396,55 @@ 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_mode(mode) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode), m_is_xsi(false) { + mapping_handle_t map_hnd = mapping.get_mapping_handle(); + + if(map_hnd.is_xsi){ + //Get the size + ::shmid_ds xsi_ds; + int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds); + if(ret == -1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Compare sizess + if(size == 0){ + size = (std::size_t)xsi_ds.shm_segsz; + } + else if(size != (std::size_t)xsi_ds.shm_segsz){ + error_info err(size_error); + throw interprocess_exception(err); + } + //Calculate flag + int flag = 0; + if(m_mode == read_only){ + flag |= SHM_RDONLY; + } + else if(m_mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + //Attach memory + void *base = ::shmat(map_hnd.handle, (void*)address, flag); + if(base == (void*)-1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Update members + m_base = base; + m_offset = offset; + m_size = size; + m_mode = mode; + m_extra_offset = 0; + m_is_xsi = true; + + return; + } + if(size == 0){ -// offset_t filesize = lseek64 offset_t filesize = lseek - (mapping.get_mapping_handle(), offset, SEEK_END); - + (map_hnd.handle, offset, SEEK_END); if(filesize == -1 ){ error_info err(system_error_code()); throw interprocess_exception(err); @@ -440,12 +453,13 @@ inline mapped_region::mapped_region error_info err(size_error); throw interprocess_exception(err); } + filesize -= offset; - size = (size_t)filesize; + if((offset_t)size != filesize){ error_info err(size_error); - throw interprocess_exception(err); + throw interprocess_exception(err); } } @@ -459,7 +473,7 @@ inline mapped_region::mapped_region prot |= PROT_READ; flags |= MAP_SHARED; break; - + case read_write: prot |= (PROT_WRITE | PROT_READ); flags |= MAP_SHARED; @@ -469,7 +483,7 @@ inline mapped_region::mapped_region prot |= (PROT_WRITE | PROT_READ); flags |= MAP_PRIVATE; break; - + default: { error_info err(mode_error); @@ -496,7 +510,7 @@ inline mapped_region::mapped_region , static_cast(m_extra_offset + m_size) , prot , flags - , mapping.get_mapping_handle() + , mapping.get_mapping_handle().handle , offset - m_extra_offset); //Check if mapping was successful @@ -537,7 +551,12 @@ inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbyte inline void mapped_region::priv_close() { if(m_base != MAP_FAILED){ - this->flush(); + if(m_is_xsi){ + int ret = ::shmdt(m_base); + assert(ret == 0); + (void)ret; + return; + } munmap(static_cast(m_base) - m_extra_offset, m_size + m_extra_offset); m_base = MAP_FAILED; } @@ -546,7 +565,7 @@ inline void mapped_region::priv_close() inline void mapped_region::dont_close_on_destruction() { m_base = MAP_FAILED; } -#endif //##if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //##if (defined BOOST_INTERPROCESS_WINDOWS) template const std::size_t mapped_region::page_size_holder::PageSize @@ -560,19 +579,17 @@ inline std::size_t mapped_region::get_page_size() return page_size_holder<0>::PageSize; } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void mapped_region::swap(mapped_region &other) -#else -inline void mapped_region::swap(mapped_region &&other) -#endif { detail::do_swap(this->m_base, other.m_base); 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_mode, other.m_mode); + #if (defined BOOST_INTERPROCESS_WINDOWS) detail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd); + #else + detail::do_swap(this->m_is_xsi, other.m_is_xsi); #endif } @@ -583,13 +600,6 @@ struct null_mapped_region_function { 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 2cdc2ce..dec5300 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -19,14 +19,17 @@ #include #include -#include +#include #include #include -#include #include #include +#include #include #include +#include +#include +#include //!\file //!Implements common operations for memory algorithms. @@ -36,206 +39,527 @@ namespace interprocess { namespace detail { template -struct multi_allocation_next +class basic_multiallocation_slist { - typedef typename detail:: - pointer_to_other::type - multi_allocation_next_ptr; - - multi_allocation_next(multi_allocation_next_ptr n) - : next_(n) - {} - multi_allocation_next_ptr next_; -}; - -//!This iterator is returned by "allocate_many" functions so that -//!the user can access the multiple buffers allocated in a single call -template -class basic_multiallocation_iterator - : public std::iterator -{ - void unspecified_bool_type_func() const {} - typedef void (basic_multiallocation_iterator::*unspecified_bool_type)() const; - typedef typename detail:: - pointer_to_other - >::type - multi_allocation_next_ptr; - public: - typedef char value_type; - typedef value_type & reference; - typedef value_type * pointer; - - basic_multiallocation_iterator() - : next_alloc_(0) - {} - - basic_multiallocation_iterator(multi_allocation_next_ptr next) - : next_alloc_(next) - {} - - basic_multiallocation_iterator &operator=(const basic_multiallocation_iterator &other) - { next_alloc_ = other.next_alloc_; return *this; } - - public: - basic_multiallocation_iterator& operator++() - { next_alloc_.next_ = detail::get_pointer(next_alloc_.next_->next_); return *this; } - - basic_multiallocation_iterator operator++(int) - { - basic_multiallocation_iterator result(next_alloc_.next_); - ++*this; - return result; - } - - bool operator== (const basic_multiallocation_iterator& other) const - { return next_alloc_.next_ == other.next_alloc_.next_; } - - bool operator!= (const basic_multiallocation_iterator& other) const - { return !operator== (other); } - - reference operator*() const - { return *reinterpret_cast(detail::get_pointer(next_alloc_.next_)); } - - operator unspecified_bool_type() const - { return next_alloc_.next_? &basic_multiallocation_iterator::unspecified_bool_type_func : 0; } - - pointer operator->() const - { return &(*(*this)); } - - static basic_multiallocation_iterator create_simple_range(void *mem) - { - basic_multiallocation_iterator it; - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); - it = basic_multiallocation_iterator(tmp_mem); - tmp_mem->next_ = 0; - return it; - } - - multi_allocation_next &get_multi_allocation_next() - { return *next_alloc_.next_; } + typedef VoidPointer void_pointer; private: - multi_allocation_next next_alloc_; -}; + static VoidPointer &priv_get_ref(const VoidPointer &p) + { return *static_cast(detail::get_pointer(p)); } -template -class basic_multiallocation_chain -{ - private: - basic_multiallocation_iterator it_; - VoidPointer last_mem_; - std::size_t num_mem_; - - basic_multiallocation_chain(const basic_multiallocation_chain &); - basic_multiallocation_chain &operator=(const basic_multiallocation_chain &); + basic_multiallocation_slist(basic_multiallocation_slist &); + basic_multiallocation_slist &operator=(basic_multiallocation_slist &); public: - typedef basic_multiallocation_iterator multiallocation_iterator; + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist) - basic_multiallocation_chain() - : it_(0), last_mem_(0), num_mem_(0) - {} - - void reset() + //!This iterator is returned by "allocate_many" functions so that + //!the user can access the multiple buffers allocated in a single call + class iterator + : public std::iterator { - this->it_ = multiallocation_iterator(); - this->last_mem_ = 0; - this->num_mem_ = 0; - } + friend class basic_multiallocation_slist; + void unspecified_bool_type_func() const {} + typedef void (iterator::*unspecified_bool_type)() const; - void push_back(void *mem) - { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); + iterator(void_pointer node_range) + : next_node_(node_range) + {} + + public: + typedef char value_type; + typedef value_type & reference; + typedef value_type * pointer; + + iterator() + : next_node_(0) + {} + + iterator &operator=(const iterator &other) + { next_node_ = other.next_node_; return *this; } + + public: + iterator& operator++() + { + next_node_ = *static_cast(detail::get_pointer(next_node_)); + return *this; + } - if(!this->last_mem_){ - this->it_ = basic_multiallocation_iterator(tmp_mem); + iterator operator++(int) + { + iterator result(*this); + ++*this; + return result; } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; - } - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - ++num_mem_; - } - void push_front(void *mem) + bool operator== (const iterator& other) const + { return next_node_ == other.next_node_; } + + bool operator!= (const iterator& other) const + { return !operator== (other); } + + reference operator*() const + { return *static_cast(detail::get_pointer(next_node_)); } + + operator unspecified_bool_type() const + { return next_node_? &iterator::unspecified_bool_type_func : 0; } + + pointer operator->() const + { return &(*(*this)); } + + private: + void_pointer next_node_; + }; + + private: + iterator it_; + + public: + basic_multiallocation_slist() + : it_(iterator()) + {} + + basic_multiallocation_slist(void_pointer p) + : it_(p ? iterator_to(p) : iterator()) + {} + + basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + : it_(iterator()) + { this->swap(other); } + + basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); - ++num_mem_; - - if(!this->last_mem_){ - this->it_ = basic_multiallocation_iterator(tmp_mem); - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - } - else{ - next_impl_t * old_first = &this->it_.get_multi_allocation_next(); - tmp_mem->next_ = old_first; - this->it_ = basic_multiallocation_iterator(tmp_mem); - } - } - - void swap(basic_multiallocation_chain &other_chain) - { - std::swap(this->it_, other_chain.it_); - std::swap(this->last_mem_, other_chain.last_mem_); - std::swap(this->num_mem_, other_chain.num_mem_); - } - - void splice_back(basic_multiallocation_chain &other_chain) - { - typedef multi_allocation_next next_impl_t; - multiallocation_iterator end_it; - multiallocation_iterator other_it = other_chain.get_it(); - multiallocation_iterator this_it = this->get_it(); - if(end_it == other_it){ - return; - } - else if(end_it == this_it){ - this->swap(other_chain); - } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ - = &other_chain.it_.get_multi_allocation_next(); - this->last_mem_ = other_chain.last_mem_; - this->num_mem_ += other_chain.num_mem_; - } - } - - void *pop_front() - { - multiallocation_iterator itend; - if(this->it_ == itend){ - this->last_mem_= 0; - this->num_mem_ = 0; - return 0; - } - else{ - void *addr = &*it_; - ++it_; - --num_mem_; - if(!num_mem_){ - this->last_mem_ = 0; - this->it_ = multiallocation_iterator(); - } - return addr; - } + basic_multiallocation_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; } bool empty() const - { return !num_mem_; } + { return !it_; } - multiallocation_iterator get_it() const - { return it_; } + iterator before_begin() const + { return iterator(void_pointer(const_cast(static_cast(&it_.next_node_)))); } - std::size_t size() const - { return num_mem_; } + iterator begin() const + { return it_; } + + iterator end() const + { return iterator(); } + + void clear() + { this->it_.next_node_ = void_pointer(0); } + + iterator insert_after(iterator it, void_pointer m) + { + priv_get_ref(m) = priv_get_ref(it.next_node_); + priv_get_ref(it.next_node_) = m; + return iterator(m); + } + + void push_front(void_pointer m) + { + priv_get_ref(m) = this->it_.next_node_; + this->it_.next_node_ = m; + } + + void pop_front() + { ++it_; } + + void *front() const + { return detail::get_pointer(it_.next_node_); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if (after_this != before_begin && after_this != before_end && before_begin != before_end) { + void_pointer next_b = priv_get_ref(before_begin.next_node_); + void_pointer next_e = priv_get_ref(before_end.next_node_); + void_pointer next_p = priv_get_ref(after_this.next_node_); + priv_get_ref(before_begin.next_node_) = next_e; + priv_get_ref(before_end.next_node_) = next_p; + priv_get_ref(after_this.next_node_) = next_b; + } + } + + void swap(basic_multiallocation_slist &other_chain) + { + std::swap(this->it_, other_chain.it_); + } + + static iterator iterator_to(void_pointer p) + { return iterator(p); } + + void_pointer extract_data() + { + void_pointer ret = empty() ? void_pointer(0) : void_pointer(&*it_); + it_ = iterator(); + return ret; + } }; +template +class basic_multiallocation_cached_slist +{ + private: + basic_multiallocation_slist slist_; + typename basic_multiallocation_slist::iterator last_; + + basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &); + basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist) + + typedef typename basic_multiallocation_slist::void_pointer void_pointer; + typedef typename basic_multiallocation_slist::iterator iterator; + + basic_multiallocation_cached_slist() + : slist_(), last_(slist_.before_begin()) + {} +/* + basic_multiallocation_cached_slist(iterator first_node) + : slist_(first_node), last_(slist_.before_begin()) + { + iterator end; + while(first_node != end){ + ++last_; + } + }*/ + + basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2) + : slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin()) + {} + + basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + : slist_(), last_(slist_.before_begin()) + { this->swap(other); } + + basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + { + basic_multiallocation_cached_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return slist_.empty(); } + + iterator before_begin() const + { return slist_.before_begin(); } + + iterator begin() const + { return slist_.begin(); } + + iterator end() const + { return slist_.end(); } + + iterator last() const + { return last_; } + + void clear() + { + slist_.clear(); + last_ = slist_.before_begin(); + } + + iterator insert_after(iterator it, void_pointer m) + { + slist_.insert_after(it, m); + if(it == last_){ + last_ = slist_.iterator_to(m); + } + return iterator_to(m); + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(last_, m); } + + void pop_front() + { + if(last_ == slist_.begin()){ + last_ = slist_.before_begin(); + } + slist_.pop_front(); + } + + void *front() const + { return slist_.front(); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if(before_begin == before_end) + return; + if(after_this == last_){ + last_ = before_end; + } + slist_.splice_after(after_this, before_begin, before_end); + } + + void swap(basic_multiallocation_cached_slist &x) + { + slist_.swap(x.slist_); + using std::swap; + swap(last_, x.last_); + if(last_ == x.before_begin()){ + last_ = this->before_begin(); + } + if(x.last_ == this->before_begin()){ + x.last_ = x.before_begin(); + } + } + + static iterator iterator_to(void_pointer p) + { return basic_multiallocation_slist::iterator_to(p); } + + std::pair extract_data() + { + if(this->empty()){ + return std::pair(void_pointer(0), void_pointer(0)); + } + else{ + void_pointer p1 = slist_.extract_data(); + void_pointer p2 = void_pointer(&*last_); + last_ = iterator(); + return std::pair(p1, p2); + } + } +}; + +template +class basic_multiallocation_cached_counted_slist +{ + private: + MultiallocatorCachedSlist cached_slist_; + std::size_t size_; + + basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &); + basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist) + + typedef typename MultiallocatorCachedSlist::void_pointer void_pointer; + typedef typename MultiallocatorCachedSlist::iterator iterator; + + basic_multiallocation_cached_counted_slist() + : cached_slist_(), size_(0) + {} + + basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n) + : cached_slist_(p1, p2), size_(n) + {} + + basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + : cached_slist_(), size_(0) + { this->swap(other); } + + basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + { + basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n) + : cached_slist_(boost::interprocess::move(mem)), size_(n) + {} + + bool empty() const + { return cached_slist_.empty(); } + + std::size_t size() const + { return size_; } + + iterator before_begin() const + { return cached_slist_.before_begin(); } + + iterator begin() const + { return cached_slist_.begin(); } + + iterator end() const + { return cached_slist_.end(); } + + iterator last() const + { return cached_slist_.last(); } + + void clear() + { + cached_slist_.clear(); + size_ = 0; + } + + iterator insert_after(iterator it, void_pointer m) + { + iterator ret = cached_slist_.insert_after(it, m); + ++size_; + return ret; + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void pop_front() + { + cached_slist_.pop_front(); + --size_; + } + + void *front() const + { return cached_slist_.front(); } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end) + { + std::size_t n = static_cast(std::distance(before_begin, before_end)); + this->splice_after(after_this, x, before_begin, before_end, n); + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end, std::size_t n) + { + cached_slist_.splice_after(after_this, before_begin, before_end); + size_ += n; + x.size_ -= n; + } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.splice_after(after_this, x.before_begin(), x.last()); + size_ += x.size_; + x.size_ = 0; + } + + void swap(basic_multiallocation_cached_counted_slist &x) + { + cached_slist_.swap(x.cached_slist_); + using std::swap; + swap(size_, x.size_); + } + + static iterator iterator_to(void_pointer p) + { return MultiallocatorCachedSlist::iterator_to(p); } + + std::pair extract_data() + { + size_ = 0; + return cached_slist_.extract_data(); + } +}; + +template +struct cast_functor +{ + typedef typename detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + + +template +class transform_multiallocation_chain +{ +private: + + MultiallocationChain holder_; + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::pointer_to_other + ::type pointer; + + transform_multiallocation_chain(transform_multiallocation_chain &); + transform_multiallocation_chain &operator=(transform_multiallocation_chain &); + + static pointer cast(void_pointer p) + { + return pointer(static_cast(detail::get_pointer(p))); + } + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain) + + typedef transform_iterator + < typename MultiallocationChain::iterator + , detail::cast_functor > iterator; + + transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n) + : holder_(p1, p2, n) + {} + + transform_multiallocation_chain() + : holder_() + {} + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + : holder_() + { this->swap(other); } + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other) + : holder_(boost::interprocess::move(other)) + {} + + transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + { + transform_multiallocation_chain tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + void push_front(pointer mem) + { holder_.push_front(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + /* + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); } + */ + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n) + { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } + + void pop_front() + { holder_.pop_front(); } + + pointer front() const + { return cast(holder_.front()); } + + bool empty() const + { return holder_.empty(); } + + iterator before_begin() const + { return iterator(holder_.before_begin()); } + + iterator begin() const + { return iterator(holder_.begin()); } + + iterator end() const + { return iterator(holder_.end()); } + + iterator last() const + { return iterator(holder_.last()); } + + std::size_t size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } + + iterator insert_after(iterator it, pointer m) + { return iterator(holder_.insert_after(it.base(), m)); } + + static iterator iterator_to(pointer p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { return holder_.extract_data(); } + + MultiallocationChain extract_multiallocation_chain() + { + return MultiallocationChain(boost::interprocess::move(holder_)); + } +}; //!This class implements several allocation functions shared by different algorithms //!(aligned allocation, multiple allocation...). @@ -245,19 +569,16 @@ class memory_algorithm_common public: typedef typename MemoryAlgorithm::void_pointer void_pointer; typedef typename MemoryAlgorithm::block_ctrl block_ctrl; - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; - typedef multi_allocation_next multi_allocation_next_t; - typedef typename multi_allocation_next_t:: - multi_allocation_next_ptr multi_allocation_next_ptr; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; typedef memory_algorithm_common this_type; - static const std::size_t Alignment = MemoryAlgorithm::Alignment; - static const std::size_t MinBlockUnits = MemoryAlgorithm::MinBlockUnits; - static const std::size_t AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; - static const std::size_t AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; - static const std::size_t BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; - static const std::size_t BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; - static const std::size_t UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; + static const std::size_t Alignment = MemoryAlgorithm::Alignment; + static const std::size_t MinBlockUnits = MemoryAlgorithm::MinBlockUnits; + static const std::size_t AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; + static const std::size_t AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; + static const std::size_t BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; + static const std::size_t BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; + static const std::size_t UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; static void assert_alignment(const void *ptr) { assert_alignment((std::size_t)ptr); } @@ -280,12 +601,17 @@ class memory_algorithm_common static std::size_t multiple_of_units(std::size_t size) { return detail::get_rounded_size(size, Alignment); } - static multiallocation_iterator allocate_many + static multiallocation_chain allocate_many (MemoryAlgorithm *memory_algo, std::size_t elem_bytes, std::size_t n_elements) { return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); } + static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain) + { + return this_type::priv_deallocate_many(memory_algo, boost::interprocess::move(chain)); + } + 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) @@ -381,7 +707,7 @@ class memory_algorithm_common return true; } - static multiallocation_iterator allocate_many + static multiallocation_chain allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes , std::size_t n_elements @@ -403,7 +729,8 @@ class memory_algorithm_common std::size_t real_size; if(alignment <= Alignment){ - return memory_algo->priv_allocate(allocate_new, nbytes, nbytes, real_size).first; + return memory_algo->priv_allocate + (boost::interprocess::allocate_new, nbytes, nbytes, real_size).first; } if(nbytes > UsableByPreviousChunk) @@ -428,7 +755,8 @@ class memory_algorithm_common ); //Now allocate the buffer - void *buffer = memory_algo->priv_allocate(allocate_new, request, request, real_size).first; + void *buffer = memory_algo->priv_allocate + (boost::interprocess::allocate_new, request, request, real_size).first; if(!buffer){ return 0; } @@ -608,7 +936,7 @@ class memory_algorithm_common } private: - static multiallocation_iterator priv_allocate_many + static multiallocation_chain priv_allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes , std::size_t n_elements @@ -620,7 +948,7 @@ class memory_algorithm_common //Calculate the total size of all requests std::size_t total_request_units = 0; std::size_t elem_units = 0; - const std::size_t ptr_size_units = memory_algo->priv_get_total_units(sizeof(multi_allocation_next_ptr)); + const std::size_t ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer)); if(!sizeof_element){ elem_units = memory_algo->priv_get_total_units(*elem_sizes); elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; @@ -634,7 +962,8 @@ class memory_algorithm_common } } - multi_allocation_next_ptr first = 0, previous = 0; + multiallocation_chain chain; + std::size_t low_idx = 0; while(low_idx < n_elements){ std::size_t total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; @@ -645,7 +974,7 @@ class memory_algorithm_common std::size_t received_size; std::pair ret = memory_algo->priv_allocate - (allocate_new, min_allocation, total_bytes, received_size, 0); + (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0); if(!ret.first){ break; } @@ -710,33 +1039,28 @@ class memory_algorithm_common block_address += new_block->m_size*Alignment; total_used_units += new_block->m_size; //Check we have enough room to overwrite the intrusive pointer - assert((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(multi_allocation_next_t)); - multi_allocation_next_ptr p = new(memory_algo->priv_get_user_buffer(new_block))multi_allocation_next_t(0); - - if(!first){ - first = p; - } - else{ - previous->next_ = p; - } - previous = p; + assert((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer)); + void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0); + chain.push_back(p); ++low_idx; //prev_block = new_block; } //Sanity check BOOST_ASSERT(total_used_units == received_units); } - + if(low_idx != n_elements){ - while(first){ - multi_allocation_next_ptr prev = first; - first = first->next_; - memory_algo->priv_deallocate(detail::get_pointer(prev)); - } - return multiallocation_iterator(); + priv_deallocate_many(memory_algo, boost::interprocess::move(chain)); } - else{ - return multiallocation_iterator(first); + return boost::interprocess::move(chain); + } + + static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain) + { + while(!chain.empty()){ + void *addr = detail::get_pointer(chain.front()); + chain.pop_front(); + memory_algo->priv_deallocate(addr); } } }; 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 index b196faf..80c6209 100644 --- 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 @@ -18,8 +18,10 @@ #include #include +#include + #include -#include +#include #include #include #include @@ -67,7 +69,7 @@ class simple_seq_fit_impl private: struct block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; /*!Block control structure*/ @@ -149,7 +151,7 @@ class simple_seq_fit_impl void clear_free_memory(); std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::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); @@ -169,7 +171,7 @@ class simple_seq_fit_impl private: /*!Real allocation algorithm with min allocation option*/ - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -188,7 +190,7 @@ class simple_seq_fit_impl ,std::size_t &received_size); /*!Real expand to both sides implementation*/ - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -375,7 +377,7 @@ inline void* simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } template @@ -390,7 +392,7 @@ inline void* simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - allocation_command (allocation_type command, std::size_t min_size, + allocation_command (boost::interprocess::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) { @@ -398,7 +400,7 @@ inline std::pair simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- (void)backwards_multiple; - command &= ~expand_bwd; + command &= ~boost::interprocess::expand_bwd; if(!command) return std::pair(0, false); return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr); @@ -426,7 +428,7 @@ inline void* simple_seq_fit_impl:: //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; + void *addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; if(!addr){ //If this fails we will try the allocation through the segment //creator. @@ -447,7 +449,7 @@ inline void* simple_seq_fit_impl:: 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; + addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } } return addr; @@ -455,7 +457,7 @@ inline void* simple_seq_fit_impl:: template void* simple_seq_fit_impl:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -471,14 +473,14 @@ void* simple_seq_fit_impl:: return reuse_ptr; } - if(command & expand_fwd){ + if(command & boost::interprocess::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){ + if(command & boost::interprocess::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; @@ -534,13 +536,13 @@ void* simple_seq_fit_impl:: template std::pair simple_seq_fit_impl:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::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){ + if(command & boost::interprocess::shrink_in_place){ bool success = this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -565,14 +567,14 @@ std::pair simple_seq_fit_impl:: //Expand in place //reuse_ptr, limit_size, preferred_size, received_size // - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::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){ + if(command & boost::interprocess::allocate_new){ received_size = 0; while(block != root){ //Update biggest block pointers @@ -600,7 +602,7 @@ std::pair simple_seq_fit_impl:: } } //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return return_type(priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); } @@ -809,12 +811,12 @@ inline void* simple_seq_fit_impl:: std::size_t ignore; if(alignment <= Alignment){ - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::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; + void *buffer = priv_allocate(boost::interprocess::allocate_new, request, request, ignore).first; if(!buffer) return 0; else if ((((std::size_t)(buffer)) % alignment) == 0) 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 bd0773a..19ed89d 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 @@ -18,8 +18,10 @@ #include #include +#include + #include -#include +#include #include #include #include @@ -61,15 +63,13 @@ class simple_seq_fit_impl typedef MutexFamily mutex_family; //!Pointer type to be used with the rest of the Interprocess framework typedef VoidPointer void_pointer; - - typedef detail::basic_multiallocation_iterator - multiallocation_iterator; - typedef detail::basic_multiallocation_chain - multiallocation_chain; + typedef detail::basic_multiallocation_cached_slist multialloc_cached; + typedef detail::basic_multiallocation_cached_counted_slist + multiallocation_chain; private: class block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; class block_ctrl; @@ -109,7 +109,6 @@ class simple_seq_fit_impl std::size_t m_extra_hdr_bytes; } m_header; - friend class detail::basic_multiallocation_iterator; friend class detail::memory_algorithm_common; typedef detail::memory_algorithm_common algo_impl_t; @@ -134,13 +133,27 @@ class simple_seq_fit_impl /// @cond //!Multiple element allocation, same size - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); + multiallocation_chain + allocate_many(std::size_t elem_bytes, std::size_t num_elements) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_bytes, num_elements); + } //!Multiple element allocation, different size - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + multiallocation_chain + allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + } //!Multiple element deallocation - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); /// @endcond @@ -171,12 +184,12 @@ class simple_seq_fit_impl template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair - raw_allocation_command (allocation_type command, std::size_t limit_size, + raw_allocation_command (boost::interprocess::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 sizeof_object = 1); @@ -196,13 +209,13 @@ class simple_seq_fit_impl static block_ctrl *priv_get_block(const void *ptr); //!Real allocation algorithm with min allocation option - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr = 0); - std::pair priv_allocation_command(allocation_type command + std::pair priv_allocation_command(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -233,7 +246,7 @@ class simple_seq_fit_impl ,std::size_t &received_size); //!Real expand to both sides implementation - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -386,7 +399,7 @@ void simple_seq_fit_impl::shrink_to_fit() if(!m_header.m_allocated){ assert(prev == root); std::size_t ignore; - unique_block = priv_allocate(allocate_new, 0, 0, ignore).first; + unique_block = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; if(!unique_block) return; last = detail::get_pointer(m_header.m_root.m_next); @@ -547,7 +560,7 @@ inline void* simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } template @@ -564,7 +577,7 @@ inline void* simple_seq_fit_impl:: template template inline std::pair simple_seq_fit_impl:: - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { @@ -577,13 +590,13 @@ inline std::pair simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects, std::size_t preferred_objects,std::size_t &received_objects, void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) return std::pair(static_cast(0), 0); - if(command & try_shrink_in_place){ + if(command & boost::interprocess::try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object , preferred_objects*sizeof_object, received_objects); @@ -596,11 +609,11 @@ inline std::pair simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - priv_allocation_command (allocation_type command, std::size_t limit_size, + priv_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size, std::size_t &received_size, void *reuse_ptr, std::size_t sizeof_object) { - command &= ~expand_bwd; + command &= ~boost::interprocess::expand_bwd; if(!command) return std::pair(static_cast(0), false); std::pair ret; @@ -634,7 +647,7 @@ inline std::size_t simple_seq_fit_impl:: template void* simple_seq_fit_impl:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -650,14 +663,14 @@ void* simple_seq_fit_impl:: return reuse_ptr; } - if(command & expand_fwd){ + if(command & boost::interprocess::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){ + if(command & boost::interprocess::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; @@ -711,43 +724,20 @@ void* simple_seq_fit_impl:: return 0; } -template -inline typename simple_seq_fit_impl::multiallocation_iterator - simple_seq_fit_impl:: - allocate_many(std::size_t elem_bytes, std::size_t num_elements) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t:: - allocate_many(this, elem_bytes, num_elements); -} - template inline void simple_seq_fit_impl:: - deallocate_many(typename simple_seq_fit_impl::multiallocation_iterator it) + deallocate_many(typename simple_seq_fit_impl::multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - while(it){ - void *addr = &*it; - ++it; + while(!chain.empty()){ + void *addr = chain.front(); + chain.pop_front(); this->priv_deallocate(addr); } } -template -inline typename simple_seq_fit_impl::multiallocation_iterator - simple_seq_fit_impl:: - allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); -} - template inline std::size_t simple_seq_fit_impl:: priv_get_total_units(std::size_t userbytes) @@ -759,13 +749,13 @@ inline std::size_t simple_seq_fit_impl:: template std::pair simple_seq_fit_impl:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::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){ + if(command & boost::interprocess::shrink_in_place){ bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -790,7 +780,7 @@ std::pair simple_seq_fit_impl:: //Expand in place //reuse_ptr, limit_size, preferred_size, received_size // - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ void *ret = priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, true); if(ret){ @@ -799,7 +789,7 @@ std::pair simple_seq_fit_impl:: } } - if(command & allocate_new){ + if(command & boost::interprocess::allocate_new){ received_size = 0; while(block != root){ //Update biggest block pointers @@ -835,7 +825,7 @@ std::pair simple_seq_fit_impl:: } } //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return_type ret (priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); algo_impl_t::assert_alignment(ret.first); diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 5379139..d4299b3 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -18,9 +18,11 @@ #include #include +#include + #include #include -#include +#include #include #include #include @@ -40,15 +42,7 @@ #include #include -//#define BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY - -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY #include -#else -//#include -//#include -#include -#endif //!\file //!Describes a best-fit algorithm based in an intrusive red-black tree used to allocate @@ -75,35 +69,26 @@ class rbtree_best_fit typedef MutexFamily mutex_family; //!Pointer type to be used with the rest of the Interprocess framework typedef VoidPointer void_pointer; - typedef detail::basic_multiallocation_iterator - multiallocation_iterator; - typedef detail::basic_multiallocation_chain - multiallocation_chain; + //typedef detail::basic_multiallocation_cached_counted_slist multiallocation_chain; + + typedef detail::basic_multiallocation_cached_slist multialloc_cached; + typedef detail::basic_multiallocation_cached_counted_slist + multiallocation_chain; /// @cond private: struct block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type char_ptr; -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY typedef typename bi::make_set_base_hook -#else -// typedef typename bi::make_splay_set_base_hook -// typedef typename bi::make_avl_set_base_hook - typedef typename bi::make_sg_set_base_hook -#endif < bi::void_pointer , bi::optimize_size , bi::link_mode >::type TreeHook; - typedef detail::multi_allocation_next multi_allocation_next_t; - typedef typename multi_allocation_next_t:: - multi_allocation_next_ptr multi_allocation_next_ptr; - struct SizeHolder { //!This block's memory size (including block_ctrl @@ -138,13 +123,7 @@ class rbtree_best_fit //!Shared interprocess_mutex to protect memory allocate/deallocate typedef typename MutexFamily::mutex_type interprocess_mutex; -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY typedef typename bi::make_multiset -#else - //typedef typename bi::make_splay_multiset - //typedef typename bi::make_avl_multiset - typedef typename bi::make_sg_multiset -#endif >::type Imultiset; typedef typename Imultiset::iterator imultiset_iterator; @@ -163,7 +142,6 @@ class rbtree_best_fit std::size_t m_size; } m_header; - friend class detail::basic_multiallocation_iterator; friend class detail::memory_algorithm_common; typedef detail::memory_algorithm_common algo_impl_t; @@ -192,13 +170,27 @@ class rbtree_best_fit //Experimental. Dont' use //!Multiple element allocation, same size - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) + { + + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_bytes, num_elements); + } //!Multiple element allocation, different size - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) + { + + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + } //!Multiple element allocation, different size - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); /// @endcond @@ -231,12 +223,12 @@ class rbtree_best_fit template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair - raw_allocation_command (allocation_type command, std::size_t limit_object, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_object, std::size_t preferred_object,std::size_t &received_object, void *reuse_ptr = 0, std::size_t sizeof_object = 1); @@ -252,13 +244,13 @@ class rbtree_best_fit static std::size_t priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes); std::pair - priv_allocation_command(allocation_type command, std::size_t limit_size, + priv_allocation_command(boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr, std::size_t sizeof_object); //!Real allocation algorithm with min allocation option - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size @@ -281,7 +273,7 @@ class rbtree_best_fit ,std::size_t &received_size); //!Real expand to both sides implementation - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -463,7 +455,7 @@ void rbtree_best_fit::shrink_to_fit() block_ctrl *last_block; if(priv_next_block(first_block) == old_end_block){ std::size_t ignore; - unique_buffer = priv_allocate(allocate_new, 0, 0, ignore).first; + unique_buffer = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; if(!unique_buffer) return; algo_impl_t::assert_alignment(unique_buffer); @@ -631,7 +623,7 @@ inline void* rbtree_best_fit:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - void * ret = priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + void * ret = priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; return ret; } @@ -648,7 +640,7 @@ inline void* rbtree_best_fit:: template template inline std::pair rbtree_best_fit:: - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { @@ -661,13 +653,13 @@ inline std::pair rbtree_best_fit inline std::pair rbtree_best_fit:: - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects, std::size_t preferred_objects,std::size_t &received_objects, void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) return std::pair(static_cast(0), 0); - if(command & try_shrink_in_place){ + if(command & boost::interprocess::try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object , preferred_objects*sizeof_object, received_objects); @@ -681,7 +673,7 @@ inline std::pair rbtree_best_fit inline std::pair rbtree_best_fit:: - priv_allocation_command (allocation_type command, std::size_t limit_size, + priv_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, void *reuse_ptr, std::size_t sizeof_object) { @@ -732,7 +724,7 @@ inline void rbtree_best_fit::zero_free_m template void* rbtree_best_fit:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -741,7 +733,7 @@ void* rbtree_best_fit:: ,std::size_t backwards_multiple) { algo_impl_t::assert_alignment(reuse_ptr); - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) return reuse_ptr; } @@ -756,7 +748,7 @@ void* rbtree_best_fit:: BOOST_ASSERT(0 == (preferred_size % backwards_multiple)); } - if(command & expand_bwd){ + if(command & boost::interprocess::expand_bwd){ //Obtain the real size of the block block_ctrl *reuse = priv_get_block(reuse_ptr); @@ -791,7 +783,7 @@ void* rbtree_best_fit:: //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 - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ std::size_t received_size2; if(!priv_expand(reuse_ptr, received_size, received_size, received_size2)){ assert(0); @@ -873,45 +865,19 @@ void* rbtree_best_fit:: return 0; } -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: - allocate_many(std::size_t elem_bytes, std::size_t num_elements) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_bytes, num_elements); -} - template inline void rbtree_best_fit:: - deallocate_many(typename rbtree_best_fit::multiallocation_iterator it) + deallocate_many(typename rbtree_best_fit::multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - while(it){ - void *addr = &*it; - ++it; - this->priv_deallocate(addr); - } -} - -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: - allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + algo_impl_t::deallocate_many(this, boost::interprocess::move(chain)); } template std::pair rbtree_best_fit:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size @@ -919,9 +885,9 @@ std::pair rbtree_best_fit: ,std::size_t backwards_multiple) { //Remove me. Forbid backwards allocation - //command &= (~expand_bwd); + //command &= (~boost::interprocess::expand_bwd); - if(command & shrink_in_place){ + if(command & boost::interprocess::shrink_in_place){ bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -940,14 +906,14 @@ std::pair rbtree_best_fit: std::size_t limit_units = priv_get_total_units(limit_size); //Expand in place - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ void *ret = priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, true, backwards_multiple); if(ret) return return_type(ret, true); } - if(command & allocate_new){ + if(command & boost::interprocess::allocate_new){ size_block_ctrl_compare comp; imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp)); @@ -965,7 +931,7 @@ std::pair rbtree_best_fit: //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return return_type(priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); } diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index e89ef76..c1ae9f4 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -162,7 +162,11 @@ class offset_ptr //!Dereferencing operator, if it is a null offset_ptr behavior //! is undefined. Never throws. reference operator* () const - { return *(this->get()); } + { + pointer p = this->get(); + reference r = *p; + return r; + } //!Indexing operator. //!Never throws. diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index a9836f6..972e08c 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -72,8 +72,7 @@ class segment_manager_base /// @cond //Experimental. Don't use - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; - typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; /// @endcond @@ -123,38 +122,40 @@ class segment_manager_base //Experimental. Dont' use. //!Allocates n_elements of //!elem_size bytes. Throws bad_alloc on failure. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) { - multiallocation_iterator ret = MemoryAlgorithm::allocate_many(elem_bytes, num_elements); - if(!ret) throw bad_alloc(); - return ret; + multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements)); + if(mem.empty()) throw bad_alloc(); + return boost::interprocess::move(mem); } //!Allocates n_elements, each one of //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure. - multiallocation_iterator allocate_many + multiallocation_chain allocate_many (const std::size_t *element_lenghts, std::size_t n_elements, std::size_t sizeof_element = 1) { - multiallocation_iterator ret = MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element); - if(!ret) throw bad_alloc(); - return ret; + multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element)); + if(mem.empty()) throw bad_alloc(); + return boost::interprocess::move(mem); } //!Allocates n_elements of //!elem_size bytes. Returns a default constructed iterator on failure. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t) + multiallocation_chain allocate_many + (std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t) { return MemoryAlgorithm::allocate_many(elem_bytes, num_elements); } //!Allocates n_elements, each one of //!element_lenghts[i]*sizeof_element bytes. //!Returns a default constructed iterator on failure. - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t) + multiallocation_chain allocate_many + (const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t) { return MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element); } //!Deallocates elements pointed by the //!multiallocation iterator range. - void deallocate_many(multiallocation_iterator it) - { MemoryAlgorithm::deallocate_many(it); } + void deallocate_many(multiallocation_chain chain) + { MemoryAlgorithm::deallocate_many(boost::interprocess::move(chain)); } /// @endcond @@ -185,27 +186,27 @@ class segment_manager_base template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0) { std::pair ret = MemoryAlgorithm::allocation_command - ( command | nothrow_allocation, limit_size, preferred_size, received_size + ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size , reuse_ptr); - if(!(command & nothrow_allocation) && !ret.first) + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) throw bad_alloc(); return ret; } std::pair - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::allocation_type command, std::size_t limit_objects, std::size_t preferred_objects,std::size_t &received_objects, void *reuse_ptr = 0, std::size_t sizeof_object = 1) { std::pair ret = MemoryAlgorithm::raw_allocation_command - ( command | nothrow_allocation, limit_objects, preferred_objects, received_objects + ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects , reuse_ptr, sizeof_object); - if(!(command & nothrow_allocation) && !ret.first) + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) throw bad_alloc(); return ret; } @@ -297,7 +298,7 @@ class segment_manager_base //scoped_lock guard(m_header); //------------------------------- - if(ctrl_data->allocation_type() != anonymous_type){ + if(ctrl_data->alloc_type() != anonymous_type){ //This is not an anonymous object, the pointer is wrong! assert(0); } @@ -311,11 +312,6 @@ class segment_manager_base /// @endcond }; -//These pointers are the ones the user will use to -//indicate previous allocation types -static const detail::anonymous_instance_t * anonymous_instance = 0; -static const detail::unique_instance_t * unique_instance = 0; - //!This object is placed in the beginning of memory segment and //!implements the allocation (named or anonymous) of portions //!of the segment. This object contains two indexes that @@ -351,7 +347,6 @@ class segment_manager typedef MemoryAlgorithm memory_algorithm; typedef typename Base::void_pointer void_pointer; typedef CharType char_type; - typedef typename Base::multiallocation_iterator multiallocation_iterator; typedef segment_manager_base segment_manager_base_type; @@ -672,6 +667,7 @@ class segment_manager typename deleter::type get_deleter() { return typename deleter::type(this); } + /// @cond //!Generic named/anonymous new function. Offers all the possibilities, @@ -753,7 +749,7 @@ class segment_manager void priv_destroy_ptr(const void *ptr, detail::in_place_interface &dtor) { block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment); - switch(ctrl_data->allocation_type()){ + switch(ctrl_data->alloc_type()){ case anonymous_type: this->prot_anonymous_destroy(ptr, dtor); break; @@ -779,7 +775,7 @@ class segment_manager //!functions. Does not throw static const CharType *priv_get_instance_name(block_header_t *ctrl_data) { - allocation_type type = ctrl_data->allocation_type(); + boost::interprocess::allocation_type type = ctrl_data->alloc_type(); if(type != named_type){ assert((type == anonymous_type && ctrl_data->m_num_char == 0) || (type == unique_type && ctrl_data->m_num_char != 0) ); @@ -805,8 +801,8 @@ class segment_manager static instance_type priv_get_instance_type(block_header_t *ctrl_data) { //Get header - assert((instance_type)ctrl_data->allocation_type() < max_allocation_type); - return (instance_type)ctrl_data->allocation_type(); + assert((instance_type)ctrl_data->alloc_type() < max_allocation_type); + return (instance_type)ctrl_data->alloc_type(); } static std::size_t priv_get_reserved_bytes() @@ -1311,18 +1307,13 @@ 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 priv_get_lock(bool use_lock) { scoped_lock local(m_header, defer_lock); if(use_lock){ local.lock(); } - return local; + return scoped_lock(boost::interprocess::move(local)); } //!This struct includes needed data and derives from @@ -1338,6 +1329,7 @@ class segment_manager , m_unique_index(restricted_segment_mngr) {} } m_header; + /// @endcond }; diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index f84c0c7..b1a9b34 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -22,10 +22,11 @@ #include #include #include -#include //std::remove #include -#ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS +#if defined(BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS) +# include //System V shared memory... +#elif defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) # include //O_CREAT, O_*... # include //shm_xxx # include //ftruncate, close @@ -46,11 +47,12 @@ class shared_memory_object { /// @cond //Non-copyable and non-assignable - shared_memory_object(const shared_memory_object &); - shared_memory_object &operator=(const shared_memory_object &); + shared_memory_object(shared_memory_object &); + shared_memory_object &operator=(shared_memory_object &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(shared_memory_object) //!Default constructor. Represents an empty shared_memory_object. shared_memory_object(); @@ -74,44 +76,22 @@ class shared_memory_object //!Moves the ownership of "moved"'s shared memory object to *this. //!After the call, "moved" does not represent any shared memory object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_memory_object(detail::moved_object moved) - : m_handle(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - shared_memory_object(shared_memory_object &&moved) + shared_memory_object(BOOST_INTERPROCESS_RV_REF(shared_memory_object) moved) : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_memory_object &operator= - (detail::moved_object moved) + shared_memory_object &operator=(BOOST_INTERPROCESS_RV_REF(shared_memory_object) moved) { - shared_memory_object tmp(moved); + shared_memory_object tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - shared_memory_object &operator=(shared_memory_object &&moved) - { - shared_memory_object tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif //!Swaps the shared_memory_objects. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } - void swap(shared_memory_object &other); - #else - void swap(shared_memory_object &&other); - #endif + void swap(shared_memory_object &moved); //!Erases a shared memory object from the system. //!Returns false on error. Never throws @@ -173,11 +153,7 @@ inline const char *shared_memory_object::get_name() const inline bool shared_memory_object::get_size(offset_t &size) const { return detail::get_file_size((file_handle_t)m_handle, size); } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void shared_memory_object::swap(shared_memory_object &other) -#else -inline void shared_memory_object::swap(shared_memory_object &&other) -#endif { std::swap(m_handle, other.m_handle); std::swap(m_mode, other.m_mode); @@ -185,7 +161,9 @@ inline void shared_memory_object::swap(shared_memory_object &&other) } inline mapping_handle_t shared_memory_object::get_mapping_handle() const -{ return detail::mapping_handle_from_file_handle(m_handle); } +{ + return detail::mapping_handle_from_file_handle(m_handle); +} inline mode_t shared_memory_object::get_mode() const { return m_mode; } @@ -229,7 +207,6 @@ inline bool shared_memory_object::priv_open_or_create throw interprocess_exception(err); } - //detail::delete_file_on_reboot_if_possible(shmfile.c_str()); m_mode = mode; return true; } @@ -240,7 +217,7 @@ inline bool shared_memory_object::remove(const char *filename) //Make sure a temporary path is created for shared memory std::string shmfile; detail::tmp_filename(filename, shmfile); - return std::remove(shmfile.c_str()) == 0; + return detail::delete_file(shmfile.c_str()) == 0; } catch(...){ return false; @@ -355,14 +332,6 @@ 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 diff --git a/include/boost/interprocess/smart_ptr/deleter.hpp b/include/boost/interprocess/smart_ptr/deleter.hpp index 5909808..c223e4f 100644 --- a/include/boost/interprocess/smart_ptr/deleter.hpp +++ b/include/boost/interprocess/smart_ptr/deleter.hpp @@ -20,6 +20,7 @@ #include #include #include +#include //!\file //!Describes the functor to delete objects from the segment. @@ -35,11 +36,11 @@ template class deleter { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type segment_manager_pointer; segment_manager_pointer mp_mngr; diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 8e4db51..39a64da 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -41,20 +42,20 @@ template class shared_count { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: typedef sp_counted_impl_pd counted_impl; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_impl_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_base_ptr; typedef typename VoidAllocator::template rebind ::other counted_impl_allocator; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; pointer m_px; @@ -212,14 +213,14 @@ template class weak_count { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: typedef sp_counted_impl_pd counted_impl; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_impl_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_base_ptr; pointer m_px; diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp index 51f44e9..9d799fa 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace boost { @@ -33,6 +34,34 @@ namespace interprocess { namespace detail { +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_ptr_dealloc_functor +{ + typedef typename Allocator::pointer pointer; + typedef detail::integral_constant::value> alloc_version; + typedef detail::integral_constant allocator_v1; + typedef detail::integral_constant allocator_v2; + + private: + void priv_deallocate(const typename Allocator::pointer &p, allocator_v1) + { m_alloc.deallocate(p, 1); } + + void priv_deallocate(const typename Allocator::pointer &p, allocator_v2) + { m_alloc.deallocate_one(p); } + + public: + Allocator& m_alloc; + + scoped_ptr_dealloc_functor(Allocator& a) + : m_alloc(a) {} + + void operator()(pointer ptr) + { if (ptr) priv_deallocate(ptr, alloc_version()); } +}; + template class sp_counted_impl_pd : public sp_counted_base @@ -50,10 +79,10 @@ class sp_counted_impl_pd sp_counted_impl_pd( sp_counted_impl_pd const & ); sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; typedef typename D::pointer pointer; @@ -73,7 +102,7 @@ class sp_counted_impl_pd { return const_allocator_pointer(&static_cast(*this)); } void dispose() // nothrow - { static_cast(*this)(m_ptr); } + { static_cast(*this)(m_ptr); } void destroy() // nothrow { @@ -83,8 +112,8 @@ class sp_counted_impl_pd BOOST_ASSERT(a_copy == *this); this_pointer this_ptr (this); //Do it now! - scoped_ptr > deallocator(this_ptr, a_copy); + scoped_ptr< this_type, scoped_ptr_dealloc_functor > + deleter(this_ptr, a_copy); typedef typename this_allocator::value_type value_type; detail::get_pointer(this_ptr)->~value_type(); } diff --git a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp index 5ebac3c..86df285 100644 --- a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp @@ -22,6 +22,7 @@ #include #include +#include #include // for std::less #include // for std::basic_ostream @@ -49,7 +50,7 @@ class intrusive_ptr { public: //!Provides the type of the internal stored pointer. - typedef typename detail::pointer_to_other::type pointer; + typedef typename boost::pointer_to_other::type pointer; //!Provides the type of the stored pointer. typedef T element_type; diff --git a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp index a21ba60..74fe1d6 100644 --- a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp @@ -19,6 +19,7 @@ #include #include #include +#include //!\file //!Describes the smart pointer scoped_ptr @@ -54,7 +55,7 @@ class scoped_ptr typedef typename detail::pointer_type::type pointer; //!Provides the type of the internal stored pointer -// typedef typename detail::pointer_to_other +// typedef typename boost::pointer_to_other // ::type pointer; //!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d. diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index ddf6f7d..5d650e2 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include // for std::swap #include // for std::less @@ -96,18 +97,20 @@ class shared_ptr typedef T element_type; typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; typedef typename detail::add_reference ::type reference; typedef typename detail::add_reference ::type const_reference; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(shared_ptr) + //!Constructs an empty shared_ptr. //!Use_count() == 0 && get()== 0. shared_ptr() @@ -122,7 +125,7 @@ class shared_ptr { //Check that the pointer passed is of the same type that //the pointer the allocator defines or it's a raw pointer - typedef typename detail::pointer_to_other::type ParameterPointer; + typedef typename boost::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); detail::sp_enable_shared_from_this( m_pn, detail::get_pointer(p), detail::get_pointer(p) ); @@ -153,15 +156,9 @@ class shared_ptr //!Move-Constructs a shared_ptr that takes ownership of other resource and //!other is put in default-constructed state. //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - explicit shared_ptr(detail::moved_object other) - : m_pn() - { this->swap(other.get()); } - #else - explicit shared_ptr(shared_ptr &&other) + explicit shared_ptr(BOOST_INTERPROCESS_RV_REF(shared_ptr) other) : m_pn() { this->swap(other); } - #endif /// @cond template @@ -198,19 +195,11 @@ class shared_ptr //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). //!Never throws - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_ptr & operator=(detail::moved_object other) // never throws + shared_ptr & operator=(BOOST_INTERPROCESS_RV_REF(shared_ptr) 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); @@ -226,7 +215,7 @@ class shared_ptr { //Check that the pointer passed is of the same type that //the pointer the allocator defines or it's a raw pointer - typedef typename detail::pointer_to_other::type ParameterPointer; + typedef typename boost::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); this_type(p, a, d).swap(*this); @@ -371,26 +360,6 @@ inline typename managed_shared_ptr::type ); } - -/* -// get_deleter (experimental) -template -typename detail::pointer_to_other, Deleter>::type - 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 064af09..36a7507 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -88,6 +88,8 @@ class unique_ptr /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(unique_ptr) + typedef T element_type; typedef D deleter_type; typedef typename detail::pointer_type::type pointer; @@ -142,7 +144,7 @@ class unique_ptr //! //!After the construction, u no longer owns a pointer. //![ Note: The deleter constructor can be implemented with - //!std::detail::forward_impl. -end note ] + //! boost::interprocess::forward. -end note ] //! //!Postconditions: get() == value u.get() had before the construction. //!get_deleter() returns a reference to the internally stored deleter which @@ -150,15 +152,9 @@ class unique_ptr //!deleter() and u.get_deleter() both reference the same lvalue deleter. //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr(detail::moved_object u) - : ptr_(u.get().release(), detail::move_impl(u.get().get_deleter())) + unique_ptr(BOOST_INTERPROCESS_RV_REF(unique_ptr) u) + : ptr_(u.release(), boost::interprocess::forward(u.get_deleter())) {} - #else - unique_ptr(unique_ptr &&u) - : ptr_(u.release(), detail::forward_impl(u.get_deleter())) - {} - #endif //!Requires: If D is not a reference type, construction of the deleter //!D from an rvalue of type E must be well formed @@ -179,9 +175,8 @@ class unique_ptr //!was constructed from u.get_deleter(). //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template - unique_ptr(detail::moved_object > u, + unique_ptr(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(unique_ptr, U, E) u, typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && @@ -192,24 +187,8 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u.get()).release(), detail::move_impl(u.get().get_deleter())) + : ptr_(const_cast&>(u).release(), boost::interprocess::move(u.get_deleter())) {} - #else - template - unique_ptr(unique_ptr && u, - typename detail::enable_if_c< - detail::is_convertible::pointer, pointer>::value && - detail::is_convertible::value && - ( - !detail::is_reference::value || - detail::is_same::value - ) - , - nat - >::type = nat()) - : ptr_(const_cast&>(u).release(), detail::forward_impl(u.get_deleter())) - {} - #endif //!Effects: If get() == 0 there are no effects. Otherwise get_deleter()(get()). //! @@ -230,21 +209,12 @@ class unique_ptr //!Returns: *this. //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr& operator=(detail::moved_object u) - { - reset(u.get().release()); - ptr_.second() = detail::move_impl(u.get().get_deleter()); - return *this; - } - #else - unique_ptr& operator=(unique_ptr && u) + unique_ptr& operator=(BOOST_INTERPROCESS_RV_REF(unique_ptr) u) { reset(u.release()); - ptr_.second() = detail::move_impl(u.get_deleter()); + ptr_.second() = boost::interprocess::move(u.get_deleter()); return *this; } - #endif //!Requires: Assignment of the deleter D from an rvalue D must not //!throw an exception. U* must be implicitly convertible to T*. @@ -261,21 +231,12 @@ class unique_ptr //! //!Throws: nothing. template - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr& operator=(detail::moved_object > mu) - { - reset(mu.get().release()); - ptr_.second() = detail::move_impl(mu.get().get_deleter()); - return *this; - } - #else - unique_ptr& operator=(unique_ptr && u) + unique_ptr& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(unique_ptr, U, E) u) { reset(u.release()); - ptr_.second() = detail::move_impl(u.get_deleter()); + ptr_.second() = boost::interprocess::move(u.get_deleter()); return *this; } - #endif //!Assigns from the literal 0 or NULL. //! @@ -359,23 +320,14 @@ class unique_ptr //!Effects: The stored pointers of this and u are exchanged. //! The stored deleters are swapped (unqualified). //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(unique_ptr& u) { ptr_.swap(u.ptr_); } - void swap(detail::moved_object mu) - { ptr_.swap(mu.get().ptr_); } - #else - void swap(unique_ptr&&u) - { ptr_.swap(u.ptr_); } - #endif - /// @cond private: boost::compressed_pair ptr_; - //This private constructor avoids moving from non-const lvalues - unique_ptr(const unique_ptr&); + unique_ptr(unique_ptr&); template unique_ptr(unique_ptr&); template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); @@ -570,16 +522,6 @@ template inline bool operator>=(const unique_ptr& x, const unique_ptr& y) { return x.get() >= y.get(); } -/// @cond - -//!This class has move constructor -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - //!Returns the type of a unique pointer //!of type T with boost::interprocess::deleter deleter @@ -597,20 +539,11 @@ 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 +inline typename managed_unique_ptr::type make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory) { - typename managed_unique_ptr::type to_return - ( constructed_object - , managed_memory.template get_deleter() - ); - return to_return; + return typename managed_unique_ptr::type + (constructed_object, managed_memory.template get_deleter()); } } //namespace interprocess{ diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index d69e4fe..4019f47 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -22,6 +22,7 @@ #include #include #include +#include //!\file //!Describes the smart pointer weak_ptr. @@ -53,7 +54,7 @@ class weak_ptr private: // Borland 5.5.1 specific workarounds typedef weak_ptr this_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; typedef typename detail::add_reference ::type reference; diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index b40e3c7..32b236f 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -94,11 +94,11 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_enter_mut, abs_time); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } else{ InternalLock dummy(m_enter_mut); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } if(!lock) @@ -161,15 +161,18 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_check_mut, abs_time); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } else{ InternalLock dummy(m_check_mut); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } - if(!lock) - return false; + if(!lock){ + timed_out = true; + unlock_enter_mut = true; + break; + } //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 (const_cast(&m_command), SLEEP, NOTIFY_ONE); diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp index c659e20..c6bc907 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -39,8 +39,11 @@ inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} inline void interprocess_recursive_mutex::lock() { - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)){ + typedef detail::OS_systemwide_thread_id_t handle_t; + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)){ if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -49,15 +52,18 @@ inline void interprocess_recursive_mutex::lock() } else{ m_mutex.lock(); - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; } } inline bool interprocess_recursive_mutex::try_lock() { - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it + typedef detail::OS_systemwide_thread_id_t handle_t; + handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -66,7 +72,7 @@ inline bool interprocess_recursive_mutex::try_lock() return true; } if(m_mutex.try_lock()){ - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } @@ -75,12 +81,15 @@ inline bool interprocess_recursive_mutex::try_lock() inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) { + typedef detail::OS_systemwide_thread_id_t handle_t; if(abs_time == boost::posix_time::pos_infin){ this->lock(); return true; } - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -89,7 +98,7 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt return true; } if(m_mutex.timed_lock(abs_time)){ - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } @@ -98,10 +107,16 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt inline void interprocess_recursive_mutex::unlock() { - assert(detail::equal_systemwide_thread_id(detail::get_current_systemwide_thread_id(), m_nOwner)); + typedef detail::OS_systemwide_thread_id_t handle_t; + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + (void)old_id; + assert(detail::equal_systemwide_thread_id(thr_id, old_id)); --m_nLockCount; if(!m_nLockCount){ - m_nOwner = detail::get_invalid_systemwide_thread_id(); + const handle_t new_id(detail::get_invalid_systemwide_thread_id()); + detail::systemwide_thread_id_copy(new_id, m_nOwner); m_mutex.unlock(); } } diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 75a2693..d0f329d 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -29,19 +29,6 @@ namespace boost { namespace interprocess { -///@cond - -class file_lock; - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - -///@endcond //!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 @@ -56,6 +43,7 @@ class file_lock file_lock &operator=(const file_lock &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_lock) //!Constructs an empty file mapping. //!Does not throw @@ -70,28 +58,16 @@ class file_lock //!Moves the ownership of "moved"'s file mapping object to *this. //!After the call, "moved" does not represent any file mapping object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_lock(detail::moved_object moved) - : m_file_hnd(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - file_lock(file_lock &&moved) + file_lock(BOOST_INTERPROCESS_RV_REF(file_lock) moved) : m_file_hnd(file_handle_t(detail::invalid_file())) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s file mapping to *this. //!After the call, "moved" does not represent any file mapping. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_lock &operator=(detail::moved_object m_other) + file_lock &operator=(BOOST_INTERPROCESS_RV_REF(file_lock) moved) { - file_lock &moved = m_other.get(); - #else - file_lock &operator=(file_lock &&moved) - { - #endif - file_lock tmp(detail::move_impl(moved)); + file_lock tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -101,13 +77,7 @@ class file_lock //!Swaps two file_locks. //!Does not throw. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(file_lock &other) - #else - void swap(file_lock &&other) - #endif { file_handle_t tmp = m_file_hnd; m_file_hnd = other.m_file_hnd; diff --git a/include/boost/interprocess/sync/interprocess_barrier.hpp b/include/boost/interprocess/sync/interprocess_barrier.hpp index 6ba5a66..3133668 100644 --- a/include/boost/interprocess/sync/interprocess_barrier.hpp +++ b/include/boost/interprocess/sync/interprocess_barrier.hpp @@ -26,6 +26,8 @@ #ifndef BOOST_INTERPROCESS_BARRIER_HPP #define BOOST_INTERPROCESS_BARRIER_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -48,6 +50,8 @@ # include +/// @endcond + namespace boost { namespace interprocess { diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 5c4a123..73b9e67 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -15,6 +15,8 @@ # pragma once #endif +/// @cond + #include #include @@ -38,6 +40,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes process-shared variables interprocess_condition class diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index 5717725..8d7192b 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -27,6 +27,8 @@ #ifndef BOOST_INTERPROCESS_MUTEX_HPP #define BOOST_INTERPROCESS_MUTEX_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -48,6 +50,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes a mutex class that can be placed in memory shared by //!several processes. @@ -110,7 +114,7 @@ class interprocess_mutex volatile boost::uint32_t m_s; #elif defined(BOOST_INTERPROCESS_USE_POSIX) pthread_mutex_t m_mut; - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index 13c0eb0..96369cc 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -27,6 +27,8 @@ #ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP #define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -50,6 +52,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes @@ -106,10 +110,10 @@ class interprocess_recursive_mutex #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) interprocess_mutex m_mutex; unsigned int m_nLockCount; - detail::OS_systemwide_thread_id_t m_nOwner; + volatile detail::OS_systemwide_thread_id_t m_nOwner; #else //#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) pthread_mutex_t m_mut; - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp index b10eb89..0fe15ad 100644 --- a/include/boost/interprocess/sync/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -11,6 +11,8 @@ #ifndef BOOST_INTERPROCESS_SEMAPHORE_HPP #define BOOST_INTERPROCESS_SEMAPHORE_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -22,7 +24,7 @@ #include #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ - (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES)) + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES)) #include //O_CREAT, O_*... #include //close #include //std::string @@ -39,6 +41,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes a interprocess_semaphore class for inter-process synchronization diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index 38ce368..417bee0 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -24,6 +26,7 @@ #include #include #include +#include #if defined BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #include #include @@ -85,7 +88,7 @@ class named_condition //!If there are no waiting threads, notify_all() has no effect. void notify_all(); - //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!Releases the lock on the named_mutex object associated with lock, blocks //!the current thread of execution until readied by a call to //!this->notify_one() or this->notify_all(), and then reacquires the lock. template @@ -96,7 +99,7 @@ class named_condition template void wait(L& lock, Pr pred); - //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!Releases the lock on the named_mutex object associated with lock, blocks //!the current thread of execution until readied by a call to //!this->notify_one() or this->notify_all(), or until time abs_time is reached, //!and then reacquires the lock. @@ -148,7 +151,10 @@ class named_condition template void do_wait(Lock& lock) - { + { + //named_condition only works with named_mutex + BOOST_STATIC_ASSERT((detail::is_same::value == true)); + //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex()); lock_inverter inverted_lock(lock); @@ -163,6 +169,8 @@ class named_condition template bool do_timed_wait(Lock& lock, const boost::posix_time::ptime &abs_time) { + //named_condition only works with named_mutex + BOOST_STATIC_ASSERT((detail::is_same::value == true)); //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex(), abs_time); if(!internal_lock) return false; diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp index 67b6998..f76212f 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -20,7 +20,7 @@ #include #ifdef SEM_FAILED -#define BOOST_INTERPROCESS_POSIX_SEM_FAILED SEM_FAILED +#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(SEM_FAILED)) #else #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(-1)) #endif diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index 2bdfa3e..8dd1e57 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -22,8 +22,11 @@ #include #include +#include #include #include +#include +#include #include #include @@ -33,11 +36,6 @@ namespace boost { namespace interprocess { -template -class sharable_lock; - -template -class upgradable_lock; //!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking //!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all @@ -55,11 +53,13 @@ class scoped_lock /// @cond private: typedef scoped_lock this_type; - scoped_lock(scoped_lock const&); - scoped_lock& operator= (scoped_lock const&); + scoped_lock(scoped_lock&); + scoped_lock& operator= (scoped_lock&); typedef bool this_type::*unspecified_bool_type; /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_lock) + typedef Mutex mutex_type; //!Effects: Default constructs a scoped_lock. @@ -122,18 +122,12 @@ 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: "detail::move_impl(lock);". This + //! can be moved with the expression: "boost::interprocess::move(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(scop.get().owns()) - { mp_mutex = scop.get().release(); } - #else - scoped_lock(scoped_lock &&scop) + scoped_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop) : mp_mutex(0), m_locked(scop.owns()) { mp_mutex = scop.release(); } - #endif //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the //! referenced mutex. upgr.release() is called. @@ -144,22 +138,12 @@ 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: "detail::move_impl(lock);" This constructor may block if + //! the expression: "boost::interprocess::move(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). - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - u_lock.mutex()->unlock_upgradable_and_lock(); - m_locked = true; - } - mp_mutex = u_lock.release(); - } - #else - scoped_lock(upgradable_lock &&upgr) + template + explicit scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -169,7 +153,6 @@ class scoped_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the //!referenced mutex: @@ -185,25 +168,10 @@ class scoped_lock //! "read lock" to a "write lock". If the "read lock" isn't held in the //! first place, the mutex merely changes type to an unlocked "write lock". //! If the "read lock" is held, then mutex transfer occurs only if it can - //! do so in a non-blocking manner.*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr - ,try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){ - mp_mutex = u_lock.release(); - } - } - else{ - u_lock.release(); - } - } - #else - scoped_lock(upgradable_lock &&upgr - ,try_to_lock_type) + //! do so in a non-blocking manner. + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -216,7 +184,6 @@ class scoped_lock u_lock.release(); } } - #endif //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time) //! on the referenced mutex: @@ -232,24 +199,9 @@ class scoped_lock //! "write lock". If the "read lock" isn't held in the first place, the mutex //! merely changes type to an unlocked "write lock". If the "read lock" is held, //! then mutex transfer occurs only if it can do so in a non-blocking manner. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr - ,boost::posix_time::ptime &abs_time) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){ - mp_mutex = u_lock.release(); - } - } - else{ - u_lock.release(); - } - } - #else - scoped_lock(upgradable_lock &&upgr - ,boost::posix_time::ptime &abs_time) + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr, boost::posix_time::ptime &abs_time + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -262,7 +214,6 @@ class scoped_lock u_lock.release(); } } - #endif //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the //!referenced mutex. @@ -279,24 +230,9 @@ class scoped_lock //! first place, the mutex merely changes type to an unlocked "write lock". //! If the "read lock" is held, then mutex transfer occurs only if it can //! do so in a non-blocking manner. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > shar - ,try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - sharable_lock &s_lock = shar.get(); - if(s_lock.owns()){ - if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){ - mp_mutex = s_lock.release(); - } - } - else{ - s_lock.release(); - } - } - #else - scoped_lock(sharable_lock &&shar - ,try_to_lock_type) + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock) shar, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -309,7 +245,6 @@ class scoped_lock s_lock.release(); } } - #endif //!Effects: if (owns()) mp_mutex->unlock(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/ @@ -325,17 +260,7 @@ class scoped_lock //! the same mutex before the assignment. In this case, this will own the //! mutex after the assignment (and scop will not), but the mutex's lock //! count will be decremented by one. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock &operator=(detail::moved_object scop) - { - if(this->owns()) - this->unlock(); - m_locked = scop.get().owns(); - mp_mutex = scop.get().release(); - return *this; - } - #else - scoped_lock &operator=(scoped_lock &&scop) + scoped_lock &operator=(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop) { if(this->owns()) this->unlock(); @@ -343,7 +268,6 @@ class scoped_lock mp_mutex = scop.release(); return *this; } - #endif //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() //! exception. Calls lock() on the referenced mutex. @@ -429,19 +353,11 @@ class scoped_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(scoped_lock &&other) + void swap( scoped_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -450,16 +366,6 @@ class scoped_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index ea97864..b7baf04 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -22,10 +22,12 @@ #include #include +#include #include #include +#include +#include #include -//Ig#include #include //!\file @@ -35,11 +37,6 @@ namespace boost { namespace interprocess { -template -class scoped_lock; - -template -class upgradable_lock; //!sharable_lock is meant to carry out the tasks for sharable-locking //!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking @@ -57,13 +54,14 @@ class sharable_lock /// @cond private: typedef sharable_lock this_type; - sharable_lock(sharable_lock const&); - explicit sharable_lock(scoped_lock const&); + sharable_lock(sharable_lock&); + explicit sharable_lock(scoped_lock&); typedef bool this_type::*unspecified_bool_type; - sharable_lock& operator=(sharable_lock const&); - sharable_lock& operator=(scoped_lock const&); + sharable_lock& operator=(sharable_lock&); + sharable_lock& operator=(scoped_lock&); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(sharable_lock) //!Effects: Default constructs a sharable_lock. //!Postconditions: owns() == false and mutex() == 0. @@ -127,17 +125,11 @@ 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: - //! "detail::move_impl(lock);". This constructor does not alter the state of the mutex, + //! "boost::interprocess::move(lock);". This constructor does not alter the state of the mutex, //! only potentially who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(upgr.get().owns()) - { mp_mutex = upgr.get().release(); } - #else - sharable_lock(sharable_lock &&upgr) + sharable_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock) upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } - #endif //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock_sharable() on the //! referenced mutex. @@ -147,20 +139,10 @@ 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: - //! "detail::move_impl(lock);".*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &u_lock = upgr.get(); - if(u_lock.owns()){ - u_lock.mutex()->unlock_upgradable_and_lock_sharable(); - m_locked = true; - } - mp_mutex = u_lock.release(); - } - #else - sharable_lock(upgradable_lock &&upgr) + //! "boost::interprocess::move(lock);".*/ + template + sharable_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -170,7 +152,6 @@ class sharable_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the //! referenced mutex. @@ -181,20 +162,10 @@ 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: - //! "detail::move_impl(lock);".*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(false) - { - scoped_lock &e_lock = scop.get(); - if(e_lock.owns()){ - e_lock.mutex()->unlock_and_lock_sharable(); - m_locked = true; - } - mp_mutex = e_lock.release(); - } - #else - sharable_lock(scoped_lock &&scop) + //! "boost::interprocess::move(lock);". + template + sharable_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop; @@ -204,7 +175,6 @@ class sharable_lock } mp_mutex = e_lock.release(); } - #endif //!Effects: if (owns()) mp_mutex->unlock_sharable(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked. @@ -221,17 +191,7 @@ class sharable_lock //!Notes: With a recursive mutex it is possible that both this and upgr own the mutex //! before the assignment. In this case, this will own the mutex after the assignment //! (and upgr will not), but the mutex's lock count will be decremented by one. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock &operator=(detail::moved_object > upgr) - { - if(this->owns()) - this->unlock(); - m_locked = upgr.get().owns(); - mp_mutex = upgr.get().release(); - return *this; - } - #else - sharable_lock &operator=(sharable_lock &&upgr) + sharable_lock &operator=(BOOST_INTERPROCESS_RV_REF(sharable_lock) upgr) { if(this->owns()) this->unlock(); @@ -239,7 +199,6 @@ class sharable_lock mp_mutex = upgr.release(); return *this; } - #endif //!Effects: If mutex() == 0 or already locked, throws a lock_exception() //! exception. Calls lock_sharable() on the referenced mutex. @@ -328,19 +287,11 @@ class sharable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(sharable_lock &&other) + void swap(sharable_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -349,16 +300,6 @@ class sharable_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 386187d..fe3744b 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -22,7 +22,11 @@ #include #include +#include #include +#include +#include + #include #include #include @@ -34,12 +38,6 @@ namespace boost { namespace interprocess { -template -class scoped_lock; - -template -class sharable_lock; - //!upgradable_lock is meant to carry out the tasks for read-locking, unlocking, //!try-read-locking and timed-read-locking (recursive or not) for the Mutex. //!Additionally the upgradable_lock can transfer ownership to a scoped_lock @@ -57,13 +55,14 @@ class upgradable_lock /// @cond private: typedef upgradable_lock this_type; - upgradable_lock(upgradable_lock const&); - explicit upgradable_lock(scoped_lock const&); + upgradable_lock(upgradable_lock&); + explicit upgradable_lock(scoped_lock&); typedef bool this_type::*unspecified_bool_type; - upgradable_lock& operator=(upgradable_lock const&); - upgradable_lock& operator=(scoped_lock const&); + upgradable_lock& operator=(upgradable_lock&); + upgradable_lock& operator=(scoped_lock&); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(upgradable_lock) //!Effects: Default constructs a upgradable_lock. //!Postconditions: owns() == false and mutex() == 0. @@ -121,17 +120,11 @@ 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: "detail::move_impl(lock);". This constructor does not alter the + //! expression: "boost::interprocess::move(lock);". This constructor does not alter the //! state of the mutex, only potentially who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(upgr.get().owns()) - { mp_mutex = upgr.get().release(); } - #else - upgradable_lock(upgradable_lock &&upgr) + upgradable_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } - #endif //!Effects: If scop.owns(), m_.unlock_and_lock_upgradable(). //!Postconditions: mutex() == the value scop.mutex() had before the construction. @@ -141,20 +134,10 @@ 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: "detail::move_impl(lock);". - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(false) - { - scoped_lock &u_lock = scop.get(); - if(u_lock.owns()){ - u_lock.mutex()->unlock_and_lock_upgradable(); - m_locked = true; - } - mp_mutex = u_lock.release(); - } - #else - upgradable_lock(scoped_lock &&scop) + //! expression: "boost::interprocess::move(lock);". + template + upgradable_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop; @@ -164,7 +147,6 @@ class upgradable_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock_upgradable() //! on the referenced mutex. @@ -181,24 +163,9 @@ class upgradable_lock //! in the first place, the mutex merely changes type to an unlocked //! "upgradable lock". If the "read lock" is held, then mutex transfer //! occurs only if it can do so in a non-blocking manner. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock( detail::moved_object > shar - , try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - sharable_lock &s_lock = shar.get(); - if(s_lock.owns()){ - if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock_upgradable()) == true){ - mp_mutex = s_lock.release(); - } - } - else{ - s_lock.release(); - } - } - #else - upgradable_lock( sharable_lock &&shar - , try_to_lock_type) + template + upgradable_lock( BOOST_INTERPROCESS_RV_REF(sharable_lock) shar, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -211,7 +178,6 @@ class upgradable_lock s_lock.release(); } } - #endif //!Effects: if (owns()) m_->unlock_upgradable(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked. @@ -229,17 +195,7 @@ class upgradable_lock //! mutex before the assignment. In this case, this will own the mutex //! after the assignment (and upgr will not), but the mutex's upgradable lock //! count will be decremented by one. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock &operator=(detail::moved_object > upgr) - { - if(this->owns()) - this->unlock(); - m_locked = upgr.get().owns(); - mp_mutex = upgr.get().release(); - return *this; - } - #else - upgradable_lock &operator=(upgradable_lock &&upgr) + upgradable_lock &operator=(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr) { if(this->owns()) this->unlock(); @@ -247,7 +203,6 @@ class upgradable_lock mp_mutex = upgr.release(); return *this; } - #endif //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() //! exception. Calls lock_upgradable() on the referenced mutex. @@ -336,19 +291,11 @@ class upgradable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(upgradable_lock &&other) + void swap(upgradable_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -357,16 +304,6 @@ class upgradable_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index cd82e01..8b86710 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -15,7 +15,7 @@ #include #include -#if !defined(BOOST_WINDOWS) || defined(BOOST_DISABLE_WIN32) +#if !defined(BOOST_INTERPROCESS_WINDOWS) #error "This header can only be used in Windows operating systems" #endif @@ -51,11 +51,12 @@ class windows_shared_memory { /// @cond //Non-copyable and non-assignable - windows_shared_memory(const windows_shared_memory &); - windows_shared_memory &operator=(const windows_shared_memory &); + windows_shared_memory(windows_shared_memory &); + windows_shared_memory &operator=(windows_shared_memory &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(windows_shared_memory) //!Default constructor. //!Represents an empty windows_shared_memory. @@ -81,26 +82,15 @@ class windows_shared_memory //!Moves the ownership of "moved"'s shared memory object to *this. //!After the call, "moved" does not represent any shared memory object. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - windows_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - windows_shared_memory(windows_shared_memory &&moved) + windows_shared_memory(BOOST_INTERPROCESS_RV_REF(windows_shared_memory) moved) { this->swap(moved); } - #endif //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - windows_shared_memory &operator= - (detail::moved_object moved) - #else - windows_shared_memory &operator=(windows_shared_memory &&moved) - #endif + windows_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(windows_shared_memory) moved) { - windows_shared_memory tmp(detail::move_impl(moved)); + windows_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -232,14 +222,6 @@ 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 { diff --git a/proj/to-do.txt b/proj/to-do.txt index 3ac56ac..623bd5d 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -1,5 +1,3 @@ --> change rvalue reference signatures in all containers - -> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ -> add contiguous_elements option to burst allocation @@ -43,28 +41,26 @@ -> barrier_test fails on MacOS X on PowerPC. -->use virtual functions to minimize template explosion in managed classes +-> use virtual functions to minimize template explosion in managed classes -->Insertions with InpIt are not tested in containers +-> Insertions with InpIt are not tested in containers -->Run tests with rvalue reference compilers with no variadic insertions +-> Run tests with rvalue reference compilers with no variadic insertions -->find a way to pass security attributes to shared memory +-> find a way to pass security attributes to shared memory -->Explain in docs that shared memory can't be used between different users in windows +-> Explain in docs that shared memory can't be used between different users in windows -> Implement vector with memcpy/memmove for trivially copyable types. --> Update all swap() calls to work with rvalues in all classes - --> correct swap overloads for the documentation so that just appears a single rvalue swap - --> correct splice()/merg overloads for the documentation so that just appears a single rvalue splice - -> flat_xxx constructors are not documented -> operator >> eta antzekoek moved_value behar dute --> make file_lock movable - -> Add cmath workaround for Boost < 1.37 + +-> rvalue reference enabled compilers are not optimized with is_movable and move_iterator + +-> Add allocator test template that test all new functions (allocate_many, etc.) + +-> MacOS shm_open is non-conformant. Is there a way to know the size of a shared memory object? diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index ed25a07..dfbe26e 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -103,18 +103,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cont", "doc_cont.vcproj 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 @@ -139,14 +127,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iunordered_set_index_alloca 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 @@ -223,10 +203,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory", 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 @@ -295,26 +271,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_intrusive", "doc_intrus 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 @@ -463,11 +423,33 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_construct_test", "nam ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stable_vector_test", "stable_vector_test.vcproj", "{5E11C8D3-FA52-760A-84FE-943A6BA05A21}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_spawn_vector", "doc_spawn_vector.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_message", "doc_ipc_message.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_alloc", "doc_named_alloc.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" + 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 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 @@ -573,18 +555,6 @@ Global {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 @@ -609,14 +579,6 @@ Global {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 @@ -693,10 +655,6 @@ Global {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 @@ -765,26 +723,10 @@ Global {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 @@ -933,6 +875,26 @@ Global {5183C8CE-F2E1-3620-237A-B765C9896390}.Debug.Build.0 = Debug|Win32 {5183C8CE-F2E1-3620-237A-B765C9896390}.Release.ActiveCfg = Release|Win32 {5183C8CE-F2E1-3620-237A-B765C9896390}.Release.Build.0 = Release|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.ActiveCfg = Debug|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.Build.0 = Debug|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.ActiveCfg = Release|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.Build.0 = Release|Win32 + {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-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-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-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 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/adaptive_node_pool_test.vcproj b/proj/vc7ide/adaptive_node_pool_test.vcproj index e67a6c8..5ede3e9 100644 --- a/proj/vc7ide/adaptive_node_pool_test.vcproj +++ b/proj/vc7ide/adaptive_node_pool_test.vcproj @@ -21,6 +21,7 @@ Optimization="0" AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" + GeneratePreprocessedFile="0" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" diff --git a/proj/vc7ide/doc_adaptive_pool.vcproj b/proj/vc7ide/doc_adaptive_pool.vcproj index 1961a35..39d77ad 100644 --- a/proj/vc7ide/doc_adaptive_pool.vcproj +++ b/proj/vc7ide/doc_adaptive_pool.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_adaptive_pool.cpp"> - - diff --git a/proj/vc7ide/doc_allocator.vcproj b/proj/vc7ide/doc_allocator.vcproj index f87a509..a59fe9f 100644 --- a/proj/vc7ide/doc_allocator.vcproj +++ b/proj/vc7ide/doc_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_conditionA.vcproj b/proj/vc7ide/doc_anonymous_conditionA.vcproj index f572274..f1e0831 100644 --- a/proj/vc7ide/doc_anonymous_conditionA.vcproj +++ b/proj/vc7ide/doc_anonymous_conditionA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BE2BEF1-C8A9-53BC-1A02-952FFA2D75A2}"> + RelativePath="..\..\example\comp_doc_anonymous_conditionA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_conditionB.vcproj b/proj/vc7ide/doc_anonymous_conditionB.vcproj index 7005b51..e4a4028 100644 --- a/proj/vc7ide/doc_anonymous_conditionB.vcproj +++ b/proj/vc7ide/doc_anonymous_conditionB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4B2EF711-14CA-5347-F025-7F75AF2D22A2}"> + RelativePath="..\..\example\comp_doc_anonymous_conditionB.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_mutexA.vcproj b/proj/vc7ide/doc_anonymous_mutexA.vcproj index f97c3ba..e562362 100644 --- a/proj/vc7ide/doc_anonymous_mutexA.vcproj +++ b/proj/vc7ide/doc_anonymous_mutexA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BE712F1-C98A-4537-12A0-72D752FFA2A2}"> + RelativePath="..\..\example\comp_doc_anonymous_mutexA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_mutexB.vcproj b/proj/vc7ide/doc_anonymous_mutexB.vcproj index f696723..bde78a6 100644 --- a/proj/vc7ide/doc_anonymous_mutexB.vcproj +++ b/proj/vc7ide/doc_anonymous_mutexB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4B712EF1-98CA-4537-A012-72D2FF75A2A2}"> + RelativePath="..\..\example\comp_doc_anonymous_mutexB.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_semaphoreA.vcproj b/proj/vc7ide/doc_anonymous_semaphoreA.vcproj index 21d58f3..07786c5 100644 --- a/proj/vc7ide/doc_anonymous_semaphoreA.vcproj +++ b/proj/vc7ide/doc_anonymous_semaphoreA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BEFCAB1-8AC0-3B5C-AF1B-9522D75AFFA2}"> + RelativePath="..\..\example\comp_doc_anonymous_semaphoreA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_semaphoreB.vcproj b/proj/vc7ide/doc_anonymous_semaphoreB.vcproj index 30b1dd4..3d39e30 100644 --- a/proj/vc7ide/doc_anonymous_semaphoreB.vcproj +++ b/proj/vc7ide/doc_anonymous_semaphoreB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BCDF711-5717-14CA-F250-F2D8F75A22A2}"> + RelativePath="..\..\example\comp_doc_anonymous_semaphoreB.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_shared_memory.vcproj b/proj/vc7ide/doc_anonymous_shared_memory.vcproj index cd5d7a4..04cbf00 100644 --- a/proj/vc7ide/doc_anonymous_shared_memory.vcproj +++ b/proj/vc7ide/doc_anonymous_shared_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_anonymous_shared_memory.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj b/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj index 2df71b6..af3aca3 100644 --- a/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj +++ b/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BF1E712-4FB5-08CB-2A11-752DCD72F2B2}"> + RelativePath="..\..\example\comp_doc_anonymous_upgradable_mutexA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj b/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj index e5b0250..5204ec5 100644 --- a/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj +++ b/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4B712E2E-5347-A352-8C9F-FF72D27982A2}"> + RelativePath="..\..\example\comp_doc_anonymous_upgradable_mutexB.cpp"> - - diff --git a/proj/vc7ide/doc_bufferstream.vcproj b/proj/vc7ide/doc_bufferstream.vcproj index 1430223..129e265 100644 --- a/proj/vc7ide/doc_bufferstream.vcproj +++ b/proj/vc7ide/doc_bufferstream.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_bufferstream.cpp"> - - diff --git a/proj/vc7ide/doc_cached_adaptive_pool.vcproj b/proj/vc7ide/doc_cached_adaptive_pool.vcproj index 86c6b9d..5164354 100644 --- a/proj/vc7ide/doc_cached_adaptive_pool.vcproj +++ b/proj/vc7ide/doc_cached_adaptive_pool.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_cached_adaptive_pool.cpp"> - - diff --git a/proj/vc7ide/doc_cached_node_allocator.vcproj b/proj/vc7ide/doc_cached_node_allocator.vcproj index 3824942..e2f4655 100644 --- a/proj/vc7ide/doc_cached_node_allocator.vcproj +++ b/proj/vc7ide/doc_cached_node_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_cached_node_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_cont.vcproj b/proj/vc7ide/doc_cont.vcproj index 9d9126c..f19202d 100644 --- a/proj/vc7ide/doc_cont.vcproj +++ b/proj/vc7ide/doc_cont.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_cont.cpp"> - - diff --git a/proj/vc7ide/doc_contB.vcproj b/proj/vc7ide/doc_contB.vcproj index 85807ca..9f545a6 100644 --- a/proj/vc7ide/doc_contB.vcproj +++ b/proj/vc7ide/doc_contB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + RelativePath="..\..\example\comp_doc_contB.cpp"> - - diff --git a/proj/vc7ide/doc_file_mapping.vcproj b/proj/vc7ide/doc_file_mapping.vcproj index b71b7cb..215ca40 100644 --- a/proj/vc7ide/doc_file_mapping.vcproj +++ b/proj/vc7ide/doc_file_mapping.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_file_mapping.cpp"> - - diff --git a/proj/vc7ide/doc_file_mapping2.vcproj b/proj/vc7ide/doc_file_mapping2.vcproj deleted file mode 100644 index 9071a47..0000000 --- a/proj/vc7ide/doc_file_mapping2.vcproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/proj/vc7ide/doc_intrusive.vcproj b/proj/vc7ide/doc_intrusive.vcproj index f1cbee5..757b60c 100644 --- a/proj/vc7ide/doc_intrusive.vcproj +++ b/proj/vc7ide/doc_intrusive.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_intrusive.cpp"> - - diff --git a/proj/vc7ide/doc_ipc_messageA.vcproj b/proj/vc7ide/doc_ipc_message.vcproj similarity index 87% rename from proj/vc7ide/doc_ipc_messageA.vcproj rename to proj/vc7ide/doc_ipc_message.vcproj index d3ee38a..5e2208a 100644 --- a/proj/vc7ide/doc_ipc_messageA.vcproj +++ b/proj/vc7ide/doc_ipc_message.vcproj @@ -2,7 +2,7 @@ @@ -13,7 +13,7 @@ @@ -67,7 +67,7 @@ + RelativePath="..\..\example\doc_ipc_message.cpp"> - - diff --git a/proj/vc7ide/doc_managed_aligned_allocation.vcproj b/proj/vc7ide/doc_managed_aligned_allocation.vcproj index 0be1539..455d93f 100644 --- a/proj/vc7ide/doc_managed_aligned_allocation.vcproj +++ b/proj/vc7ide/doc_managed_aligned_allocation.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_aligned_allocation.cpp"> - - diff --git a/proj/vc7ide/doc_managed_allocation_command.vcproj b/proj/vc7ide/doc_managed_allocation_command.vcproj index f9ff6f1..367eb81 100644 --- a/proj/vc7ide/doc_managed_allocation_command.vcproj +++ b/proj/vc7ide/doc_managed_allocation_command.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_allocation_command.cpp"> - - diff --git a/proj/vc7ide/doc_managed_construction_info.vcproj b/proj/vc7ide/doc_managed_construction_info.vcproj index 36f749f..2ff84df6 100644 --- a/proj/vc7ide/doc_managed_construction_info.vcproj +++ b/proj/vc7ide/doc_managed_construction_info.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_construction_info.cpp"> - - diff --git a/proj/vc7ide/doc_managed_grow.vcproj b/proj/vc7ide/doc_managed_grow.vcproj index 8355e3b..a516ede 100644 --- a/proj/vc7ide/doc_managed_grow.vcproj +++ b/proj/vc7ide/doc_managed_grow.vcproj @@ -128,11 +128,6 @@ RelativePath="..\..\example\doc_managed_grow.cpp"> - - diff --git a/proj/vc7ide/doc_managed_heap_memory.vcproj b/proj/vc7ide/doc_managed_heap_memory.vcproj index fb63372..046ce13 100644 --- a/proj/vc7ide/doc_managed_heap_memory.vcproj +++ b/proj/vc7ide/doc_managed_heap_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_heap_memory.cpp"> - - diff --git a/proj/vc7ide/doc_managed_mapped_file.vcproj b/proj/vc7ide/doc_managed_mapped_file.vcproj index 31a7c39..d0588af 100644 --- a/proj/vc7ide/doc_managed_mapped_file.vcproj +++ b/proj/vc7ide/doc_managed_mapped_file.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_mapped_file.cpp"> - - diff --git a/proj/vc7ide/doc_managed_multiple_allocation.vcproj b/proj/vc7ide/doc_managed_multiple_allocation.vcproj index fc35fde..69b2afc 100644 --- a/proj/vc7ide/doc_managed_multiple_allocation.vcproj +++ b/proj/vc7ide/doc_managed_multiple_allocation.vcproj @@ -128,11 +128,6 @@ RelativePath="..\..\example\doc_managed_multiple_allocation.cpp"> - - diff --git a/proj/vc7ide/doc_managed_raw_allocation.vcproj b/proj/vc7ide/doc_managed_raw_allocation.vcproj index 1269082..f537e1f 100644 --- a/proj/vc7ide/doc_managed_raw_allocation.vcproj +++ b/proj/vc7ide/doc_managed_raw_allocation.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_raw_allocation.cpp"> - - diff --git a/proj/vc7ide/doc_map.vcproj b/proj/vc7ide/doc_map.vcproj index 7c49867..9ac8ca3 100644 --- a/proj/vc7ide/doc_map.vcproj +++ b/proj/vc7ide/doc_map.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_map.cpp"> - - diff --git a/proj/vc7ide/doc_message_queueA.vcproj b/proj/vc7ide/doc_message_queueA.vcproj index daf452c..f05e0fa 100644 --- a/proj/vc7ide/doc_message_queueA.vcproj +++ b/proj/vc7ide/doc_message_queueA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{42FBE7AD-C8A9-12A0-5347-72FFA25175A2}"> + RelativePath="..\..\example\comp_doc_message_queueA.cpp"> - - diff --git a/proj/vc7ide/doc_message_queueB.vcproj b/proj/vc7ide/doc_message_queueB.vcproj index 974b1a5..773af14 100644 --- a/proj/vc7ide/doc_message_queueB.vcproj +++ b/proj/vc7ide/doc_message_queueB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{412EC7F1-45A7-98CA-A012-7952A2D2AFF2}"> + RelativePath="..\..\example\comp_doc_message_queueB.cpp"> - - diff --git a/proj/vc7ide/doc_move_containers.vcproj b/proj/vc7ide/doc_move_containers.vcproj index 30c5981..5d91966 100644 --- a/proj/vc7ide/doc_move_containers.vcproj +++ b/proj/vc7ide/doc_move_containers.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_move_containers.cpp"> - - diff --git a/proj/vc7ide/doc_named_allocA.vcproj b/proj/vc7ide/doc_named_alloc.vcproj similarity index 87% rename from proj/vc7ide/doc_named_allocA.vcproj rename to proj/vc7ide/doc_named_alloc.vcproj index 3954d12..68b97f9 100644 --- a/proj/vc7ide/doc_named_allocA.vcproj +++ b/proj/vc7ide/doc_named_alloc.vcproj @@ -2,7 +2,7 @@ @@ -13,7 +13,7 @@ @@ -67,7 +67,7 @@ + RelativePath="..\..\example\doc_named_alloc.cpp"> - - diff --git a/proj/vc7ide/doc_named_conditionA.vcproj b/proj/vc7ide/doc_named_conditionA.vcproj index 73fb140..909275b 100644 --- a/proj/vc7ide/doc_named_conditionA.vcproj +++ b/proj/vc7ide/doc_named_conditionA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{AB2F71E1-2E95-7FA3-2A10-741FA12A22F2}"> + RelativePath="..\..\example\comp_doc_named_conditionA.cpp"> - - diff --git a/proj/vc7ide/doc_named_conditionB.vcproj b/proj/vc7ide/doc_named_conditionB.vcproj index cb2bdd7..1ac14ae 100644 --- a/proj/vc7ide/doc_named_conditionB.vcproj +++ b/proj/vc7ide/doc_named_conditionB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{AB712FE1-92E5-7543-12A0-74522FFA12A2}"> + RelativePath="..\..\example\comp_doc_named_conditionB.cpp"> - - diff --git a/proj/vc7ide/doc_named_mutex.vcproj b/proj/vc7ide/doc_named_mutex.vcproj index 9aa0582..874a7a1 100644 --- a/proj/vc7ide/doc_named_mutex.vcproj +++ b/proj/vc7ide/doc_named_mutex.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_named_mutex.cpp"> - - diff --git a/proj/vc7ide/doc_node_allocator.vcproj b/proj/vc7ide/doc_node_allocator.vcproj index 03c0a52..269ca8a 100644 --- a/proj/vc7ide/doc_node_allocator.vcproj +++ b/proj/vc7ide/doc_node_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_node_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_offset_ptr.vcproj b/proj/vc7ide/doc_offset_ptr.vcproj index 4768fa8..58d1ffd 100644 --- a/proj/vc7ide/doc_offset_ptr.vcproj +++ b/proj/vc7ide/doc_offset_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_offset_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_private_adaptive_pool.vcproj b/proj/vc7ide/doc_private_adaptive_pool.vcproj index ad9eda0..7a50b91 100644 --- a/proj/vc7ide/doc_private_adaptive_pool.vcproj +++ b/proj/vc7ide/doc_private_adaptive_pool.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_private_adaptive_pool.cpp"> - - diff --git a/proj/vc7ide/doc_private_node_allocator.vcproj b/proj/vc7ide/doc_private_node_allocator.vcproj index b60943b..22ca032 100644 --- a/proj/vc7ide/doc_private_node_allocator.vcproj +++ b/proj/vc7ide/doc_private_node_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_private_node_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_scoped_ptr.vcproj b/proj/vc7ide/doc_scoped_ptr.vcproj index ec2dc09..e6a62dd 100644 --- a/proj/vc7ide/doc_scoped_ptr.vcproj +++ b/proj/vc7ide/doc_scoped_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_scoped_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_shared_memory.vcproj b/proj/vc7ide/doc_shared_memory.vcproj index f085b5e..66a1de0 100644 --- a/proj/vc7ide/doc_shared_memory.vcproj +++ b/proj/vc7ide/doc_shared_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_shared_memory.cpp"> - - diff --git a/proj/vc7ide/doc_shared_ptr.vcproj b/proj/vc7ide/doc_shared_ptr.vcproj index bf0ecd7..160d883 100644 --- a/proj/vc7ide/doc_shared_ptr.vcproj +++ b/proj/vc7ide/doc_shared_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_shared_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_shared_ptr_explicit.vcproj b/proj/vc7ide/doc_shared_ptr_explicit.vcproj index c10bbdb..77480ad 100644 --- a/proj/vc7ide/doc_shared_ptr_explicit.vcproj +++ b/proj/vc7ide/doc_shared_ptr_explicit.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_shared_ptr_explicit.cpp"> - - diff --git a/proj/vc7ide/doc_named_allocB.vcproj b/proj/vc7ide/doc_spawn_vector.vcproj similarity index 85% rename from proj/vc7ide/doc_named_allocB.vcproj rename to proj/vc7ide/doc_spawn_vector.vcproj index 09f43f8..a6a6726 100644 --- a/proj/vc7ide/doc_named_allocB.vcproj +++ b/proj/vc7ide/doc_spawn_vector.vcproj @@ -2,8 +2,8 @@ @@ -67,7 +67,7 @@ + RelativePath="..\..\example\doc_spawn_vector.cpp"> - - diff --git a/proj/vc7ide/doc_unique_ptr.vcproj b/proj/vc7ide/doc_unique_ptr.vcproj index f2cc7b5..39dd224 100644 --- a/proj/vc7ide/doc_unique_ptr.vcproj +++ b/proj/vc7ide/doc_unique_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_unique_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_vectorstream.vcproj b/proj/vc7ide/doc_vectorstream.vcproj index 9e2b8fc..9504650 100644 --- a/proj/vc7ide/doc_vectorstream.vcproj +++ b/proj/vc7ide/doc_vectorstream.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_vectorstream.cpp"> - - diff --git a/proj/vc7ide/doc_where_allocate.vcproj b/proj/vc7ide/doc_where_allocate.vcproj index 9a255f5..6bd2493 100644 --- a/proj/vc7ide/doc_where_allocate.vcproj +++ b/proj/vc7ide/doc_where_allocate.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_where_allocate.cpp"> - - diff --git a/proj/vc7ide/doc_windows_shared_memory.vcproj b/proj/vc7ide/doc_windows_shared_memory.vcproj index 990cb2c..dd6357d 100644 --- a/proj/vc7ide/doc_windows_shared_memory.vcproj +++ b/proj/vc7ide/doc_windows_shared_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_windows_shared_memory.cpp"> - - diff --git a/proj/vc7ide/doc_windows_shared_memory2.vcproj b/proj/vc7ide/doc_windows_shared_memory2.vcproj index 011cfbf..2be8642 100644 --- a/proj/vc7ide/doc_windows_shared_memory2.vcproj +++ b/proj/vc7ide/doc_windows_shared_memory2.vcproj @@ -39,7 +39,7 @@ LinkIncremental="1" AdditionalLibraryDirectories="../../../../stage/lib" GenerateDebugInformation="TRUE" - ProgramDatabaseFile="$(OutDir)/doc_windows_shared_memory2.pdb" + ProgramDatabaseFile="$(OutDir)/doc_windows_shared_memoryB.pdb" SubSystem="1" TargetMachine="1" FixedBaseAddress="1"/> @@ -86,7 +86,7 @@ + RelativePath="..\..\example\comp_doc_windows_shared_memoryB.cpp"> - - diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index abf9115..83dd2cf 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -119,25 +119,15 @@ + + - - - - - - - - + + @@ -361,18 +354,9 @@ - - - - - - @@ -385,9 +369,6 @@ - - @@ -397,9 +378,6 @@ - - @@ -418,9 +396,6 @@ - - @@ -454,6 +429,9 @@ + + @@ -463,9 +441,6 @@ - - diff --git a/proj/vc7ide/shared_memory_mappable_test.vcproj b/proj/vc7ide/shared_memory_mappable_test.vcproj index 2954e48..da82e29 100644 --- a/proj/vc7ide/shared_memory_mappable_test.vcproj +++ b/proj/vc7ide/shared_memory_mappable_test.vcproj @@ -22,9 +22,11 @@ AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" GeneratePreprocessedFile="0" + KeepComments="FALSE" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="FALSE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/doc_ipc_messageB.vcproj b/proj/vc7ide/stable_vector_test.vcproj similarity index 83% rename from proj/vc7ide/doc_ipc_messageB.vcproj rename to proj/vc7ide/stable_vector_test.vcproj index b3317e9..fdc2192 100644 --- a/proj/vc7ide/doc_ipc_messageB.vcproj +++ b/proj/vc7ide/stable_vector_test.vcproj @@ -2,8 +2,8 @@ @@ -67,7 +67,7 @@ + UniqueIdentifier="{37BC807F-2451-A306-7AC5-7A35A32A22DF}"> + RelativePath="..\..\test\stable_vector_test.cpp"> - - diff --git a/proj/vc7ide/string_test.vcproj b/proj/vc7ide/string_test.vcproj index 5bd6b2d..77f6f35 100644 --- a/proj/vc7ide/string_test.vcproj +++ b/proj/vc7ide/string_test.vcproj @@ -21,6 +21,7 @@ Optimization="0" AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" + GeneratePreprocessedFile="0" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" diff --git a/proj/vc7ide/windows_shared_memory_mapping_test.vcproj b/proj/vc7ide/windows_shared_memory_mapping_test.vcproj index 67d5880..e488012 100644 --- a/proj/vc7ide/windows_shared_memory_mapping_test.vcproj +++ b/proj/vc7ide/windows_shared_memory_mapping_test.vcproj @@ -13,7 +13,7 @@ @@ -67,7 +67,7 @@ #include "node_pool_test.hpp" #include diff --git a/test/allocator_v1.hpp b/test/allocator_v1.hpp index d52a039..3974046 100644 --- a/test/allocator_v1.hpp +++ b/test/allocator_v1.hpp @@ -18,10 +18,12 @@ #include #include +#include + #include -#include +#include #include -#include +#include #include #include #include @@ -49,10 +51,10 @@ class allocator_v1 typedef typename segment_manager::void_pointer aux_pointer_t; typedef typename - detail::pointer_to_other + boost::pointer_to_other ::type cvoid_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type alloc_ptr_t; template @@ -64,9 +66,9 @@ class allocator_v1 public: typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef typename detail::add_reference ::type reference; diff --git a/test/check_equal_containers.hpp b/test/check_equal_containers.hpp index dd68998..fb15530 100644 --- a/test/check_equal_containers.hpp +++ b/test/check_equal_containers.hpp @@ -32,10 +32,12 @@ bool CheckEqualContainers(MyShmCont *shmcont, MyStdCont *stdcont) typename MyShmCont::iterator itshm(shmcont->begin()), itshmend(shmcont->end()); typename MyStdCont::iterator itstd(stdcont->begin()); - if((typename MyStdCont::size_type)std::distance(itshm, itshmend) != shmcont->size()){ + typename MyStdCont::size_type dist = (typename MyStdCont::size_type)std::distance(itshm, itshmend); + if(dist != shmcont->size()){ return false; } - for(; itshm != itshmend; ++itshm, ++itstd){ + std::size_t i = 0; + for(; itshm != itshmend; ++itshm, ++itstd, ++i){ value_type val(*itstd); const value_type &v = *itshm; if(v != val) diff --git a/test/data_test.cpp b/test/data_test.cpp index 66bb0dc..5c5f15a 100644 --- a/test/data_test.cpp +++ b/test/data_test.cpp @@ -17,7 +17,6 @@ #include #include #include -#include //std::remove #include "print_container.hpp" #include "get_process_id_name.hpp" @@ -29,8 +28,6 @@ int main () std::string process_name; test::get_process_id_name(process_name); const char *const shMemName = process_name.c_str(); - std::string filename (test::get_process_id_name()); - filename += "_file"; try{ shared_memory_object::remove(shMemName); @@ -90,12 +87,9 @@ int main () res = (0 == segment.find(allocName).first); if(!res) return 1; - - std::remove(filename.c_str()); } } catch(...){ - std::remove(filename.c_str()); shared_memory_object::remove(shMemName); throw; } diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 3046d46..94e1763 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -26,7 +26,6 @@ #include #include "allocator_v1.hpp" #include -#include #include #include #include @@ -67,12 +66,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, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin()+size/2, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { IntType move_me(2); - shmdeque->assign(shmdeque->size()/2, detail::move_impl(move_me)); + shmdeque->assign(shmdeque->size()/2, boost::interprocess::move(move_me)); stddeque->assign(stddeque->size()/2, 2); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } @@ -81,13 +80,13 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) stddeque->clear(); shmdeque->clear(); stddeque->insert(stddeque->begin(), 50, 1); - shmdeque->insert(shmdeque->begin(), 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin(), 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->begin()+20, 50, 1); - shmdeque->insert(shmdeque->begin()+20, 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin()+20, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->begin()+20, 20, 1); - shmdeque->insert(shmdeque->begin()+20, 20, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin()+20, 20, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { @@ -95,13 +94,13 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) stddeque->clear(); shmdeque->clear(); stddeque->insert(stddeque->end(), 50, 1); - shmdeque->insert(shmdeque->end(), 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end(), 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->end()-20, 50, 1); - shmdeque->insert(shmdeque->end()-20, 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end()-20, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->end()-20, 20, 1); - shmdeque->insert(shmdeque->end()-20, 20, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end()-20, 20, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } @@ -127,10 +126,9 @@ bool do_test() { //Now test move semantics deque original; - deque move_ctor(detail::move_impl(original)); + deque move_ctor(boost::interprocess::move(original)); deque move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } @@ -174,7 +172,7 @@ bool do_test() int i; for(i = 0; i < max*100; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->end(), detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end(), boost::interprocess::move(move_me)); stddeque->insert(stddeque->end(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -184,7 +182,7 @@ bool do_test() for(i = 0; i < max*100; ++i){ IntType move_me(i); - shmdeque->push_back(detail::move_impl(move_me)); + shmdeque->push_back(boost::interprocess::move(move_me)); stddeque->push_back(i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -194,7 +192,7 @@ bool do_test() for(i = 0; i < max*100; ++i){ IntType move_me(i); - shmdeque->push_front(detail::move_impl(move_me)); + shmdeque->push_front(boost::interprocess::move(move_me)); stddeque->push_front(i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -215,7 +213,7 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me (-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -223,8 +221,8 @@ bool do_test() } shmdeque->insert(shmdeque->end() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stddeque->insert(stddeque->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -238,21 +236,21 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } shmdeque->insert(shmdeque->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stddeque->insert(stddeque->begin(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } if(!copyable_only(shmdeque, stddeque - ,detail::bool_::value>())){ + ,detail::bool_::value>())){ return false; } @@ -263,7 +261,7 @@ bool do_test() for(i = 0; i < max; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->begin(), detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin(), boost::interprocess::move(move_me)); stddeque->insert(stddeque->begin(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index e8466f0..8a7af64 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -19,10 +19,10 @@ #include #include -#include +#include #include #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ class dummy_test_allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; -// typedef detail::version_type version; +// typedef boost::interprocess::version_type version; template struct rebind @@ -111,7 +111,7 @@ class dummy_test_allocator //Experimental version 2 dummy_test_allocator functions std::pair - allocation_command(allocation_type, + allocation_command(boost::interprocess::allocation_type, size_type, size_type, size_type &, const pointer & = 0) diff --git a/test/emplace_test.hpp b/test/emplace_test.hpp index 103d8da..ba27eab 100644 --- a/test/emplace_test.hpp +++ b/test/emplace_test.hpp @@ -29,27 +29,18 @@ class EmplaceInt EmplaceInt& operator=(const EmplaceInt &o); public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(EmplaceInt) + EmplaceInt(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0) : a_(a), b_(b), c_(c), d_(d), e_(e) {} - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - EmplaceInt(EmplaceInt &&o) + EmplaceInt(BOOST_INTERPROCESS_RV_REF(EmplaceInt) o) : a_(o.a_), b_(o.b_), c_(o.c_), d_(o.d_), e_(o.e_) - #else - EmplaceInt(detail::moved_object mo) - : a_(mo.get().a_), b_(mo.get().b_), c_(mo.get().c_), d_(mo.get().d_), e_(mo.get().e_) - #endif {} - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - EmplaceInt& operator=(EmplaceInt &&o) + EmplaceInt& operator=(BOOST_INTERPROCESS_RV_REF(EmplaceInt) o) { - #else - EmplaceInt& operator=(detail::moved_object mo) - { - EmplaceInt &o = mo.get(); - #endif this->a_ = o.a_; this->b_ = o.b_; this->c_ = o.c_; @@ -93,12 +84,6 @@ class EmplaceInt } //namespace test { -template<> -struct is_movable -{ - static const bool value = true; -}; - namespace test { enum EmplaceOptions{ diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 0a62b33..a773cee 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -19,10 +19,10 @@ #include #include -#include +#include #include #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ class expand_bwd_test_allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -118,14 +118,14 @@ class expand_bwd_test_allocator //Experimental version 2 expand_bwd_test_allocator functions std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) { (void)preferred_size; (void)reuse; (void)command; //This allocator only expands backwards! - assert(m_allocations == 0 || (command & expand_bwd)); + assert(m_allocations == 0 || (command & boost::interprocess::expand_bwd)); received_size = limit_size; diff --git a/test/file_lock_test.cpp b/test/file_lock_test.cpp index cc0c84c..e689256 100644 --- a/test/file_lock_test.cpp +++ b/test/file_lock_test.cpp @@ -11,12 +11,13 @@ #include #include #include +#include #include #include "mutex_test_template.hpp" #include "sharable_mutex_test_template.hpp" #include "get_process_id_name.hpp" #include -#include +#include //std::remove using namespace boost::interprocess; //This wrapper is necessary to have a default constructor @@ -49,16 +50,15 @@ int main () { scoped_lock sl(flock, test::delay(1)); } - }/* + } { //Now test move semantics file_lock mapping(test::get_process_id_name()); - file_lock move_ctor(detail::move_impl(mapping)); + file_lock move_ctor(boost::interprocess::move(mapping)); file_lock move_assign; - move_assign = detail::move_impl(move_ctor); - mapping.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); mapping.swap(move_assign); - }*/ + } //test::test_all_lock(); //test::test_all_mutex(); diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 2aa7e3f..1151fd1 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -16,12 +16,17 @@ #include #include //std::auto_ptr #include //std::exception -#include //std::remove #include //std::size_t #include "get_process_id_name.hpp" using namespace boost::interprocess; +file_mapping get_file_mapping() +{ + file_mapping f; + return file_mapping(boost::interprocess::move(f)); +} + int main () { try{ @@ -125,19 +130,19 @@ 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_ctor(boost::interprocess::move(mapping)); file_mapping move_assign; - move_assign = detail::move_impl(move_ctor); - mapping.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); mapping.swap(move_assign); + file_mapping ret(get_file_mapping()); } } catch(std::exception &exc){ - std::remove(test::get_process_id_name()); + file_mapping::remove(test::get_process_id_name()); std::cout << "Unhandled exception: " << exc.what() << std::endl; throw; } - std::remove(test::get_process_id_name()); + file_mapping::remove(test::get_process_id_name()); return 0; } diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp index e7ebd77..9bc3ae4 100644 --- a/test/flat_tree_test.cpp +++ b/test/flat_tree_test.cpp @@ -62,7 +62,7 @@ typedef basic_managed_shared_memory , rbtree_best_fit, - flat_map_index + iset_index > my_managed_shared_memory; //Alias allocator type @@ -132,10 +132,49 @@ public: { return a.id_ < b.id_; } }; +//Test recursive structures +class recursive_flat_multiset +{ +public: + int id_; + flat_multiset flat_set_; + friend bool operator< (const recursive_flat_multiset &a, const recursive_flat_set &b) + { return a.id_ < b.id_; } +}; + +class recursive_flat_multimap +{ +public: + int id_; + flat_map map_; + friend bool operator< (const recursive_flat_multimap &a, const recursive_flat_multimap &b) + { return a.id_ < b.id_; } +}; + +template +void test_move() +{ + //Now test move semantics + C original; + C move_ctor(boost::interprocess::move(original)); + C move_assign; + move_assign = boost::interprocess::move(move_ctor); + move_assign.swap(original); +} + int main() { using namespace boost::interprocess::test; + //Now test move semantics + { + test_move >(); + test_move >(); + test_move >(); + test_move >(); + } + + if (0 != set_test, SetOptions>()) return 1; - #endif //!defined(__GNUC__) + //#endif //!defined(__GNUC__) return 0; + } #include diff --git a/test/get_process_id_name.hpp b/test/get_process_id_name.hpp index df3bb8f..330cf58 100644 --- a/test/get_process_id_name.hpp +++ b/test/get_process_id_name.hpp @@ -23,8 +23,8 @@ namespace test{ inline void get_process_id_name(std::string &str) { std::stringstream sstr; - sstr << "process_" << boost::interprocess::detail::get_current_process_id(); - str = sstr.str(); + sstr << "process_" << boost::interprocess::detail::get_current_process_id() << std::ends; + str = sstr.str().c_str(); } inline const char *get_process_id_name() diff --git a/test/list_test.cpp b/test/list_test.cpp index d7f58dd..2e95d9d 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -54,10 +54,9 @@ int main () { //Now test move semantics list original; - list move_ctor(detail::move_impl(original)); + list move_ctor(boost::interprocess::move(original)); list move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } if(test::list_test()) diff --git a/test/list_test.hpp b/test/list_test.hpp index 390f61e..a9de4c8 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -19,7 +19,6 @@ #include #include "print_container.hpp" #include -#include #include #include "get_process_id_name.hpp" @@ -36,7 +35,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(detail::move_impl(move_me)); + shmlist->push_back(boost::interprocess::move(move_me)); stdlist->push_back(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -54,7 +53,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(detail::move_impl(move_me)); + shmlist->push_front(boost::interprocess::move(move_me)); stdlist->push_front(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -113,6 +112,7 @@ int list_test (bool copied_allocators_equal = true) MyShmList *shmlist = segment.template construct("MyList") (segment.get_segment_manager()); + MyStdList *stdlist = new MyStdList; if(push_data_t::execute(max, shmlist, stdlist)){ @@ -135,14 +135,14 @@ 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] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - shmlist->assign(detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(&aux_vect[50])); + shmlist->assign(boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(&aux_vect[50])); stdlist->assign(&aux_vect2[0], &aux_vect2[50]); if(!CheckEqualContainers(shmlist, stdlist)) return 1; } @@ -165,15 +165,15 @@ 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] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } shmlist->insert(shmlist->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(&aux_vect[50])); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(&aux_vect[50])); stdlist->insert(stdlist->begin(), &aux_vect2[0], &aux_vect2[50]); } diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index cebbfe5..f0b3f6e 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -31,7 +31,7 @@ int main () { //Remove the file it is already created - std::remove(FileName); + file_mapping::remove(FileName); const int max = 100; void *array[max]; @@ -52,7 +52,7 @@ int main () { //Remove the file it is already created - std::remove(FileName); + file_mapping::remove(FileName); //Named allocate capable memory mapped file managed memory class managed_mapped_file mfile(create_only, FileName, FileSize); @@ -203,15 +203,14 @@ int main () { //Now test move semantics managed_mapped_file original(open_only, FileName); - managed_mapped_file move_ctor(detail::move_impl(original)); + managed_mapped_file move_ctor(boost::interprocess::move(original)); managed_mapped_file move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } } - std::remove(FileName); + file_mapping::remove(FileName); return 0; } diff --git a/test/managed_shared_memory_test.cpp b/test/managed_shared_memory_test.cpp index 1314038..f19fabe 100644 --- a/test/managed_shared_memory_test.cpp +++ b/test/managed_shared_memory_test.cpp @@ -199,10 +199,9 @@ int main () { //Now test move semantics managed_shared_memory original(open_only, ShmemName); - managed_shared_memory move_ctor(detail::move_impl(original)); + managed_shared_memory move_ctor(boost::interprocess::move(original)); managed_shared_memory move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } } diff --git a/test/managed_windows_shared_memory_test.cpp b/test/managed_windows_shared_memory_test.cpp index f02868f..cdb1d68 100644 --- a/test/managed_windows_shared_memory_test.cpp +++ b/test/managed_windows_shared_memory_test.cpp @@ -9,8 +9,9 @@ ////////////////////////////////////////////////////////////////////////////// #include +#include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS #include #include @@ -130,9 +131,9 @@ int main () //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_ctor(boost::interprocess::move(original)); managed_windows_shared_memory move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); } } diff --git a/test/map_test.hpp b/test/map_test.hpp index 13363bf..c4e88f7 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -17,9 +17,8 @@ #include #include #include "print_container.hpp" -#include #include -#include +#include #include #include "get_process_id_name.hpp" @@ -41,7 +40,7 @@ template IntPairType; + typedef boost::interprocess::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; const int memsize = 65536; const char *const shMemName = test::get_process_id_name(); @@ -73,7 +72,9 @@ int map_test () //This is really nasty, but we have no other simple choice IntPairType aux_vect[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect[i])IntPairType(IntType(i/2), IntType(i/2)); + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } typedef typename MyStdMap::value_type StdValueType; @@ -86,21 +87,23 @@ int map_test () IntPairType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect3[i])IntPairType(IntType(i/2), IntType(i/2)); + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } MyShmMap *shmmap2 = segment.template construct("MyShmMap2") - (detail::make_move_iterator(&aux_vect[0]) - , detail::make_move_iterator(aux_vect + 50) + (boost::interprocess::make_move_iterator(&aux_vect[0]) + , boost::interprocess::make_move_iterator(aux_vect + 50) , std::less(), segment.get_segment_manager()); MyStdMap *stdmap2 = new MyStdMap(aux_vect2, aux_vect2 + 50); MyShmMultiMap *shmmultimap2 = segment.template construct("MyShmMultiMap2") - (detail::make_move_iterator(&aux_vect3[0]) - , detail::make_move_iterator(aux_vect3 + 50) + (boost::interprocess::make_move_iterator(&aux_vect3[0]) + , boost::interprocess::make_move_iterator(aux_vect3 + 50) , std::less(), segment.get_segment_manager()); MyStdMultiMap *stdmultimap2 = new MyStdMultiMap(aux_vect2, aux_vect2 + 50); @@ -112,71 +115,89 @@ int map_test () delete stdmap2; delete stdmultimap2; } + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + IntPairType aux_vect3[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } - int i, j; - for(i = 0; i < max; ++i){ - shmmap->insert(detail::move_impl(IntPairType (detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(StdPairType(i, i)); + for(int i = 0; i < max; ++i){ + shmmap->insert(boost::interprocess::move(aux_vect[i])); + stdmap->insert(StdPairType(i, i)); + shmmultimap->insert(boost::interprocess::move(aux_vect3[i])); + stdmultimap->insert(StdPairType(i, i)); + } + + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + typename MyShmMap::iterator it; + typename MyShmMap::const_iterator cit = it; + + shmmap->erase(shmmap->begin()++); + stdmap->erase(stdmap->begin()++); + shmmultimap->erase(shmmultimap->begin()++); + stdmultimap->erase(stdmultimap->begin()++); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + shmmap->erase(shmmap->begin()); + stdmap->erase(stdmap->begin()); + shmmultimap->erase(shmmultimap->begin()); + stdmultimap->erase(stdmultimap->begin()); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + //Swapping test + std::less lessfunc; + MyShmMap tmpshmemap2 (lessfunc, segment.get_segment_manager()); + MyStdMap tmpstdmap2; + MyShmMultiMap tmpshmemultimap2(lessfunc, segment.get_segment_manager()); + MyStdMultiMap tmpstdmultimap2; + shmmap->swap(tmpshmemap2); + stdmap->swap(tmpstdmap2); + shmmultimap->swap(tmpshmemultimap2); + stdmultimap->swap(tmpstdmultimap2); + shmmap->swap(tmpshmemap2); + stdmap->swap(tmpstdmap2); + shmmultimap->swap(tmpshmemultimap2); + stdmultimap->swap(tmpstdmultimap2); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; } - - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - typename MyShmMap::iterator it; - typename MyShmMap::const_iterator cit = it; - - shmmap->erase(shmmap->begin()++); - stdmap->erase(stdmap->begin()++); - shmmultimap->erase(shmmultimap->begin()++); - stdmultimap->erase(stdmultimap->begin()++); - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - shmmap->erase(shmmap->begin()); - stdmap->erase(stdmap->begin()); - shmmultimap->erase(shmmultimap->begin()); - stdmultimap->erase(stdmultimap->begin()); - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - //Swapping test - std::less lessfunc; - MyShmMap tmpshmemap2 (lessfunc, segment.get_segment_manager()); - MyStdMap tmpstdmap2; - MyShmMultiMap tmpshmemultimap2(lessfunc, segment.get_segment_manager()); - MyStdMultiMap tmpstdmultimap2; - shmmap->swap(tmpshmemap2); - stdmap->swap(tmpstdmap2); - shmmultimap->swap(tmpshmemultimap2); - stdmultimap->swap(tmpstdmultimap2); - shmmap->swap(tmpshmemap2); - stdmap->swap(tmpstdmap2); - shmmultimap->swap(tmpshmemultimap2); - stdmultimap->swap(tmpstdmultimap2); - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - //Insertion from other container //Initialize values { //This is really nasty, but we have no other simple choice IntPairType aux_vect[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect3[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } - shmmap->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); - StdPairType stdpairtype(-1, -1); - constant_iterator constant_beg(stdpairtype, 50), constant_end; - stdmap->insert(constant_beg, constant_end); - shmmultimap->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); - stdmultimap->insert(constant_beg, constant_end); + shmmap->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); + shmmultimap->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); + for(std::size_t i = 0; i != 50; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + } if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; @@ -192,34 +213,44 @@ int map_test () { IntPairType aux_vect[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect3[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect4[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect4[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect4[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect5[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect5[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect5[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } - shmmap->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); - shmmap->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); - StdPairType stdpairtype(-1, -1); - constant_iterator constant_beg(stdpairtype, 50), constant_end; - stdmap->insert(constant_beg, constant_end); - stdmap->insert(constant_beg, constant_end); - shmmultimap->insert(detail::make_move_iterator(&aux_vect4[0]), detail::make_move_iterator(aux_vect4 + 50)); - shmmultimap->insert(detail::make_move_iterator(&aux_vect5[0]), detail::make_move_iterator(aux_vect5 + 50)); - stdmultimap->insert(constant_beg, constant_end); - stdmultimap->insert(constant_beg, constant_end); + shmmap->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); + shmmap->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); + shmmultimap->insert(boost::interprocess::make_move_iterator(&aux_vect4[0]), boost::interprocess::make_move_iterator(aux_vect4 + 50)); + shmmultimap->insert(boost::interprocess::make_move_iterator(&aux_vect5[0]), boost::interprocess::make_move_iterator(aux_vect5 + 50)); + + for(std::size_t i = 0; i != 50; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + } if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; @@ -231,84 +262,158 @@ int map_test () if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; } - for(i = 0; i < max; ++i){ - shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(StdPairType(i, i)); - } - - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - for(i = 0; i < max; ++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(), 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)) - return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) - return 1; - - 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(), 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)), 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)), 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)), 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)), 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)) - return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) - return 1; - } - - //Compare count with std containers - for(i = 0; i < max; ++i){ - if(shmmap->count(IntType(i)) != stdmap->count(i)){ - return -1; + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + IntPairType aux_vect3[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } - if(shmmultimap->count(IntType(i)) != stdmultimap->count(i)){ - return -1; + for(int i = 0; i < max; ++i){ + shmmap->insert(boost::interprocess::move(aux_vect[i])); + stdmap->insert(StdPairType(i, i)); + shmmultimap->insert(boost::interprocess::move(aux_vect3[i])); + stdmultimap->insert(StdPairType(i, i)); } - } - //Now do count exercise - shmmap->erase(shmmap->begin(), shmmap->end()); - shmmultimap->erase(shmmultimap->begin(), shmmultimap->end()); - shmmap->clear(); - shmmultimap->clear(); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - for(j = 0; j < 3; ++j) - for(i = 0; i < 100; ++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)) - return 1; + for(int i = 0; i < max; ++i){ + IntPairType intpair; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(shmmap->begin(), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->begin(), StdPairType(i, i)); + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmultimap->insert(shmmultimap->begin(), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->begin(), StdPairType(i, i)); + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(shmmap->end(), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->end(), StdPairType(i, i)); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmultimap->insert(shmmultimap->end(), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->end(), StdPairType(i, i)); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(shmmap->lower_bound(IntType(i)), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->lower_bound(i), StdPairType(i, i)); + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + { + IntType i1(i); + shmmultimap->insert(shmmultimap->lower_bound(boost::interprocess::move(i1)), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->lower_bound(i), StdPairType(i, i)); + } + + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + { + IntType i1(i); + shmmap->insert(shmmap->upper_bound(boost::interprocess::move(i1)), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + { + IntType i1(i); + shmmultimap->insert(shmmultimap->upper_bound(boost::interprocess::move(i1)), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + } + + //Compare count with std containers + for(int i = 0; i < max; ++i){ + if(shmmap->count(IntType(i)) != stdmap->count(i)){ + return -1; + } + + if(shmmultimap->count(IntType(i)) != stdmultimap->count(i)){ + return -1; + } + } + + //Now do count exercise + shmmap->erase(shmmap->begin(), shmmap->end()); + shmmultimap->erase(shmmultimap->begin(), shmmultimap->end()); + shmmap->clear(); + shmmultimap->clear(); + + for(int j = 0; j < 3; ++j) + for(int i = 0; i < 100; ++i){ + IntPairType intpair; + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(boost::interprocess::move(intpair)); + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmultimap->insert(boost::interprocess::move(intpair)); + if(shmmap->count(IntType(i)) != typename MyShmMultiMap::size_type(1)) + return 1; + if(shmmultimap->count(IntType(i)) != typename MyShmMultiMap::size_type(j+1)) + return 1; + } } segment.template destroy("MyShmMap"); @@ -337,7 +442,7 @@ template IntPairType; + typedef boost::interprocess::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; const int memsize = 65536; @@ -367,10 +472,18 @@ int map_test_copyable () int i; for(i = 0; i < max; ++i){ - shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); + { + IntType i1(i), i2(i); + IntPairType intpair1(boost::interprocess::move(i1), boost::interprocess::move(i2)); + shmmap->insert(boost::interprocess::move(intpair1)); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); + } + { + IntType i1(i), i2(i); + IntPairType intpair2(boost::interprocess::move(i1), boost::interprocess::move(i2)); + shmmultimap->insert(boost::interprocess::move(intpair2)); stdmultimap->insert(StdPairType(i, i)); + } } if(!CheckEqualContainers(shmmap, stdmap)) return 1; if(!CheckEqualContainers(shmmultimap, stdmultimap)) return 1; diff --git a/test/mapped_file_test.cpp b/test/mapped_file_test.cpp index 75bb9eb..d2f6aba 100644 --- a/test/mapped_file_test.cpp +++ b/test/mapped_file_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "named_creation_template.hpp" #include @@ -29,7 +30,7 @@ struct file_destroyer ~file_destroyer() { //The last destructor will destroy the file - std::remove(FileName); + file_mapping::remove(FileName); } }; @@ -60,7 +61,7 @@ int main () { typedef boost::interprocess::detail::managed_open_or_create_impl mapped_file; - std::remove(FileName); + file_mapping::remove(FileName); test::test_named_creation(); //Create and get name, size and address @@ -76,11 +77,11 @@ int main () 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_ctor(boost::interprocess::move(file1)); mapped_file move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); } - std::remove(FileName); + file_mapping::remove(FileName); return 0; } diff --git a/test/memory_algorithm_test_template.hpp b/test/memory_algorithm_test_template.hpp index f7216d4..08436af 100644 --- a/test/memory_algorithm_test_template.hpp +++ b/test/memory_algorithm_test_template.hpp @@ -17,7 +17,7 @@ #include #include #include //std::memset -#include //std::remove +#include namespace boost { namespace interprocess { namespace test { @@ -107,7 +107,7 @@ bool test_allocation_shrink(Allocator &a) ; ++i){ std::size_t received_size; if(a.template allocation_command - ( shrink_in_place | nothrow_allocation, i*2 + ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, i*2 , i, received_size, static_cast(buffers[i])).first){ if(received_size > std::size_t(i*2)){ return false; @@ -159,7 +159,7 @@ bool test_allocation_expand(Allocator &a) preferred_size = min_size > preferred_size ? min_size : preferred_size; while(a.template allocation_command - ( expand_fwd | nothrow_allocation, min_size + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size , preferred_size, received_size, static_cast(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ @@ -197,10 +197,10 @@ bool test_allocation_shrink_and_expand(Allocator &a) for(int i = 0; true; ++i){ std::size_t received_size; void *ptr = a.template allocation_command - ( allocate_new | nothrow_allocation, i, i*2, received_size).first; + ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, i, i*2, received_size).first; if(!ptr){ ptr = a.template allocation_command - ( allocate_new | nothrow_allocation, 1, i*2, received_size).first; + ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, 1, i*2, received_size).first; if(!ptr) break; } @@ -214,7 +214,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) ; ++i){ std::size_t received_size; if(a.template allocation_command - ( shrink_in_place | nothrow_allocation, received_sizes[i] + ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_sizes[i] , i, received_size, static_cast(buffers[i])).first){ if(received_size > std::size_t(received_sizes[i])){ return false; @@ -233,7 +233,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) std::size_t received_size; std::size_t request_size = received_sizes[i]; if(a.template allocation_command - ( expand_fwd | nothrow_allocation, request_size + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, request_size , request_size, received_size, static_cast(buffers[i])).first){ if(received_size != received_sizes[i]){ return false; @@ -298,7 +298,7 @@ bool test_allocation_deallocation_expand(Allocator &a) preferred_size = min_size > preferred_size ? min_size : preferred_size; while(a.template allocation_command - ( expand_fwd | nothrow_allocation, min_size + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size , preferred_size, received_size, static_cast(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ @@ -368,7 +368,7 @@ bool test_allocation_with_reuse(Allocator &a) std::size_t min_size = (received_size + 1); std::size_t prf_size = (received_size + (i+1)*2); std::pair ret = a.raw_allocation_command - ( expand_bwd | nothrow_allocation, min_size + ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size , prf_size, received_size, static_cast(ptr), sizeof_object); if(!ret.first) break; @@ -631,7 +631,6 @@ bool test_grow_shrink_to_fit(Allocator &a) template bool test_many_equal_allocation(Allocator &a) { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; for( deallocation_type t = DirectDeallocation ; t != EndDeallocationType ; t = (deallocation_type)((int)t + 1)){ @@ -665,16 +664,17 @@ bool test_many_equal_allocation(Allocator &a) if(!a.check_sanity()) return false; + typedef typename Allocator::multiallocation_chain multiallocation_chain; std::vector buffers; for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(i+1, (i+1)*2, std::nothrow); - if(!it) + multiallocation_chain chain(a.allocate_many(i+1, (i+1)*2, std::nothrow)); + if(chain.empty()) break; - multiallocation_iterator itend; - std::size_t n = 0; - for(; it != itend; ++n){ - buffers.push_back(&*it++); + std::size_t n = chain.size(); + while(!chain.empty()){ + buffers.push_back(detail::get_pointer(chain.front())); + chain.pop_front(); } if(n != std::size_t((i+1)*2)) return false; @@ -740,7 +740,7 @@ bool test_many_equal_allocation(Allocator &a) template bool test_many_different_allocation(Allocator &a) { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + typedef typename Allocator::multiallocation_chain multiallocation_chain; const std::size_t ArraySize = 11; std::size_t requested_sizes[ArraySize]; for(std::size_t i = 0; i < ArraySize; ++i){ @@ -777,13 +777,13 @@ bool test_many_different_allocation(Allocator &a) std::vector buffers; for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); - if(!it) + multiallocation_chain chain(a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow)); + if(chain.empty()) break; - multiallocation_iterator itend; - std::size_t n = 0; - for(; it != itend; ++n){ - buffers.push_back(&*it++); + std::size_t n = chain.size(); + while(!chain.empty()){ + buffers.push_back(detail::get_pointer(chain.front())); + chain.pop_front(); } if(n != ArraySize) return false; @@ -846,9 +846,9 @@ bool test_many_different_allocation(Allocator &a) template bool test_many_deallocation(Allocator &a) { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + typedef typename Allocator::multiallocation_chain multiallocation_chain; const std::size_t ArraySize = 11; - std::vector buffers; + vector buffers; std::size_t requested_sizes[ArraySize]; for(std::size_t i = 0; i < ArraySize; ++i){ requested_sizes[i] = 4*i; @@ -857,13 +857,13 @@ bool test_many_deallocation(Allocator &a) { for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); - if(!it) + multiallocation_chain chain = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); + if(chain.empty()) break; - buffers.push_back(it); + buffers.push_back(boost::interprocess::move(chain)); } for(int i = 0, max = (int)buffers.size(); i != max; ++i){ - a.deallocate_many(buffers[i]); + a.deallocate_many(boost::interprocess::move(buffers[i])); } buffers.clear(); bool ok = free_memory == a.get_free_memory() && @@ -873,13 +873,13 @@ bool test_many_deallocation(Allocator &a) { for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(i*4, ArraySize, std::nothrow); - if(!it) + multiallocation_chain chain(a.allocate_many(i*4, ArraySize, std::nothrow)); + if(chain.empty()) break; - buffers.push_back(it); + buffers.push_back(boost::interprocess::move(chain)); } for(int i = 0, max = (int)buffers.size(); i != max; ++i){ - a.deallocate_many(buffers[i]); + a.deallocate_many(boost::interprocess::move(buffers[i])); } buffers.clear(); diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 2ac7fb8..ee62582 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -21,10 +21,11 @@ namespace test { class movable_int { - movable_int(const movable_int&); - movable_int &operator= (const movable_int&); + movable_int(movable_int&); + movable_int &operator= (movable_int&); public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(movable_int) movable_int() : m_int(0) @@ -34,23 +35,12 @@ class movable_int : m_int(a) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_int(detail::moved_object mmi) - : m_int(mmi.get().m_int) - { mmi.get().m_int = 0; } - #else - movable_int(movable_int &&mmi) + movable_int(BOOST_INTERPROCESS_RV_REF(movable_int) mmi) : m_int(mmi.m_int) { mmi.m_int = 0; } - #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_int & operator= (detail::moved_object mmi) - { this->m_int = mmi.get().m_int; mmi.get().m_int = 0; return *this; } - #else - movable_int & operator= (movable_int &&mmi) + movable_int & operator= (BOOST_INTERPROCESS_RV_REF(movable_int) mmi) { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } - #endif movable_int & operator= (int i) { this->m_int = i; return *this; } @@ -92,6 +82,7 @@ std::basic_ostream & operator<< class movable_and_copyable_int { public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(movable_and_copyable_int) movable_and_copyable_int() : m_int(0) @@ -108,23 +99,12 @@ class movable_and_copyable_int movable_and_copyable_int &operator= (const movable_and_copyable_int& mi) { this->m_int = mi.m_int; return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_and_copyable_int(detail::moved_object mmi) - : m_int(mmi.get().m_int) - { mmi.get().m_int = 0; } - #else - movable_and_copyable_int(movable_and_copyable_int &&mmi) + movable_and_copyable_int(BOOST_INTERPROCESS_RV_REF(movable_and_copyable_int) mmi) : m_int(mmi.m_int) { mmi.m_int = 0; } - #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_and_copyable_int & operator= (detail::moved_object mmi) - { this->m_int = mmi.get().m_int; mmi.get().m_int = 0; return *this; } - #else - movable_and_copyable_int & operator= (movable_and_copyable_int &&mmi) + movable_and_copyable_int & operator= (BOOST_INTERPROCESS_RV_REF(movable_and_copyable_int) mmi) { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } - #endif movable_and_copyable_int & operator= (int i) { this->m_int = i; return *this; } @@ -167,26 +147,6 @@ std::basic_ostream & operator<< } //namespace interprocess { } //namespace boost { -namespace boost{ -namespace interprocess{ - -template<> -struct is_movable -{ - public: - enum { value = true }; -}; - -template<> -struct is_movable -{ - public: - enum { value = true }; -}; - -} //namespace interprocess{ -} //namespace boost{ - #include #endif //#ifndef BOOST_INTERPROCESS_TEST_MOVABLE_INT_HEADER diff --git a/test/multi_index_test.cpp b/test/multi_index_test.cpp index 40ce912..ad3e75b 100644 --- a/test/multi_index_test.cpp +++ b/test/multi_index_test.cpp @@ -28,8 +28,8 @@ using namespace boost::interprocess; namespace bmi = boost::multi_index; -typedef managed_shared_memory::allocator::type char_allocator; -typedef basic_string, char_allocator>shm_string; +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator> shm_string; //Data to insert in shared memory struct employee @@ -75,33 +75,7 @@ template class bmi::multi_index_container< , 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, @@ -114,33 +88,7 @@ template class bmi::multi_index_container< , 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; diff --git a/test/set_test.hpp b/test/set_test.hpp index db8766f..00c1d2f 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -17,7 +17,7 @@ #include #include #include "print_container.hpp" -#include +#include #include #include "get_process_id_name.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] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -72,21 +72,21 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect3[i] = detail::move_impl(move_me); + aux_vect3[i] = boost::interprocess::move(move_me); } MyShmSet *shmset2 = segment.template construct("MyShmSet2") - (detail::make_move_iterator(&aux_vect[0]) - , detail::make_move_iterator(aux_vect + 50) + (boost::interprocess::make_move_iterator(&aux_vect[0]) + , boost::interprocess::make_move_iterator(aux_vect + 50) , std::less(), segment.get_segment_manager()); MyStdSet *stdset2 = new MyStdSet(aux_vect2, aux_vect2 + 50); MyShmMultiSet *shmmultiset2 = segment.template construct("MyShmMultiSet2") - (detail::make_move_iterator(&aux_vect3[0]) - , detail::make_move_iterator(aux_vect3 + 50) + (boost::interprocess::make_move_iterator(&aux_vect3[0]) + , boost::interprocess::make_move_iterator(aux_vect3 + 50) , std::less(), segment.get_segment_manager()); MyStdMultiSet *stdmultiset2 = new MyStdMultiSet(aux_vect2, aux_vect2 + 50); @@ -108,20 +108,20 @@ int set_test () int i, j; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::move_impl(move_me)" << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::move(move_me)" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me)" << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::move(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] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -192,19 +192,19 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = detail::move_impl(move_me); + aux_vect3[i] = boost::interprocess::move(move_me); } - shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); + shmset->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); stdset->insert(aux_vect2, aux_vect2 + 50); - shmmultiset->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); + shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); stdmultiset->insert(aux_vect2, aux_vect2 + 50); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::make_move_iterator(&aux_vect[0])..." << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::make_move_iterator(&aux_vect[0])..." << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::make_move_iterator(&aux_vect3[0]), ..." << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), ..." << std::endl; return 1; } @@ -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] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -237,35 +237,35 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = detail::move_impl(move_me); + aux_vect3[i] = boost::interprocess::move(move_me); } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect4[i] = detail::move_impl(move_me); + aux_vect4[i] = boost::interprocess::move(move_me); } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect5[i] = detail::move_impl(move_me); + aux_vect5[i] = boost::interprocess::move(move_me); } - shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); - shmset->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); + shmset->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); + shmset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); stdset->insert(aux_vect2, aux_vect2 + 50); stdset->insert(aux_vect2, aux_vect2 + 50); - shmmultiset->insert(detail::make_move_iterator(&aux_vect4[0]), detail::make_move_iterator(aux_vect4 + 50)); - shmmultiset->insert(detail::make_move_iterator(&aux_vect5[0]), detail::make_move_iterator(aux_vect5 + 50)); + shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect4[0]), boost::interprocess::make_move_iterator(aux_vect4 + 50)); + shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect5[0]), boost::interprocess::make_move_iterator(aux_vect5 + 50)); stdmultiset->insert(aux_vect2, aux_vect2 + 50); stdmultiset->insert(aux_vect2, aux_vect2 + 50); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::make_move_iterator(&aux_vect3[0])..." << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0])..." << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::make_move_iterator(&aux_vect5[0])..." << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect5[0])..." << std::endl; return 1; } @@ -285,88 +285,88 @@ int set_test () for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::move_impl(move_me)) try 2" << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::move(move_me)) try 2" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me2)) try 2" << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::move(move_me2)) try 2" << std::endl; return 1; } for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(shmset->begin(), detail::move_impl(move_me)); + shmset->insert(shmset->begin(), boost::interprocess::move(move_me)); stdset->insert(stdset->begin(), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2)); + shmmultiset->insert(shmmultiset->begin(), boost::interprocess::move(move_me2)); stdmultiset->insert(stdmultiset->begin(), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->begin(), detail::move_impl(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->begin(), boost::interprocess::move(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), boost::interprocess::move(move_me2))" << std::endl; return 1; } IntType move_me3(i); - shmset->insert(shmset->end(), detail::move_impl(move_me3)); + shmset->insert(shmset->end(), boost::interprocess::move(move_me3)); stdset->insert(stdset->end(), i); IntType move_me4(i); - shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4)); + shmmultiset->insert(shmmultiset->end(), boost::interprocess::move(move_me4)); stdmultiset->insert(stdmultiset->end(), i); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->end(), detail::move_impl(move_me3))" << std::endl; + std::cout << "Error in shmset->insert(shmset->end(), boost::interprocess::move(move_me3))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->end(), boost::interprocess::move(move_me4))" << std::endl; return 1; } { IntType move_me(i); - shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me)); + shmset->insert(shmset->upper_bound(move_me), boost::interprocess::move(move_me)); stdset->insert(stdset->upper_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2)); + shmmultiset->insert(shmmultiset->upper_bound(move_me2), boost::interprocess::move(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), detail::move_impl(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), boost::interprocess::move(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), boost::interprocess::move(move_me2))" << std::endl; return 1; } } { IntType move_me(i); - shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2)); + shmset->insert(shmset->lower_bound(move_me), boost::interprocess::move(move_me2)); stdset->insert(stdset->lower_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2)); + shmmultiset->insert(shmmultiset->lower_bound(move_me2), boost::interprocess::move(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), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), boost::interprocess::move(move_me2))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), boost::interprocess::move(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(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(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(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(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 6f363f3..d424017 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -19,6 +19,12 @@ using namespace boost::interprocess; +shared_memory_object get_shared_memory_mapping() +{ + shared_memory_object sh; + return shared_memory_object(boost::interprocess::move(sh)); +} + int main () { try{ @@ -139,9 +145,10 @@ int main () { //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_ctor(boost::interprocess::move(mapping)); shared_memory_object move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); + shared_memory_object ret(get_shared_memory_mapping()); } } catch(std::exception &exc){ @@ -152,5 +159,3 @@ int main () shared_memory_object::remove(test::get_process_id_name()); return 0; } - -#include diff --git a/test/shared_memory_test.cpp b/test/shared_memory_test.cpp index 976a4a2..8f99380 100644 --- a/test/shared_memory_test.cpp +++ b/test/shared_memory_test.cpp @@ -31,13 +31,14 @@ struct eraser } }; +typedef detail::managed_open_or_create_impl shared_memory; + //This wrapper is necessary to have a common constructor //in generic named_creation_template functions class shared_memory_creation_test_wrapper : public eraser - , public detail::managed_open_or_create_impl + , public shared_memory { - typedef detail::managed_open_or_create_impl shared_memory; public: shared_memory_creation_test_wrapper(create_only_t) @@ -56,8 +57,6 @@ class shared_memory_creation_test_wrapper int main () { - typedef detail::managed_open_or_create_impl shared_memory; - try{ shared_memory_object::remove(ShmName); test::test_named_creation(); @@ -76,9 +75,9 @@ int main () 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_ctor(boost::interprocess::move(shm1)); shared_memory move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); } } catch(std::exception &ex){ diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index 38c08d1..877a00e 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -25,6 +25,10 @@ #include #include "get_process_id_name.hpp" + +#include +#include + using namespace boost::interprocess; class base_class @@ -613,7 +617,6 @@ void test_alias() shared_memory_object::remove(process_name.c_str()); } - int main() { if(0 != simple_test()) @@ -626,8 +629,7 @@ int main() return 1; test_alias(); - - return 0; } #include + diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 5944f35..a184eba 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include @@ -54,10 +53,9 @@ int main () { //Now test move semantics slist original; - slist move_ctor(detail::move_impl(original)); + slist move_ctor(boost::interprocess::move(original)); slist move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } @@ -79,8 +77,7 @@ int main () if(!boost::interprocess::test::test_emplace < slist, Options>()) return 1; - - return 0; } #include + diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp new file mode 100644 index 0000000..5df1ef3 --- /dev/null +++ b/test/stable_vector_test.cpp @@ -0,0 +1,90 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +#include +#include +#include +#include "allocator_v1.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "dummy_test_allocator.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//Explicit instantiation to detect compilation errors +//template class stable_vector >; + +class recursive_vector +{ + public: + int id_; + stable_vector vector_; +}; + +void recursive_vector_test()//Test for recursive types +{ + stable_vector recursive_vector_vector; +} + +int main() +{ + recursive_vector_test(); + { + //Now test move semantics + stable_vector original; + stable_vector move_ctor(boost::interprocess::move(original)); + stable_vector move_assign; + move_assign = boost::interprocess::move(move_ctor); + move_assign.swap(original); + } + typedef allocator ShmemAllocator; + typedef stable_vector MyVector; + + typedef test::allocator_v1 ShmemV1Allocator; + typedef stable_vector MyV1Vector; + + typedef allocator ShmemMoveAllocator; + typedef stable_vector MyMoveVector; + + typedef allocator ShmemCopyMoveAllocator; + typedef stable_vector MyCopyMoveVector; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::interprocess::test::test_emplace + < stable_vector, Options>()) + return 1; + + return 0; +} + +#include diff --git a/test/string_test.cpp b/test/string_test.cpp index 62318bb..747900b 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(detail::move_impl(auxShmString)); + shmStringVect->push_back(boost::interprocess::move(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(), detail::move_impl(auxShmString)); + shmStringVect->insert(shmStringVect->begin(), boost::interprocess::move(auxShmString)); stdStringVect->insert(stdStringVect->begin(), auxStdString); } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index 21b4668..ff60dce 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include @@ -33,32 +32,7 @@ /////////////////////////////////////////////////////////////////// using namespace boost::interprocess; -/* -//Explicit instantiation to detect compilation errors -template class boost::interprocess::set - - ,test::dummy_test_allocator >; -template class boost::interprocess::map - - ,test::dummy_test_allocator > >; - -template class boost::interprocess::multiset - - ,test::dummy_test_allocator >; - -template class boost::interprocess::multimap - - ,test::dummy_test_allocator > >; -*/ //Customize managed_shared_memory class typedef basic_managed_shared_memory -void test_move_semantics() +void test_move() { //Now test move semantics C original; - C move_ctor(detail::move_impl(original)); + C move_ctor(boost::interprocess::move(original)); C move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } @@ -181,10 +154,10 @@ int main () } //Now test move semantics { - test_move_semantics >(); - test_move_semantics >(); - test_move_semantics >(); - test_move_semantics >(); + test_move >(); + test_move >(); + test_move >(); + test_move >(); } using namespace boost::interprocess::detail; @@ -221,6 +194,7 @@ int main () return 1; } + if (0 != test::map_test, MapOptions>()) return 1; + return 0; } diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp index be43789..35d63bb 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(detail::move_impl(my_ptr3)); + my_unique_ptr_class my_ptr4(boost::interprocess::move(my_ptr3)); //Construct a list and fill MyList list(segment.get_segment_manager()); //Insert from my_unique_ptr_class - list.push_front(detail::move_impl(my_ptr)); - list.push_back(detail::move_impl(my_ptr2)); + list.push_front(boost::interprocess::move(my_ptr)); + list.push_back(boost::interprocess::move(my_ptr2)); //Check pointers assert(my_ptr.get() == 0); @@ -85,20 +85,13 @@ int main() assert(list.begin()->get() == ptr1); assert(list.rbegin()->get() == ptr2); - //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); - //Construct a set and fill typedef std::less set_less_t; MySet set(set_less_t(), segment.get_segment_manager()); //Insert in set from list passing ownership - set.insert(detail::move_impl(*list.begin())); - set.insert(detail::move_impl(*list.rbegin())); + set.insert(boost::interprocess::move(*list.begin())); + set.insert(boost::interprocess::move(*list.rbegin())); //Check pointers assert(list.begin()->get() == 0); @@ -120,12 +113,12 @@ int main() //Insert from my_unique_ptr_class if(ptr1 < ptr2){ - vector.insert(vector.begin(), detail::move_impl(*set.begin())); - vector.insert(vector.end(), detail::move_impl(*set.rbegin())); + vector.insert(vector.begin(), boost::interprocess::move(*set.begin())); + vector.insert(vector.end(), boost::interprocess::move(*set.rbegin())); } else{ - vector.insert(vector.begin(), detail::move_impl(*set.rbegin())); - vector.insert(vector.end(), detail::move_impl(*set.begin())); + vector.insert(vector.begin(), boost::interprocess::move(*set.rbegin())); + vector.insert(vector.end(), boost::interprocess::move(*set.begin())); } //Check pointers @@ -134,14 +127,14 @@ int main() assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); - MyVector vector2(detail::move_impl(vector)); + MyVector vector2(boost::interprocess::move(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 = detail::move_impl(b); + a = boost::interprocess::move(b); } shared_memory_object::remove(process_name.c_str()); return 0; diff --git a/test/upgradable_mutex_test.cpp b/test/upgradable_mutex_test.cpp index 846743a..238196b 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(detail::move_impl(lock)); - lock.swap(detail::move_impl(e_lock)); + scoped_lock e_lock(boost::interprocess::move(lock)); + lock.swap(e_lock); } { scoped_lock lock(mut); scoped_lock e_lock(mut2); - e_lock = detail::move_impl(lock); + e_lock = boost::interprocess::move(lock); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() - scoped_lock e_lock(detail::move_impl(u_lock)); + scoped_lock e_lock(boost::interprocess::move(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(detail::move_impl(u_lock)); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(u_lock)); + e_lock = boost::interprocess::move(moved); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() - scoped_lock e_lock(detail::move_impl(u_lock), try_to_lock); + scoped_lock e_lock(boost::interprocess::move(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(detail::move_impl(u_lock), try_to_lock); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(u_lock), try_to_lock); + e_lock = boost::interprocess::move(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(detail::move_impl(u_lock), t); + scoped_lock e_lock(boost::interprocess::move(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(detail::move_impl(u_lock), t); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(u_lock), t); + e_lock = boost::interprocess::move(moved); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() - scoped_lock e_lock(detail::move_impl(s_lock), try_to_lock); + scoped_lock e_lock(boost::interprocess::move(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(detail::move_impl(s_lock), try_to_lock); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(s_lock), try_to_lock); + e_lock = boost::interprocess::move(moved); } //Conversions to upgradable_lock { upgradable_lock lock(mut); - upgradable_lock u_lock(detail::move_impl(lock)); - lock.swap(detail::move_impl(u_lock)); + upgradable_lock u_lock(boost::interprocess::move(lock)); + lock.swap(u_lock); } { upgradable_lock lock(mut); upgradable_lock u_lock(mut2); - upgradable_lock moved(detail::move_impl(lock)); - u_lock = detail::move_impl(moved); + upgradable_lock moved(boost::interprocess::move(lock)); + u_lock = boost::interprocess::move(moved); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() - upgradable_lock u_lock(detail::move_impl(s_lock), try_to_lock); + upgradable_lock u_lock(boost::interprocess::move(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(detail::move_impl(s_lock), try_to_lock); - u_lock = detail::move_impl(moved); + upgradable_lock moved(boost::interprocess::move(s_lock), try_to_lock); + u_lock = boost::interprocess::move(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() - upgradable_lock u_lock(detail::move_impl(e_lock)); + upgradable_lock u_lock(boost::interprocess::move(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(detail::move_impl(e_lock)); - u_lock = detail::move_impl(moved); + upgradable_lock moved(boost::interprocess::move(e_lock)); + u_lock = boost::interprocess::move(moved); } //Conversions to sharable_lock { sharable_lock lock(mut); - sharable_lock s_lock(detail::move_impl(lock)); - lock.swap(detail::move_impl(s_lock)); + sharable_lock s_lock(boost::interprocess::move(lock)); + lock.swap(s_lock); } { sharable_lock lock(mut); sharable_lock s_lock(mut2); - sharable_lock moved(detail::move_impl(lock)); - s_lock = detail::move_impl(moved); + sharable_lock moved(boost::interprocess::move(lock)); + s_lock = boost::interprocess::move(moved); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() - sharable_lock s_lock(detail::move_impl(u_lock)); + sharable_lock s_lock(boost::interprocess::move(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(detail::move_impl(u_lock)); - s_lock = detail::move_impl(moved); + sharable_lock moved(boost::interprocess::move(u_lock)); + s_lock = boost::interprocess::move(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() - sharable_lock s_lock(detail::move_impl(e_lock)); + sharable_lock s_lock(boost::interprocess::move(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(detail::move_impl(e_lock)); - s_lock = detail::move_impl(moved); + sharable_lock moved(boost::interprocess::move(e_lock)); + s_lock = boost::interprocess::move(moved); } } diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index fdcab2d..13e7b0a 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -59,19 +59,17 @@ int main () { //Now test move semantics managed_heap_memory original(memsize); - managed_heap_memory move_ctor(detail::move_impl(original)); + managed_heap_memory move_ctor(boost::interprocess::move(original)); managed_heap_memory move_assign; - move_assign = detail::move_impl(move_ctor); - original.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); original.swap(move_assign); } { //Now test move semantics managed_external_buffer original(create_only, static_buffer, memsize); - managed_external_buffer move_ctor(detail::move_impl(original)); + managed_external_buffer move_ctor(boost::interprocess::move(original)); managed_external_buffer move_assign; - move_assign = detail::move_impl(move_ctor); - original.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); original.swap(move_assign); } @@ -84,13 +82,13 @@ int main () //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_external_buffer temp_external(boost::interprocess::move(user_buffer)); + user_default = boost::interprocess::move(temp_external); + user_buffer = boost::interprocess::move(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); + wmanaged_heap_memory temp_heap(boost::interprocess::move(heap_buffer)); + heap_default = boost::interprocess::move(temp_heap); + heap_buffer = boost::interprocess::move(heap_default); } //Initialize memory diff --git a/test/vector_test.cpp b/test/vector_test.cpp index afb1e12..d78974f 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -44,16 +44,7 @@ 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; @@ -94,17 +85,16 @@ int main() { //Now test move semantics vector original; - vector move_ctor(detail::move_impl(original)); + vector move_ctor(boost::interprocess::move(original)); vector move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } typedef allocator ShmemAllocator; typedef vector MyVector; - //typedef allocator ShmemVolatileAllocator; - //typedef vector MyVolatileVector; + typedef test::allocator_v1 ShmemV1Allocator; + typedef vector MyV1Vector; typedef allocator ShmemMoveAllocator; typedef vector MyMoveVector; @@ -115,8 +105,8 @@ int main() if(test::vector_test()) return 1; - //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 dd3e46f..e4c891d 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -17,8 +17,8 @@ #include #include -#include #include +#include #include "print_container.hpp" #include "check_equal_containers.hpp" #include "movable_int.hpp" @@ -32,14 +32,14 @@ namespace interprocess{ namespace test{ template -bool copyable_only(V1 *, V2 *, detail::false_type) +bool copyable_only(V1 *, V2 *, boost::interprocess::detail::false_type) { return true; } //Function to check if both sets are equal template -bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) +bool copyable_only(V1 *shmvector, V2 *stdvector, boost::interprocess::detail::true_type) { typedef typename V1::value_type IntType; std::size_t size = shmvector->size(); @@ -50,18 +50,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, detail::move_impl(move_me)); + shmvector->insert(shmvector->begin()+size/2, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(2); - shmvector->assign(shmvector->size()/2, detail::move_impl(move_me)); + shmvector->assign(shmvector->size()/2, boost::interprocess::move(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, detail::move_impl(move_me)); + shmvector->assign(shmvector->size()*3-1, boost::interprocess::move(move_me)); stdvector->assign(stdvector->size()*3-1, 3); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } @@ -111,8 +111,9 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType new_int(i); - shmvector->insert(shmvector->end(), detail::move_impl(new_int)); + shmvector->insert(shmvector->end(), boost::interprocess::move(new_int)); stdvector->insert(stdvector->end(), i); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -133,7 +134,8 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = detail::move_impl(new_int); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + aux_vect[i] = boost::interprocess::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -141,8 +143,8 @@ int vector_test() } shmvector->insert(shmvector->end() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -156,15 +158,15 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = detail::move_impl(new_int); + aux_vect[i] = boost::interprocess::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } shmvector->insert(shmvector->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; } @@ -174,7 +176,7 @@ int vector_test() if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; IntType push_back_this(1); - shmvector->push_back(detail::move_impl(push_back_this)); + shmvector->push_back(boost::interprocess::move(push_back_this)); stdvector->push_back(int(1)); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -189,7 +191,7 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType insert_this(i); - shmvector->insert(shmvector->begin(), detail::move_impl(insert_this)); + shmvector->insert(shmvector->begin(), boost::interprocess::move(insert_this)); stdvector->insert(stdvector->begin(), i); } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -204,6 +206,18 @@ int vector_test() stdvector->assign(l.begin(), l.end()); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; } +/* + std::size_t cap = shmvector->capacity(); + shmvector->reserve(cap*2); + stdvector->reserve(cap*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->resize(0); + stdvector->resize(0); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->resize(cap*2); + stdvector->resize(cap*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; +*/ delete stdvector; segment.template destroy("MyShmVector"); diff --git a/test/windows_shared_memory_mapping_test.cpp b/test/windows_shared_memory_mapping_test.cpp index 8bd4f10..0135367 100644 --- a/test/windows_shared_memory_mapping_test.cpp +++ b/test/windows_shared_memory_mapping_test.cpp @@ -10,7 +10,7 @@ #include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS #include #include diff --git a/test/windows_shared_memory_test.cpp b/test/windows_shared_memory_test.cpp index 2f8512e..ae5ac7f 100644 --- a/test/windows_shared_memory_test.cpp +++ b/test/windows_shared_memory_test.cpp @@ -11,7 +11,7 @@ #include #include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS #include #include @@ -32,16 +32,14 @@ static const char *name_initialization_routine() } static const std::size_t ShmSize = 1000; +typedef detail::managed_open_or_create_impl + windows_shared_memory_t; //This wrapper is necessary to have a common constructor //in generic named_creation_template functions class shared_memory_creation_test_wrapper - : public detail::managed_open_or_create_impl - + : public windows_shared_memory_t { - typedef detail::managed_open_or_create_impl - windows_shared_memory_t; - public: shared_memory_creation_test_wrapper(create_only_t) : windows_shared_memory_t(create_only, name_initialization_routine(), ShmSize) @@ -59,8 +57,6 @@ class shared_memory_creation_test_wrapper int main () { - typedef detail::managed_open_or_create_impl windows_shared_memory_t; - try{ test::test_named_creation(); } @@ -79,6 +75,6 @@ int main() return 0; } -#endif //#ifdef BOOST_WINDOWS +#endif //#ifdef BOOST_INTERPROCESS_WINDOWS #include