From 9a6e1441914918ccf0b1925f6aa6a89a49f60f31 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Jul 2019 17:38:40 +0200 Subject: [PATCH 01/10] Import plf list header for modification Taken from https://www.plflib.org/list.htm --- src/list.h | 3431 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3431 insertions(+) create mode 100644 src/list.h diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000000000..cfbfa1495eb8b --- /dev/null +++ b/src/list.h @@ -0,0 +1,3431 @@ +// Copyright (c) 2019, Matthew Bentley (mattreecebentley@gmail.com) www.plflib.org + +// zLib license (https://www.zlib.net/zlib_license.html): +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + + +#ifndef PLF_LIST_H +#define PLF_LIST_H + + +#define PLF_LIST_BLOCK_MIN static_cast((sizeof(node) * 8 > (sizeof(*this) + sizeof(group)) * 2) ? 8 : (((sizeof(*this) + sizeof(group)) * 2) / sizeof(node)) + 1) +#define PLF_LIST_BLOCK_MAX 2048 + + + +// Compiler-specific defines used by list: + +#if defined(_MSC_VER) + #define PLF_LIST_FORCE_INLINE __forceinline + + #if _MSC_VER < 1600 + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() + #elif _MSC_VER == 1600 + #define PLF_LIST_MOVE_SEMANTICS_SUPPORT + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() + #elif _MSC_VER == 1700 + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_MOVE_SEMANTICS_SUPPORT + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() + #elif _MSC_VER == 1800 + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_VARIADICS_SUPPORT // Variadics, in this context, means both variadic templates and variadic macros are supported + #define PLF_LIST_MOVE_SEMANTICS_SUPPORT + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() + #define PLF_LIST_INITIALIZER_LIST_SUPPORT + #elif _MSC_VER >= 1900 + #define PLF_LIST_ALIGNMENT_SUPPORT + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_VARIADICS_SUPPORT + #define PLF_LIST_MOVE_SEMANTICS_SUPPORT + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) + #define PLF_LIST_INITIALIZER_LIST_SUPPORT + #endif + + #if defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L) + #define PLF_LIST_CONSTEXPR constexpr + #else + #define PLF_LIST_CONSTEXPR + #endif + +#elif defined(__cplusplus) && __cplusplus >= 201103L // C++11 support, at least + #define PLF_LIST_FORCE_INLINE // note: GCC creates faster code without forcing inline + + #if defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__clang__) // If compiler is GCC/G++ + #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 // 4.2 and below do not support variadic templates + #define PLF_LIST_VARIADICS_SUPPORT + #endif + #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 // 4.3 and below do not support initializer lists + #define PLF_LIST_INITIALIZER_LIST_SUPPORT + #endif + #if (__GNUC__ == 4 && __GNUC_MINOR__ < 6) || __GNUC__ < 4 + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #elif __GNUC__ < 6 + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept + #else // C++17 support + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) + #endif + #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4 + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #endif + #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4 + #define PLF_LIST_ALIGNMENT_SUPPORT + #endif + #if __GNUC__ >= 5 // GCC v4.9 and below do not support std::is_trivially_copyable + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #endif + #elif defined(__GLIBCXX__) // Using another compiler type with libstdc++ - we are assuming full c++11 compliance for compiler - which may not be true + #if __GLIBCXX__ >= 20080606 // libstdc++ 4.2 and below do not support variadic templates + #define PLF_LIST_VARIADICS_SUPPORT + #endif + #if __GLIBCXX__ >= 20090421 // libstdc++ 4.3 and below do not support initializer lists + #define PLF_LIST_INITIALIZER_LIST_SUPPORT + #endif + #if __GLIBCXX__ >= 20160111 + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) + #elif __GLIBCXX__ >= 20120322 + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept + #else + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #endif + #if __GLIBCXX__ >= 20130322 + #define PLF_LIST_ALIGNMENT_SUPPORT + #endif + #if __GLIBCXX__ >= 20150422 // libstdc++ v4.9 and below do not support std::is_trivially_copyable + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #endif + #elif defined(_LIBCPP_VERSION) + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_VARIADICS_SUPPORT + #define PLF_LIST_INITIALIZER_LIST_SUPPORT + #define PLF_LIST_ALIGNMENT_SUPPORT + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept + + #if !(defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)) + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #endif + #else // Assume type traits and initializer support for other compilers and standard libraries + #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #define PLF_LIST_ALIGNMENT_SUPPORT + #define PLF_LIST_VARIADICS_SUPPORT + #define PLF_LIST_INITIALIZER_LIST_SUPPORT + #define PLF_LIST_TYPE_TRAITS_SUPPORT + #define PLF_LIST_NOEXCEPT noexcept + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept + #endif + + #if __cplusplus >= 201703L + #if defined(__clang__) && ((__clang_major__ == 3 && __clang_minor__ == 9) || __clang_major__ > 3) + #define PLF_LIST_CONSTEXPR constexpr + #elif defined(__GNUC__) && __GNUC__ >= 7 + #define PLF_LIST_CONSTEXPR constexpr + #elif !defined(__clang__) && !defined(__GNUC__) + #define PLF_LIST_CONSTEXPR constexpr // assume correct C++17 implementation for other compilers + #else + #define PLF_LIST_CONSTEXPR + #endif + #else + #define PLF_LIST_CONSTEXPR + #endif + + #define PLF_LIST_MOVE_SEMANTICS_SUPPORT +#else + #define PLF_LIST_FORCE_INLINE + #define PLF_LIST_NOEXCEPT throw() + #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) + #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) + #define PLF_LIST_CONSTEXPR +#endif + + + +#ifdef PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + #ifdef PLF_LIST_VARIADICS_SUPPORT + #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) std::allocator_traits::construct(allocator_instance, location, __VA_ARGS__) + #else + #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, data) std::allocator_traits::construct(allocator_instance, location, data) + #endif + + #define PLF_LIST_DESTROY(the_allocator, allocator_instance, location) std::allocator_traits::destroy(allocator_instance, location) + #define PLF_LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) std::allocator_traits::allocate(allocator_instance, size, hint) + #define PLF_LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) std::allocator_traits::allocate(*this, size, hint) + #define PLF_LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) std::allocator_traits::deallocate(allocator_instance, location, size) +#else + #ifdef PLF_LIST_VARIADICS_SUPPORT + #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) allocator_instance.construct(location, __VA_ARGS__) + #else + #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, data) allocator_instance.construct(location, data) + #endif + + #define PLF_LIST_DESTROY(the_allocator, allocator_instance, location) allocator_instance.destroy(location) + #define PLF_LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) allocator_instance.allocate(size, hint) + #define PLF_LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) the_allocator::allocate(size, hint) + #define PLF_LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) allocator_instance.deallocate(location, size) +#endif + + + + +#include // memmove, memcpy +#include // assert +#include // std::numeric_limits +#include // std::uninitialized_copy, std::allocator +#include // std::bidirectional_iterator_tag + + +#ifndef GFX_TIMSORT_HPP + #include // std::sort +#endif + +#ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + #include // std::is_trivially_destructible, etc +#endif + +#ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + #include // std::move +#endif + +#ifdef PLF_LIST_INITIALIZER_LIST_SUPPORT + #include +#endif + + + + +namespace plf +{ + + + +template > class list : private element_allocator_type +{ +public: + // Standard container typedefs: + typedef element_type value_type; + typedef element_allocator_type allocator_type; + typedef unsigned short group_size_type; + + #ifdef PLF_LIST_ALLOCATOR_TRAITS_SUPPORT // C++11 + typedef typename std::allocator_traits::size_type size_type; + typedef typename std::allocator_traits::difference_type difference_type; + typedef element_type & reference; + typedef const element_type & const_reference; + typedef typename std::allocator_traits::pointer pointer; + typedef typename std::allocator_traits::const_pointer const_pointer; + #else + typedef typename element_allocator_type::size_type size_type; + typedef typename element_allocator_type::difference_type difference_type; + typedef typename element_allocator_type::reference reference; + typedef typename element_allocator_type::const_reference const_reference; + typedef typename element_allocator_type::pointer pointer; + typedef typename element_allocator_type::const_pointer const_pointer; + #endif + + + // Iterator declarations: + template class list_iterator; + typedef list_iterator iterator; + typedef list_iterator const_iterator; + friend class list_iterator; // Using 'iterator' typedef name here is illegal under C++03 + friend class list_iterator; + + template class list_reverse_iterator; + typedef list_reverse_iterator reverse_iterator; + typedef list_reverse_iterator const_reverse_iterator; + friend class list_reverse_iterator; + friend class list_reverse_iterator; + + +private: + struct group; // forward declarations for typedefs below + struct node; + + #ifdef PLF_LIST_ALLOCATOR_TRAITS_SUPPORT // C++11 + typedef typename std::allocator_traits::template rebind_alloc group_allocator_type; + typedef typename std::allocator_traits::template rebind_alloc node_allocator_type; + typedef typename std::allocator_traits::pointer group_pointer_type; + typedef typename std::allocator_traits::pointer node_pointer_type; + typedef typename std::allocator_traits::template rebind_alloc node_pointer_allocator_type; + #else + typedef typename element_allocator_type::template rebind::other group_allocator_type; + typedef typename element_allocator_type::template rebind::other node_allocator_type; + typedef typename group_allocator_type::pointer group_pointer_type; + typedef typename node_allocator_type::pointer node_pointer_type; + typedef typename element_allocator_type::template rebind::other node_pointer_allocator_type; + #endif + + + + struct node_base + { + node_pointer_type next, previous; + + node_base() + {} + + node_base(const node_pointer_type &n, const node_pointer_type &p): + next(n), + previous(p) + {} + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + node_base(node_pointer_type &&n, node_pointer_type &&p) PLF_LIST_NOEXCEPT: + next(std::move(n)), + previous(std::move(p)) + {} + #endif + }; + + + + struct node : public node_base + { + element_type element; + + node(const node_pointer_type next, const node_pointer_type previous, const element_type &source): + node_base(next, previous), + element(source) + {} + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + node(node_pointer_type &&next, node_pointer_type &&previous, element_type &&source) PLF_LIST_NOEXCEPT: + node_base(std::move(next), std::move(previous)), + element(std::move(source)) + {} + #endif + + + #ifdef PLF_LIST_VARIADICS_SUPPORT + template + node(node_pointer_type const next, node_pointer_type const previous, arguments&&... parameters): + node_base(next, previous), + element(std::forward(parameters) ...) + {} + #endif + }; + + + + struct group : public node_allocator_type + { + node_pointer_type nodes; + node_pointer_type free_list_head; + node_pointer_type beyond_end; + group_size_type number_of_elements; + + + group() PLF_LIST_NOEXCEPT: + nodes(NULL), + free_list_head(NULL), + beyond_end(NULL), + number_of_elements(0) + {} + + + #if defined(PLF_LIST_VARIADICS_SUPPORT) || defined(PLF_LIST_MOVE_SEMANTICS_SUPPORT) + group(const group_size_type group_size, node_pointer_type const previous = NULL): + nodes(PLF_LIST_ALLOCATE_INITIALIZATION(node_allocator_type, group_size, previous)), + free_list_head(NULL), + beyond_end(nodes + group_size), + number_of_elements(0) + {} + #else + // This is a hack around the fact that allocator_type::construct only supports copy construction in C++03 and copy elision does not occur on the vast majority of compilers in this circumstance. And to avoid running out of memory (and performance loss) from allocating the same block twice, we're allocating in this constructor and moving data in the copy constructor. + group(const group_size_type group_size, node_pointer_type const previous = NULL) PLF_LIST_NOEXCEPT: + nodes(NULL), + free_list_head(previous), + beyond_end(NULL), + number_of_elements(group_size) + {} + + // Not a real copy constructor ie. actually a move constructor. Only used for allocator.construct in C++03 for reasons stated above: + group(const group &source): + node_allocator_type(source), + nodes(PLF_LIST_ALLOCATE_INITIALIZATION(node_allocator_type, source.number_of_elements, source.free_list_head)), + free_list_head(NULL), + beyond_end(nodes + source.number_of_elements), + number_of_elements(0) + {} + #endif + + + group & operator = (const group &source) PLF_LIST_NOEXCEPT // Actually a move operator, used by c++03 in group_vector's remove, expand_capacity and append + { + nodes = source.nodes; + free_list_head = source.free_list_head; + beyond_end = source.beyond_end; + number_of_elements = source.number_of_elements; + return *this; + } + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + group(group &&source) PLF_LIST_NOEXCEPT: + node_allocator_type(source), + nodes(std::move(source.nodes)), + free_list_head(std::move(source.free_list_head)), + beyond_end(std::move(source.beyond_end)), + number_of_elements(source.number_of_elements) + { + source.nodes = NULL; + source.beyond_end = NULL; + } + + + group & operator = (group &&source) PLF_LIST_NOEXCEPT + { + nodes = std::move(source.nodes); + free_list_head = std::move(source.free_list_head); + beyond_end = std::move(source.beyond_end); + number_of_elements = std::move(source.number_of_elements); + source.nodes = NULL; + source.beyond_end = NULL; + return *this; + } + #endif + + + ~group() PLF_LIST_NOEXCEPT + { + PLF_LIST_DEALLOCATE(node_allocator_type, (*this), nodes, static_cast(beyond_end - nodes)); + } + }; + + + + + class group_vector : private node_pointer_allocator_type + { + public: + group_pointer_type last_endpoint_group, block_pointer, last_searched_group; // last_endpoint_group is the last -active- group in the block. Other -inactive- (previously used, now empty of elements) groups may be stored after this group for future usage (to reduce deallocation/reallocation of nodes). block_pointer + size - 1 == the last group in the block, regardless of whether or not the group is active. + size_type size; + + + struct ebco_pair2 : allocator_type // empty-base-class optimisation + { + size_type capacity; // Total element capacity of all initialized groups + explicit ebco_pair2(const size_type number_of_elements) PLF_LIST_NOEXCEPT: capacity(number_of_elements) {}; + } element_allocator_pair; + + struct ebco_pair : group_allocator_type + { + size_type capacity; // Total group capacity + explicit ebco_pair(const size_type number_of_groups) PLF_LIST_NOEXCEPT: capacity(number_of_groups) {}; + } group_allocator_pair; + + + + group_vector() PLF_LIST_NOEXCEPT: + node_pointer_allocator_type(node_pointer_allocator_type()), + last_endpoint_group(NULL), + block_pointer(NULL), + last_searched_group(NULL), + size(0), + element_allocator_pair(0), + group_allocator_pair(0) + {} + + + + inline PLF_LIST_FORCE_INLINE void blank() PLF_LIST_NOEXCEPT + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivial::value) + { + std::memset(static_cast(this), 0, sizeof(group_vector)); + } + else + #endif + { + last_endpoint_group = NULL; + block_pointer = NULL; + last_searched_group = NULL; + size = 0; + element_allocator_pair.capacity = 0; + group_allocator_pair.capacity = 0; + } + } + + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + group_vector(group_vector &&source) PLF_LIST_NOEXCEPT: + last_endpoint_group(std::move(source.last_endpoint_group)), + block_pointer(std::move(source.block_pointer)), + last_searched_group(std::move(source.last_searched_group)), + size(source.size), + element_allocator_pair(source.element_allocator_pair.capacity), + group_allocator_pair(source.group_allocator_pair.capacity) + { + source.blank(); + } + + + group_vector & operator = (group_vector &&source) PLF_LIST_NOEXCEPT + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivial::value) + { + std::memcpy(static_cast(this), &source, sizeof(group_vector)); + } + else + #endif + { + last_endpoint_group = std::move(source.last_endpoint_group); + block_pointer = std::move(source.block_pointer); + last_searched_group = std::move(source.last_searched_group); + size = source.size; + element_allocator_pair.capacity = source.element_allocator_pair.capacity; + group_allocator_pair.capacity = source.group_allocator_pair.capacity; + } + + source.blank(); + return *this; + } + #endif + + + + ~group_vector() PLF_LIST_NOEXCEPT + {} + + + + void destroy_all_data(const node_pointer_type last_endpoint_node) PLF_LIST_NOEXCEPT + { + if (block_pointer == NULL) + { + return; + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) + #endif + { + clear(last_endpoint_node); // If clear has already been called, last_endpoint_node will already be == block_pointer->nodes, so no work will occur + } + + const group_pointer_type end_group = block_pointer + size; + for (group_pointer_type current_group = block_pointer; current_group != end_group; ++current_group) + { + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, current_group); + } + + PLF_LIST_DEALLOCATE(group_allocator_type, group_allocator_pair, block_pointer, group_allocator_pair.capacity); + blank(); + } + + + + void clear(const node_pointer_type last_endpoint_node) PLF_LIST_NOEXCEPT + { + for (group_pointer_type current_group = block_pointer; current_group != last_endpoint_group; ++current_group) + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) + #endif + { + const node_pointer_type end = current_group->beyond_end; + + if ((end - current_group->nodes) != current_group->number_of_elements) // If there are erased nodes present in the group + { + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + if (current_node->next != NULL) // ie. is not part of free list + { + PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); + } + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); + } + } + } + else + { + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); + } + } + } + } + + current_group->free_list_head = NULL; + current_group->number_of_elements = 0; + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) + #endif + { + if ((last_endpoint_node - last_endpoint_group->nodes) != last_endpoint_group->number_of_elements) // If there are erased nodes present in the group + { + for (node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node) + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + if (current_node->next != NULL) // is not part of free list ie. element has not already had it's destructor called + { + PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); + } + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); + } + } + } + else + { + for (node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node) + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); + PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); + } + } + } + } + + last_endpoint_group->free_list_head = NULL; + last_endpoint_group->number_of_elements = 0; + last_searched_group = last_endpoint_group = block_pointer; + } + + + + void expand_capacity(const size_type new_capacity) // used by add_new and append + { + group_pointer_type const old_block = block_pointer; + block_pointer = PLF_LIST_ALLOCATE(group_allocator_type, group_allocator_pair, new_capacity, 0); + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) + { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer + std::memcpy(static_cast(&*block_pointer), static_cast(&*old_block), sizeof(group) * size); // reinterpret_cast necessary to deal with GCC 8 warnings + } + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) + { + std::uninitialized_copy(std::make_move_iterator(old_block), std::make_move_iterator(old_block + size), block_pointer); + } + #endif + else + #endif + { + // If allocator supplies non-trivial pointers it becomes necessary to destroy the group. uninitialized_copy will not work in this context as the copy constructor for "group" is overriden in C++03/98. The = operator for "group" has been overriden to make the following work: + const group_pointer_type beyond_end = old_block + size; + group_pointer_type current_new_group = block_pointer; + + for (group_pointer_type current_group = old_block; current_group != beyond_end; ++current_group) + { + *(current_new_group++) = *(current_group); + + current_group->nodes = NULL; + current_group->beyond_end = NULL; + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, current_group); + } + } + + last_searched_group = block_pointer + (last_searched_group - old_block); // correct pointer post-reallocation + PLF_LIST_DEALLOCATE(group_allocator_type, group_allocator_pair, old_block, group_allocator_pair.capacity); + group_allocator_pair.capacity = new_capacity; + } + + + + void add_new(const group_size_type group_size) + { + if (group_allocator_pair.capacity == size) + { + expand_capacity(group_allocator_pair.capacity * 2); + } + + last_endpoint_group = block_pointer + size - 1; + + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group + 1, group_size, last_endpoint_group->nodes); + #else + PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group + 1, group(group_size, last_endpoint_group->nodes)); + #endif + + ++last_endpoint_group; // Doing this here instead of pre-construct to avoid need for a try-catch block + element_allocator_pair.capacity += group_size; + ++size; + } + + + + void initialize(const group_size_type group_size) // For adding first group *only* when group vector is completely empty and block_pointer is NULL + { + last_endpoint_group = block_pointer = last_searched_group = PLF_LIST_ALLOCATE(group_allocator_type, group_allocator_pair, 1, 0); + group_allocator_pair.capacity = 1; + + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group, group_size); + #else + PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group, group(group_size)); + #endif + + size = 1; // Doing these here instead of pre-construct to avoid need for a try-catch block + element_allocator_pair.capacity = group_size; + } + + + + void remove(group_pointer_type const group_to_erase) PLF_LIST_NOEXCEPT + { + if (last_searched_group >= group_to_erase && last_searched_group != block_pointer) + { + --last_searched_group; + } + + element_allocator_pair.capacity -= static_cast(group_to_erase->beyond_end - group_to_erase->nodes); + + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, group_to_erase); + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) + { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer + std::memmove(static_cast(&*group_to_erase), static_cast(&*group_to_erase + 1), sizeof(group) * (--size - static_cast(&*group_to_erase - &*block_pointer))); + } + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) + { + std::move(group_to_erase + 1, block_pointer + size--, group_to_erase); + } + #endif + else + #endif + { + group_pointer_type back = block_pointer + size--; + std::copy(group_to_erase + 1, back--, group_to_erase); + + back->nodes = NULL; + back->beyond_end = NULL; + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, back); + } + } + + + + void move_to_back(group_pointer_type const group_to_erase) + { + if (last_searched_group >= group_to_erase && last_searched_group != block_pointer) + { + --last_searched_group; + } + + group *temp_group = PLF_LIST_ALLOCATE(group_allocator_type, group_allocator_pair, 1, NULL); + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) + { + std::memcpy(static_cast(&*temp_group), static_cast(&*group_to_erase), sizeof(group)); + std::memmove(static_cast(&*group_to_erase), static_cast(&*group_to_erase + 1), sizeof(group) * ((size - 1) - static_cast(&*group_to_erase - &*block_pointer))); + std::memcpy(static_cast(&*(block_pointer + size - 1)), static_cast(&*temp_group), sizeof(group)); + } + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) + { + PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, temp_group, std::move(*group_to_erase)); + std::move(group_to_erase + 1, block_pointer + size, group_to_erase); + *(block_pointer + size - 1) = std::move(*temp_group); + + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + { + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, temp_group); + } + } + #endif + else + #endif + { + PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, temp_group, group()); + + *temp_group = *group_to_erase; + std::copy(group_to_erase + 1, block_pointer + size, group_to_erase); + *(block_pointer + --size) = *temp_group; + + temp_group->nodes = NULL; + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, temp_group); + } + + PLF_LIST_DEALLOCATE(group_allocator_type, group_allocator_pair, temp_group, 1); + } + + + + group_pointer_type get_nearest_freelist_group(const node_pointer_type location_node) PLF_LIST_NOEXCEPT // In working implementation this cannot throw + { + const group_pointer_type beyond_end_group = last_endpoint_group + 1; + group_pointer_type left = last_searched_group - 1, right = last_searched_group + 1, freelist_group = NULL; + bool right_not_beyond_back = (right < beyond_end_group); + bool left_not_beyond_front = (left >= block_pointer); + + + if (location_node >= last_searched_group->nodes && location_node < last_searched_group->beyond_end) // ie. location is within last_search_group + { + if (last_searched_group->free_list_head != NULL) // if last_searched_group has previously-erased nodes + { + return last_searched_group; + } + } + else // search for the node group which location_node is located within, using last_searched_group as a starting point and searching left and right. Try and find the closest node group with reusable erased-element locations along the way: + { + group_pointer_type closest_freelist_left = (last_searched_group->free_list_head == NULL) ? NULL : last_searched_group, closest_freelist_right = (last_searched_group->free_list_head == NULL) ? NULL : last_searched_group; + + while (true) + { + if (right_not_beyond_back) + { + if ((location_node < right->beyond_end) && (location_node >= right->nodes)) // location_node's group is found + { + if (right->free_list_head != NULL) // group has erased nodes, reuse them: + { + last_searched_group = right; + return right; + } + + difference_type left_distance; + + if (closest_freelist_right != NULL) + { + last_searched_group = right; + left_distance = right - closest_freelist_right; + + if (left_distance <= 2) // ie. this group is close enough to location_node's group + { + return closest_freelist_right; + } + + freelist_group = closest_freelist_right; + } + else + { + last_searched_group = right; + left_distance = right - left; + } + + + // Otherwise find closest group with freelist - check an equal distance on the right to the distance we've checked on the left: + const group_pointer_type end_group = (((right + left_distance) > beyond_end_group) ? beyond_end_group : (right + left_distance - 1)); + + while (++right != end_group) + { + if (right->free_list_head != NULL) + { + return right; + } + } + + if (freelist_group != NULL) + { + return freelist_group; + } + + right_not_beyond_back = (right < beyond_end_group); + break; // group with reusable erased nodes not found yet, continue searching in loop below + } + + if (right->free_list_head != NULL) // location_node's group not found, but a reusable location found + { + if ((closest_freelist_right == NULL) & (closest_freelist_left == NULL)) + { + closest_freelist_left = right; + } + + closest_freelist_right = right; + } + + right_not_beyond_back = (++right < beyond_end_group); + } + + + if (left_not_beyond_front) + { + if ((location_node >= left->nodes) && (location_node < left->beyond_end)) + { + if (left->free_list_head != NULL) + { + last_searched_group = left; + return left; + } + + difference_type right_distance; + + if (closest_freelist_left != NULL) + { + last_searched_group = left; + right_distance = closest_freelist_left - left; + + if (right_distance <= 2) + { + return closest_freelist_left; + } + + freelist_group = closest_freelist_left; + } + else + { + last_searched_group = left; + right_distance = right - left; + } + + // Otherwise find closest group with freelist: + const group_pointer_type end_group = (((left - right_distance) < block_pointer) ? block_pointer - 1 : (left - right_distance) + 1); + + while (--left != end_group) + { + if (left->free_list_head != NULL) + { + return left; + } + } + + if (freelist_group != NULL) + { + return freelist_group; + } + + left_not_beyond_front = (left >= block_pointer); + break; + } + + if (left->free_list_head != NULL) + { + if ((closest_freelist_left == NULL) & (closest_freelist_right == NULL)) + { + closest_freelist_right = left; + } + + closest_freelist_left = left; + } + + left_not_beyond_front = (--left >= block_pointer); + } + } + } + + + // The node group which location_node is located within, is known at this point. Continue searching outwards from this group until a group is found with a reusable location: + while (true) + { + if (right_not_beyond_back) + { + if (right->free_list_head != NULL) + { + return right; + } + + right_not_beyond_back = (++right < beyond_end_group); + } + + if (left_not_beyond_front) + { + if (left->free_list_head != NULL) + { + return left; + } + + left_not_beyond_front = (--left >= block_pointer); + } + } + + // Will never reach here on functioning implementations + } + + + + void swap(group_vector &source) PLF_LIST_NOEXCEPT_SWAP(group_allocator_type) + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivial::value) // if all pointer types are trivial we can just copy using memcpy - faster - avoids constructors/destructors etc + { + char temp[sizeof(group_vector)]; + std::memcpy(static_cast(&temp), static_cast(this), sizeof(group_vector)); + std::memcpy(static_cast(this), static_cast(&source), sizeof(group_vector)); + std::memcpy(static_cast(&source), static_cast(&temp), sizeof(group_vector)); + } + else + #endif + { + const group_pointer_type swap_last_endpoint_group = last_endpoint_group, swap_block_pointer = block_pointer, swap_last_searched_group = last_searched_group; + const size_type swap_size = size, swap_element_capacity = element_allocator_pair.capacity, swap_capacity = group_allocator_pair.capacity; + + last_endpoint_group = source.last_endpoint_group; + block_pointer = source.block_pointer; + last_searched_group = source.last_searched_group; + size = source.size; + element_allocator_pair.capacity = source.element_allocator_pair.capacity; + group_allocator_pair.capacity = source.group_allocator_pair.capacity; + + source.last_endpoint_group = swap_last_endpoint_group; + source.block_pointer = swap_block_pointer; + source.last_searched_group = swap_last_searched_group; + source.size = swap_size; + source.element_allocator_pair.capacity = swap_element_capacity; + source.group_allocator_pair.capacity = swap_capacity; + } + } + + + + void trim_trailing_groups() PLF_LIST_NOEXCEPT + { + const group_pointer_type beyond_last = block_pointer + size; + + for (group_pointer_type current_group = last_endpoint_group + 1; current_group != beyond_last; ++current_group) + { + element_allocator_pair.capacity -= static_cast(current_group->beyond_end - current_group->nodes); + PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, current_group); + } + + size -= static_cast(beyond_last - (last_endpoint_group + 1)); + } + + + + void append(group_vector &source) + { + source.trim_trailing_groups(); + trim_trailing_groups(); + + if (size + source.size > group_allocator_pair.capacity) + { + expand_capacity(size + source.size); + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) + { // &* in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer + std::memcpy(static_cast(&*block_pointer + size), static_cast(&*source.block_pointer), sizeof(group) * source.size); + } + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) + { + std::uninitialized_copy(std::make_move_iterator(source.block_pointer), std::make_move_iterator(source.block_pointer + source.size), block_pointer + size); + } + #endif + else + #endif + { + group_pointer_type current_new_group = block_pointer + size; + const group_pointer_type beyond_end_source = source.block_pointer + source.size; + + for (group_pointer_type current_group = source.block_pointer; current_group != beyond_end_source; ++current_group) + { + *(current_new_group++) = *(current_group); + + current_group->nodes = NULL; + current_group->beyond_end = NULL; + PLF_LIST_DESTROY(group_allocator_type, source.group_allocator_pair, current_group); + } + } + + PLF_LIST_DEALLOCATE(group_allocator_type, source.group_allocator_pair, source.block_pointer, source.group_allocator_pair.capacity); + size += source.size; + last_endpoint_group = block_pointer + size - 1; + element_allocator_pair.capacity += source.element_allocator_pair.capacity; + source.blank(); + } + }; + + + + // Implement const/non-const iterator switching pattern: + template struct choose; + + template struct choose + { + typedef IsTrue type; + }; + + template struct choose + { + typedef IsFalse type; + }; + + +public: + + template class list_iterator + { + private: + node_pointer_type node_pointer; + + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename list::value_type value_type; + typedef typename list::difference_type difference_type; + typedef typename choose::type pointer; + typedef typename choose::type reference; + + friend class list; + + + + inline PLF_LIST_FORCE_INLINE bool operator == (const list_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer == rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE bool operator == (const list_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer == rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer != rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer != rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE reference operator * () const + { + return node_pointer->element; + } + + + + inline PLF_LIST_FORCE_INLINE pointer operator -> () const + { + return &(node_pointer->element); + } + + + + inline PLF_LIST_FORCE_INLINE list_iterator & operator ++ () PLF_LIST_NOEXCEPT + { + assert(node_pointer != NULL); // covers uninitialised list_iterator + node_pointer = node_pointer->next; + return *this; + } + + + + inline list_iterator operator ++(int) PLF_LIST_NOEXCEPT + { + const list_iterator copy(*this); + ++*this; + return copy; + } + + + + inline PLF_LIST_FORCE_INLINE list_iterator & operator -- () PLF_LIST_NOEXCEPT + { + assert(node_pointer != NULL); // covers uninitialised list_iterator + node_pointer = node_pointer->previous; + return *this; + } + + + + inline list_iterator operator -- (int) PLF_LIST_NOEXCEPT + { + const list_iterator copy(*this); + --*this; + return copy; + } + + + + inline list_iterator & operator = (const list_iterator &rh) PLF_LIST_NOEXCEPT + { + node_pointer = rh.node_pointer; + return *this; + } + + + + inline list_iterator & operator = (const list_iterator &rh) PLF_LIST_NOEXCEPT + { + node_pointer = rh.node_pointer; + return *this; + } + + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + inline list_iterator & operator = (const list_iterator &&rh) PLF_LIST_NOEXCEPT + { + node_pointer = std::move(rh.node_pointer); + return *this; + } + + + inline list_iterator & operator = (const list_iterator &&rh) PLF_LIST_NOEXCEPT + { + node_pointer = std::move(rh.node_pointer); + return *this; + } + #endif + + + + list_iterator() PLF_LIST_NOEXCEPT: node_pointer(NULL) {} + + list_iterator(const list_iterator &source) PLF_LIST_NOEXCEPT: node_pointer(source.node_pointer) {} + + list_iterator(const list_iterator &source) PLF_LIST_NOEXCEPT: node_pointer(source.node_pointer) {} + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + list_iterator (const list_iterator &&source) PLF_LIST_NOEXCEPT: node_pointer(std::move(source.node_pointer)) {} + + list_iterator(const list_iterator &&source) PLF_LIST_NOEXCEPT: node_pointer(std::move(source.node_pointer)) {} + #endif + + private: + + list_iterator (const node_pointer_type node_p) PLF_LIST_NOEXCEPT: node_pointer(node_p) {} + }; + + + + + template class list_reverse_iterator + { + private: + node_pointer_type node_pointer; + + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename list::value_type value_type; + typedef typename list::difference_type difference_type; + typedef typename choose::type pointer; + typedef typename choose::type reference; + + friend class list; + + + inline PLF_LIST_FORCE_INLINE bool operator == (const list_reverse_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer == rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE bool operator == (const list_reverse_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer == rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer != rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const PLF_LIST_NOEXCEPT + { + return (node_pointer != rh.node_pointer); + } + + + + inline PLF_LIST_FORCE_INLINE reference operator * () const + { + return node_pointer->element; + } + + + + inline PLF_LIST_FORCE_INLINE pointer operator -> () const + { + return &(node_pointer->element); + } + + + + inline PLF_LIST_FORCE_INLINE list_reverse_iterator & operator ++ () PLF_LIST_NOEXCEPT + { + assert(node_pointer != NULL); // covers uninitialised list_reverse_iterator + node_pointer = node_pointer->previous; + return *this; + } + + + + inline list_reverse_iterator operator ++(int) PLF_LIST_NOEXCEPT + { + const list_reverse_iterator copy(*this); + ++*this; + return copy; + } + + + + inline PLF_LIST_FORCE_INLINE list_reverse_iterator & operator -- () PLF_LIST_NOEXCEPT + { + assert(node_pointer != NULL); + node_pointer = node_pointer->next; + return *this; + } + + + + inline list_reverse_iterator operator -- (int) PLF_LIST_NOEXCEPT + { + const list_reverse_iterator copy(*this); + --*this; + return copy; + } + + + + inline list_reverse_iterator & operator = (const list_reverse_iterator &rh) PLF_LIST_NOEXCEPT + { + node_pointer = rh.node_pointer; + return *this; + } + + + + inline list_reverse_iterator & operator = (const list_reverse_iterator &rh) PLF_LIST_NOEXCEPT + { + node_pointer = rh.node_pointer; + return *this; + } + + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + inline list_reverse_iterator & operator = (const list_reverse_iterator &&rh) PLF_LIST_NOEXCEPT + { + node_pointer = std::move(rh.node_pointer); + return *this; + } + + + inline list_reverse_iterator & operator = (const list_reverse_iterator &&rh) PLF_LIST_NOEXCEPT + { + node_pointer = std::move(rh.node_pointer); + return *this; + } + #endif + + + + inline typename list::iterator base() const PLF_LIST_NOEXCEPT + { + return typename list::iterator(node_pointer->next); + } + + + + list_reverse_iterator() PLF_LIST_NOEXCEPT: node_pointer(NULL) {} + + list_reverse_iterator(const list_reverse_iterator &source) PLF_LIST_NOEXCEPT: node_pointer(source.node_pointer) {} + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + list_reverse_iterator (const list_reverse_iterator &&source) PLF_LIST_NOEXCEPT: node_pointer(std::move(source.node_pointer)) {} + #endif + + private: + + list_reverse_iterator (const node_pointer_type node_p) PLF_LIST_NOEXCEPT: node_pointer(node_p) {} + }; + + + +private: + + // Used by range-insert and range-constructor to prevent fill-insert and fill-constructor function calls mistakenly resolving to the range insert/constructor + template + struct plf_enable_if_c + { + typedef T type; + }; + + template + struct plf_enable_if_c + {}; + + + + group_vector groups; + node_base end_node; + node_pointer_type last_endpoint; // last_endpoint being NULL means no elements have been constructed, but there may still be groups available due to clear() or reservee() + iterator end_iterator, begin_iterator; // end_iterator is always the last entry point in last group in list (or one past the end of group) + + struct ebco_pair1 : node_pointer_allocator_type // Packaging the group allocator with least-used member variables, for empty-base-class optimisation + { + size_type total_number_of_elements; + explicit ebco_pair1(const size_type total_num_elements) PLF_LIST_NOEXCEPT: total_number_of_elements(total_num_elements) {} + } node_pointer_allocator_pair; + + struct ebco_pair2 : node_allocator_type + { + size_type number_of_erased_nodes; + explicit ebco_pair2(const size_type num_erased_nodes) PLF_LIST_NOEXCEPT: number_of_erased_nodes(num_erased_nodes) {} + } node_allocator_pair; + + + +public: + + // Default constructor: + + list() PLF_LIST_NOEXCEPT: + element_allocator_type(element_allocator_type()), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + {} + + + + // Allocator-extended constructor: + + explicit list(const element_allocator_type &alloc): + element_allocator_type(alloc), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + {} + + + + // Copy constructor: + + list(const list &source): + element_allocator_type(source), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + { + reserve(source.node_pointer_allocator_pair.total_number_of_elements); + insert(end_iterator, source.begin_iterator, source.end_iterator); + } + + + + // Allocator-extended copy constructor: + + list(const list &source, const allocator_type &alloc): + element_allocator_type(alloc), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + { + reserve(source.node_pointer_allocator_pair.total_number_of_elements); + insert(end_iterator, source.begin_iterator, source.end_iterator); + } + + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + // Move constructor: + + list(list &&source) PLF_LIST_NOEXCEPT: + element_allocator_type(source), + groups(std::move(source.groups)), + end_node(std::move(source.end_node)), + last_endpoint(std::move(source.last_endpoint)), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator((source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? reinterpret_cast(&end_node) : std::move(source.begin_iterator)), + node_pointer_allocator_pair(source.node_pointer_allocator_pair.total_number_of_elements), + node_allocator_pair(source.node_allocator_pair.number_of_erased_nodes) + { + end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; + source.groups.blank(); + source.reset(); + } + + + + // Allocator-extended move constructor: + + list(list &&source, const allocator_type &alloc): + element_allocator_type(alloc), + groups(std::move(source.groups)), + end_node(std::move(source.end_node)), + last_endpoint(std::move(source.last_endpoint)), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator((source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? reinterpret_cast(&end_node) : std::move(source.begin_iterator)), + node_pointer_allocator_pair(source.node_pointer_allocator_pair.total_number_of_elements), + node_allocator_pair(source.node_allocator_pair.number_of_erased_nodes) + { + end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; + source.groups.blank(); + source.reset(); + } + #endif + + + + // Fill constructor: + + list(const size_type fill_number, const element_type &element, const element_allocator_type &alloc = element_allocator_type()): + element_allocator_type(alloc), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + { + reserve(fill_number); + insert(end_iterator, fill_number, element); + } + + + + // Range constructor: + + template + list(const typename plf_enable_if_c::is_integer, iterator_type>::type &first, const iterator_type &last, const element_allocator_type &alloc = element_allocator_type()): + element_allocator_type(alloc), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + { + insert(end_iterator, first, last); + } + + + + // Initializer-list constructor: + + #ifdef PLF_LIST_INITIALIZER_LIST_SUPPORT + list(const std::initializer_list &element_list, const element_allocator_type &alloc = element_allocator_type()): + element_allocator_type(alloc), + end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), + last_endpoint(NULL), + end_iterator(reinterpret_cast(&end_node)), + begin_iterator(reinterpret_cast(&end_node)), + node_pointer_allocator_pair(0), + node_allocator_pair(0) + { + reserve(element_list.size()); + insert(end_iterator, element_list); + } + + #endif + + + + ~list() PLF_LIST_NOEXCEPT + { + groups.destroy_all_data(last_endpoint); + } + + + + inline iterator begin() PLF_LIST_NOEXCEPT + { + return begin_iterator; + } + + + + inline const_iterator begin() const PLF_LIST_NOEXCEPT + { + return begin_iterator; + } + + + + inline iterator end() PLF_LIST_NOEXCEPT + { + return end_iterator; + } + + + + inline const_iterator end() const PLF_LIST_NOEXCEPT + { + return end_iterator; + } + + + + inline const_iterator cbegin() const PLF_LIST_NOEXCEPT + { + return const_iterator(begin_iterator.node_pointer); + } + + + + inline const_iterator cend() const PLF_LIST_NOEXCEPT + { + return const_iterator(end_iterator.node_pointer); + } + + + + inline reverse_iterator rbegin() const PLF_LIST_NOEXCEPT + { + return reverse_iterator(end_node.previous); + } + + + + inline reverse_iterator rend() const PLF_LIST_NOEXCEPT + { + return reverse_iterator(end_iterator.node_pointer); + } + + + + inline const_reverse_iterator crbegin() const PLF_LIST_NOEXCEPT + { + return const_reverse_iterator(end_node.previous); + } + + + + inline const_reverse_iterator crend() const PLF_LIST_NOEXCEPT + { + return const_reverse_iterator(end_iterator.node_pointer); + } + + + + inline reference front() + { + assert(begin_iterator.node_pointer != &end_node); + return begin_iterator.node_pointer->element; + } + + + + inline const_reference front() const + { + assert(begin_iterator.node_pointer != &end_node); + return begin_iterator.node_pointer->element; + } + + + + inline reference back() + { + assert(end_node.previous != &end_node); + return end_node.previous->element; + } + + + + inline const_reference back() const + { + assert(end_node.previous != &end_node); + return end_node.previous->element; + } + + + + void clear() PLF_LIST_NOEXCEPT + { + if (last_endpoint == NULL) + { + return; + } + + if (node_pointer_allocator_pair.total_number_of_elements != 0) + { + groups.clear(last_endpoint); + } + + end_node.next = reinterpret_cast(&end_node); + end_node.previous = reinterpret_cast(&end_node); + last_endpoint = groups.block_pointer->nodes; + begin_iterator.node_pointer = end_iterator.node_pointer; + node_pointer_allocator_pair.total_number_of_elements = 0; + node_allocator_pair.number_of_erased_nodes = 0; + } + + + +private: + + + void reset() PLF_LIST_NOEXCEPT + { + groups.destroy_all_data(last_endpoint); + last_endpoint = NULL; + end_node.next = reinterpret_cast(&end_node); + end_node.previous = reinterpret_cast(&end_node); + begin_iterator.node_pointer = end_iterator.node_pointer; + node_pointer_allocator_pair.total_number_of_elements = 0; + node_allocator_pair.number_of_erased_nodes = 0; + } + + + + +public: + + + iterator insert(const iterator it, const element_type &element) + { + if (last_endpoint != NULL) // ie. list is not empty + { + if (node_allocator_pair.number_of_erased_nodes == 0) // No erased nodes available for reuse + { + if (last_endpoint == groups.last_endpoint_group->beyond_end) // last_endpoint is beyond the end of a group + { + if (static_cast(groups.last_endpoint_group - groups.block_pointer) == groups.size - 1) // ie. there are no reusable groups available at the back of group vector + { + groups.add_new((node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX) ? static_cast(node_pointer_allocator_pair.total_number_of_elements) : PLF_LIST_BLOCK_MAX); + } + else + { + ++groups.last_endpoint_group; + } + + last_endpoint = groups.last_endpoint_group->nodes; + } + + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, element); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(it.node_pointer, it.node_pointer->previous, element)); + #endif + + ++(groups.last_endpoint_group->number_of_elements); + ++node_pointer_allocator_pair.total_number_of_elements; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = last_endpoint; + } + + it.node_pointer->previous->next = last_endpoint; + it.node_pointer->previous = last_endpoint; + + return iterator(last_endpoint++); + } + else + { + group_pointer_type const node_group = groups.get_nearest_freelist_group((it.node_pointer != end_iterator.node_pointer) ? it.node_pointer : end_node.previous); + node_pointer_type const selected_node = node_group->free_list_head; + const node_pointer_type previous = node_group->free_list_head->previous; + + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, element); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, node(it.node_pointer, it.node_pointer->previous, element)); + #endif + + node_group->free_list_head = previous; + ++(node_group->number_of_elements); + ++node_pointer_allocator_pair.total_number_of_elements; + --node_allocator_pair.number_of_erased_nodes; + + it.node_pointer->previous->next = selected_node; + it.node_pointer->previous = selected_node; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = selected_node; + } + + return iterator(selected_node); + } + } + else // list is empty + { + if (groups.block_pointer == NULL) // In case of prior reserve/clear call as opposed to being uninitialized + { + groups.initialize(PLF_LIST_BLOCK_MIN); + } + + groups.last_endpoint_group->number_of_elements = 1; + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + node_pointer_allocator_pair.total_number_of_elements = 1; + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_nothrow_copy_constructible::value) // Avoid try-catch code generation + { + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, element)); + #endif + } + else + #endif + { + try + { + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, element)); + #endif + } + catch (...) + { + reset(); + throw; + } + } + + return begin_iterator; + } + } + + + + inline PLF_LIST_FORCE_INLINE void push_back(const element_type &element) + { + insert(end_iterator, element); + } + + + + inline PLF_LIST_FORCE_INLINE void push_front(const element_type &element) + { + insert(begin_iterator, element); + } + + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + iterator insert(const iterator it, element_type &&element) // This is almost identical to the insert implementation above with the only change being std::move of the element + { + if (last_endpoint != NULL) + { + if (node_allocator_pair.number_of_erased_nodes == 0) + { + if (last_endpoint == groups.last_endpoint_group->beyond_end) + { + if (static_cast(groups.last_endpoint_group - groups.block_pointer) == groups.size - 1) + { + groups.add_new((node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX) ? static_cast(node_pointer_allocator_pair.total_number_of_elements) : PLF_LIST_BLOCK_MAX); + } + else + { + ++groups.last_endpoint_group; + } + + last_endpoint = groups.last_endpoint_group->nodes; + } + + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::move(element)); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(it.node_pointer, it.node_pointer->previous, std::move(element))); + #endif + + ++(groups.last_endpoint_group->number_of_elements); + ++node_pointer_allocator_pair.total_number_of_elements; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = last_endpoint; + } + + it.node_pointer->previous->next = last_endpoint; + it.node_pointer->previous = last_endpoint; + + return iterator(last_endpoint++); + } + else + { + group_pointer_type const node_group = groups.get_nearest_freelist_group((it.node_pointer != end_iterator.node_pointer) ? it.node_pointer : end_node.previous); + node_pointer_type const selected_node = node_group->free_list_head; + const node_pointer_type previous = node_group->free_list_head->previous; + + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::move(element)); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, node(it.node_pointer, it.node_pointer->previous, std::move(element))); + #endif + + node_group->free_list_head = previous; + ++(node_group->number_of_elements); + ++node_pointer_allocator_pair.total_number_of_elements; + --node_allocator_pair.number_of_erased_nodes; + + it.node_pointer->previous->next = selected_node; + it.node_pointer->previous = selected_node; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = selected_node; + } + + return iterator(selected_node); + } + } + else + { + if (groups.block_pointer == NULL) + { + groups.initialize(PLF_LIST_BLOCK_MIN); + } + + groups.last_endpoint_group->number_of_elements = 1; + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + node_pointer_allocator_pair.total_number_of_elements = 1; + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_nothrow_move_constructible::value) + { + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move(element)); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, std::move(element))); + #endif + } + else + #endif + { + try + { + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move(element)); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, std::move(element))); + #endif + } + catch (...) + { + reset(); + throw; + } + } + + return begin_iterator; + } + } + + + + inline PLF_LIST_FORCE_INLINE void push_back(element_type &&element) + { + insert(end_iterator, std::move(element)); + } + + + + inline PLF_LIST_FORCE_INLINE void push_front(element_type &&element) + { + insert(begin_iterator, std::move(element)); + } + #endif + + + + + #ifdef PLF_LIST_VARIADICS_SUPPORT + template + iterator emplace(const iterator it, arguments &&... parameters) // This is almost identical to the insert implementations above with the only changes being std::forward of element parameters and removal of VARIADICS support checking + { + if (last_endpoint != NULL) + { + if (node_allocator_pair.number_of_erased_nodes == 0) + { + if (last_endpoint == groups.last_endpoint_group->beyond_end) + { + if (static_cast(groups.last_endpoint_group - groups.block_pointer) == groups.size - 1) + { + groups.add_new((node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX) ? static_cast(node_pointer_allocator_pair.total_number_of_elements) : PLF_LIST_BLOCK_MAX); + } + else + { + ++groups.last_endpoint_group; + } + + last_endpoint = groups.last_endpoint_group->nodes; + } + + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::forward(parameters)...); + + ++(groups.last_endpoint_group->number_of_elements); + ++node_pointer_allocator_pair.total_number_of_elements; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = last_endpoint; + } + + it.node_pointer->previous->next = last_endpoint; + it.node_pointer->previous = last_endpoint; + + return iterator(last_endpoint++); + } + else + { + group_pointer_type const node_group = groups.get_nearest_freelist_group((it.node_pointer != end_iterator.node_pointer) ? it.node_pointer : end_node.previous); + node_pointer_type const selected_node = node_group->free_list_head; + const node_pointer_type previous = node_group->free_list_head->previous; + + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::forward(parameters)...); + + node_group->free_list_head = previous; + ++(node_group->number_of_elements); + ++node_pointer_allocator_pair.total_number_of_elements; + --node_allocator_pair.number_of_erased_nodes; + + it.node_pointer->previous->next = selected_node; + it.node_pointer->previous = selected_node; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = selected_node; + } + + return iterator(selected_node); + } + } + else + { + if (groups.block_pointer == NULL) + { + groups.initialize(PLF_LIST_BLOCK_MIN); + } + + groups.last_endpoint_group->number_of_elements = 1; + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + node_pointer_allocator_pair.total_number_of_elements = 1; + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_nothrow_constructible::value) + { + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward(parameters)...); + } + else + #endif + { + try + { + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward(parameters)...); + } + catch (...) + { + reset(); + throw; + } + } + + return begin_iterator; + } + } + + + + template + inline PLF_LIST_FORCE_INLINE reference emplace_back(arguments &&... parameters) + { + return (emplace(end_iterator, std::forward(parameters)...)).node_pointer->element; + } + + + + template + inline PLF_LIST_FORCE_INLINE reference emplace_front(arguments &&... parameters) + { + return (emplace(begin_iterator, std::forward(parameters)...)).node_pointer->element; + } + + + #endif + + + +private: + + void group_fill_position(const element_type &element, group_size_type number_of_elements, node_pointer_type const position) + { + position->previous->next = last_endpoint; + groups.last_endpoint_group->number_of_elements += number_of_elements; + node_pointer_type previous = position->previous; + + do + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_nothrow_copy_constructible::value) + { + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(last_endpoint + 1, previous, element)); + #endif + } + else + #endif + { + try + { + #ifdef PLF_LIST_VARIADICS_SUPPORT + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element); + #else + PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(last_endpoint + 1, previous, element)); + #endif + } + catch (...) + { + previous->next = position; + position->previous = --previous; + groups.last_endpoint_group->number_of_elements -= static_cast(number_of_elements - (last_endpoint - position)); + throw; + } + } + + previous = last_endpoint++; + } while (--number_of_elements != 0); + + previous->next = position; + position->previous = previous; + } + + + +public: + + // Fill insert + + iterator insert(iterator position, const size_type number_of_elements, const element_type &element) + { + if (number_of_elements == 0) + { + return end_iterator; + } + else if (number_of_elements == 1) + { + return insert(position, element); + } + + + if (node_pointer_allocator_pair.total_number_of_elements == 0 && last_endpoint != NULL && (static_cast(groups.block_pointer->beyond_end - groups.block_pointer->nodes) < number_of_elements) && (static_cast(groups.block_pointer->beyond_end - groups.block_pointer->nodes) < PLF_LIST_BLOCK_MAX)) + { + reset(); + } + + + if (groups.block_pointer == NULL) // ie. Uninitialized list + { + if (number_of_elements > PLF_LIST_BLOCK_MAX) + { + size_type multiples = number_of_elements / PLF_LIST_BLOCK_MAX; + const group_size_type remainder = static_cast(number_of_elements - (multiples++ * PLF_LIST_BLOCK_MAX)); // ++ to aid while loop below + + // Create and fill first group: + if (remainder != 0) // make sure smallest block is first + { + if (remainder >= PLF_LIST_BLOCK_MIN) + { + groups.initialize(remainder); + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + group_fill_position(element, remainder, end_iterator.node_pointer); + } + else + { // Create first group as BLOCK_MIN size then subtract difference between BLOCK_MIN and remainder from next group: + groups.initialize(PLF_LIST_BLOCK_MIN); + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + group_fill_position(element, PLF_LIST_BLOCK_MIN, end_iterator.node_pointer); + + groups.add_new(PLF_LIST_BLOCK_MAX - (PLF_LIST_BLOCK_MIN - remainder)); + end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position(element, PLF_LIST_BLOCK_MAX - (PLF_LIST_BLOCK_MIN - remainder), end_iterator.node_pointer); + --multiples; + } + } + else + { + groups.initialize(PLF_LIST_BLOCK_MAX); + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + group_fill_position(element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer); + --multiples; + } + + while (--multiples != 0) + { + groups.add_new(PLF_LIST_BLOCK_MAX); + end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position(element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer); + } + + } + else + { + groups.initialize((number_of_elements < PLF_LIST_BLOCK_MIN) ? PLF_LIST_BLOCK_MIN : static_cast(number_of_elements)); // Construct first group + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + group_fill_position(element, static_cast(number_of_elements), end_iterator.node_pointer); + } + + node_pointer_allocator_pair.total_number_of_elements = number_of_elements; + return begin_iterator; + } + else + { + // Insert first element, then use up any erased nodes: + size_type remainder = number_of_elements - 1; + const iterator return_iterator = insert(position, element); + + while (node_allocator_pair.number_of_erased_nodes != 0) + { + insert(position, element); + --node_allocator_pair.number_of_erased_nodes; + + if (--remainder == 0) + { + return return_iterator; + } + } + + node_pointer_allocator_pair.total_number_of_elements += remainder; + + // then use up remainder of last_endpoint_group: + const group_size_type remaining_nodes_in_group = static_cast(groups.last_endpoint_group->beyond_end - last_endpoint); + + if (remaining_nodes_in_group != 0) + { + if (remaining_nodes_in_group < remainder) + { + group_fill_position(element, remaining_nodes_in_group, position.node_pointer); + remainder -= remaining_nodes_in_group; + } + else + { + group_fill_position(element, static_cast(remainder), position.node_pointer); + return return_iterator; + } + } + + + // use up trailing groups: + while ((groups.last_endpoint_group != (groups.block_pointer + groups.size - 1)) & (remainder != 0)) + { + last_endpoint = (++groups.last_endpoint_group)->nodes; + const group_size_type group_size = static_cast(groups.last_endpoint_group->beyond_end - groups.last_endpoint_group->nodes); + + if (group_size < remainder) + { + group_fill_position(element, group_size, position.node_pointer); + remainder -= group_size; + } + else + { + group_fill_position(element, static_cast(remainder), position.node_pointer); + return return_iterator; + } + } + + size_type multiples = remainder / static_cast(PLF_LIST_BLOCK_MAX); + remainder -= multiples * PLF_LIST_BLOCK_MAX; + + while (multiples-- != 0) + { + groups.add_new(PLF_LIST_BLOCK_MAX); + last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position(element, PLF_LIST_BLOCK_MAX, position.node_pointer); + } + + if (remainder != 0) // Bit annoying to create a large block to house a lower number of elements, but beats the alternatives + { + groups.add_new(PLF_LIST_BLOCK_MAX); + last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position(element, static_cast(remainder), position.node_pointer); + } + + return return_iterator; + } + } + + + + // Range insert + + template + iterator insert(const iterator it, typename plf_enable_if_c::is_integer, iterator_type>::type first, const iterator_type last) + { + if (first == last) + { + return end_iterator; + } + + const iterator return_iterator = insert(it, *first); + + while(++first != last) + { + insert(it, *first); + } + + return return_iterator; + } + + + + // Initializer-list insert + + #ifdef PLF_LIST_INITIALIZER_LIST_SUPPORT + inline iterator insert(const iterator it, const std::initializer_list &element_list) + { // use range insert: + return insert(it, element_list.begin(), element_list.end()); + } + #endif + + + +private: + + inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers(group_pointer_type const group_to_process, const node_pointer_type beyond_end_node) PLF_LIST_NOEXCEPT + { + for (node_pointer_type current_node = group_to_process->nodes; current_node != beyond_end_node; ++current_node) + { + PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, &(current_node->next)); // Destruct element + PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, &(current_node->previous)); // Destruct element + } + } + + + +public: + + + // Single erase: + + iterator erase(const const_iterator it) // if uninitialized/invalid iterator supplied, function could generate an exception, hence no noexcept + { + assert(node_pointer_allocator_pair.total_number_of_elements != 0); + assert(it.node_pointer != NULL); + assert(it.node_pointer != end_iterator.node_pointer); + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) + #endif + { + PLF_LIST_DESTROY(element_allocator_type, (*this), &(it.node_pointer->element)); // Destruct element + } + + --node_pointer_allocator_pair.total_number_of_elements; + ++node_allocator_pair.number_of_erased_nodes; + + + group_pointer_type node_group = groups.last_searched_group; + + // find nearest group with reusable (erased element) memory location: + if ((it.node_pointer < node_group->nodes) || (it.node_pointer >= node_group->beyond_end)) + { + // Search left and right: + const group_pointer_type beyond_end_group = groups.last_endpoint_group + 1; + group_pointer_type left = node_group - 1; + bool right_not_beyond_back = (++node_group < beyond_end_group); + bool left_not_beyond_front = (left >= groups.block_pointer); + + while (true) + { + if (right_not_beyond_back) + { + if ((it.node_pointer < node_group->beyond_end) && (it.node_pointer >= node_group->nodes)) // usable location found + { + break; + } + + right_not_beyond_back = (++node_group < beyond_end_group); + } + + if (left_not_beyond_front) + { + if ((it.node_pointer >= left->nodes) && (it.node_pointer < left->beyond_end)) // usable location found + { + node_group = left; + break; + } + + left_not_beyond_front = (--left >= groups.block_pointer); + } + } + + groups.last_searched_group = node_group; + } + + it.node_pointer->next->previous = it.node_pointer->previous; + it.node_pointer->previous->next = it.node_pointer->next; + + if (it.node_pointer == begin_iterator.node_pointer) + { + begin_iterator.node_pointer = it.node_pointer->next; + } + + + const iterator return_iterator(it.node_pointer->next); + + if (--(node_group->number_of_elements) != 0) // ie. group is not empty yet, add node to free list + { + it.node_pointer->next = NULL; // next == NULL so that destructor can detect the free list item as opposed to non-free-list item + it.node_pointer->previous = node_group->free_list_head; + node_group->free_list_head = it.node_pointer; + return return_iterator; + } + else if (node_group != groups.last_endpoint_group--) // remove group (and decrement active back group) + { + const group_size_type group_size = static_cast(node_group->beyond_end - node_group->nodes); + node_allocator_pair.number_of_erased_nodes -= group_size; + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) + #endif + { + destroy_all_node_pointers(node_group, node_group->beyond_end); + } + + node_group->free_list_head = NULL; + + if ((group_size == PLF_LIST_BLOCK_MAX) | (node_group >= groups.last_endpoint_group - 1)) // Preserve only last (active) group or second/third-to-last group - seems to be best for performance under high-modification benchmarks + { + groups.move_to_back(node_group); + } + else + { + groups.remove(node_group); + } + + return return_iterator; + } + else // clear back group, leave trailing + { + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) + #endif + { + destroy_all_node_pointers(node_group, last_endpoint); + } + + node_group->free_list_head = NULL; + + if (node_pointer_allocator_pair.total_number_of_elements != 0) + { + node_allocator_pair.number_of_erased_nodes -= static_cast(last_endpoint - node_group->nodes); + last_endpoint = groups.last_endpoint_group->beyond_end; + } + else + { + groups.last_endpoint_group = groups.block_pointer; // If number of elements is zero, it indicates that this was the first group in the vector. In which case the last_endpoint_group would be invalid at this point due to the decrement in the above else-if statement. So it needs to be reset, as it will not be reset in the function call below. + clear(); + } + + + return return_iterator; + } + } + + + + // Range-erase: + + inline void erase(const const_iterator iterator1, const const_iterator iterator2) // if uninitialized/invalid iterator supplied, function could generate an exception + { + for (const_iterator current = iterator1; current != iterator2;) + { + current = erase(current); + } + } + + + + inline void pop_back() // Exception will occur on empty list + { + erase(iterator(end_node.previous)); + } + + + + inline void pop_front() // Exception will occur on empty list + { + erase(begin_iterator); + } + + + + inline list & operator = (const list &source) + { + assert (&source != this); + + clear(); + reserve(source.node_pointer_allocator_pair.total_number_of_elements); + insert(end_iterator, source.begin_iterator, source.end_iterator); + + return *this; + } + + + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + // Move assignment + list & operator = (list &&source) PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(allocator_type) + { + assert (&source != this); + + // Move source values across: + groups.destroy_all_data(last_endpoint); + + groups = std::move(source.groups); + end_node = std::move(source.end_node); + last_endpoint = std::move(source.last_endpoint); + begin_iterator.node_pointer = (source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? end_iterator.node_pointer : std::move(source.begin_iterator.node_pointer); + node_pointer_allocator_pair.total_number_of_elements = source.node_pointer_allocator_pair.total_number_of_elements; + node_allocator_pair.number_of_erased_nodes = source.node_allocator_pair.number_of_erased_nodes; + + end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; + + source.groups.blank(); + source.reset(); + return *this; + } + #endif + + + + bool operator == (const list &rh) const PLF_LIST_NOEXCEPT + { + assert (this != &rh); + + if (node_pointer_allocator_pair.total_number_of_elements != rh.node_pointer_allocator_pair.total_number_of_elements) + { + return false; + } + + iterator rh_iterator = rh.begin_iterator; + + for (iterator lh_iterator = begin_iterator; lh_iterator != end_iterator;) + { + if (*rh_iterator++ != *lh_iterator++) + { + return false; + } + } + + return true; + } + + + + inline bool operator != (const list &rh) const PLF_LIST_NOEXCEPT + { + return !(*this == rh); + } + + + + inline bool empty() const PLF_LIST_NOEXCEPT + { + return node_pointer_allocator_pair.total_number_of_elements == 0; + } + + + + inline size_type size() const PLF_LIST_NOEXCEPT + { + return node_pointer_allocator_pair.total_number_of_elements; + } + + + + inline size_type max_size() const PLF_LIST_NOEXCEPT + { + #ifdef PLF_LIST_ALLOCATOR_TRAITS_SUPPORT + return std::allocator_traits::max_size(*this); + #else + return element_allocator_type::max_size(); + #endif + } + + + + inline size_type capacity() const PLF_LIST_NOEXCEPT + { + return groups.element_allocator_pair.capacity; + } + + + + inline size_type approximate_memory_use() const PLF_LIST_NOEXCEPT + { + return static_cast(sizeof(*this) + (groups.element_allocator_pair.capacity * sizeof(node)) + (sizeof(group) * groups.group_allocator_pair.capacity)); + } + + + +private: + + + struct less + { + inline bool operator() (const element_type &a, const element_type &b) const PLF_LIST_NOEXCEPT + { + return a < b; + } + }; + + + + // Function-object to redirect the sort function to sort pointers by the elements they point to, not the pointer value + template + struct sort_dereferencer + { + comparison_function stored_instance; + + explicit sort_dereferencer(const comparison_function &function_instance): + stored_instance(function_instance) + {} + + sort_dereferencer() PLF_LIST_NOEXCEPT + {} + + inline bool operator() (const node_pointer_type first, const node_pointer_type second) + { + return stored_instance(first->element, second->element); + } + }; + + + +public: + + + template + void sort(comparison_function compare) + { + if (node_pointer_allocator_pair.total_number_of_elements < 2) + { + return; + } + + node_pointer_type * const node_pointers = PLF_LIST_ALLOCATE(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer_allocator_pair.total_number_of_elements, NULL); + node_pointer_type *node_pointer = node_pointers; + + + // According to the C++ standard, construction of a pointer (of any type) may not trigger an exception - hence, no try-catch blocks are necessary for constructing the pointers: + for (group_pointer_type current_group = groups.block_pointer; current_group != groups.last_endpoint_group; ++current_group) + { + const node_pointer_type end = current_group->beyond_end; + + if ((end - current_group->nodes) != current_group->number_of_elements) // If there are erased nodes present in the group + { + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + if (current_node->next != NULL) // is not free list node + { + PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); + } + } + } + else + { + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); + } + } + } + + if ((last_endpoint - groups.last_endpoint_group->nodes) != groups.last_endpoint_group->number_of_elements) // If there are erased nodes present in the group + { + for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) + { + if (current_node->next != NULL) + { + PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); + } + } + } + else + { + for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) + { + PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); + } + } + + + #ifdef GFX_TIMSORT_HPP + gfx::timsort(node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, sort_dereferencer(compare)); + #else + std::sort(node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, sort_dereferencer(compare)); + #endif + + begin_iterator.node_pointer = node_pointers[0]; + begin_iterator.node_pointer->next = node_pointers[1]; + begin_iterator.node_pointer->previous = end_iterator.node_pointer; + + end_node.next = node_pointers[0]; + end_node.previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 1]; + end_node.previous->next = end_iterator.node_pointer; + end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 2]; + + node_pointer_type * const back = node_pointers + node_pointer_allocator_pair.total_number_of_elements - 1; + + for(node_pointer = node_pointers + 1; node_pointer != back; ++node_pointer) + { + (*node_pointer)->next = *(node_pointer + 1); + (*node_pointer)->previous = *(node_pointer - 1); + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer - 1); + } + } + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) + #endif + { + PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, back); + } + + PLF_LIST_DEALLOCATE(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointers, node_pointer_allocator_pair.total_number_of_elements); + } + + + + inline void sort() + { + sort(less()); + } + + + + void reorder(const iterator position, const iterator first, const iterator last) PLF_LIST_NOEXCEPT + { + last.node_pointer->next->previous = first.node_pointer->previous; + first.node_pointer->previous->next = last.node_pointer->next; + + last.node_pointer->next = position.node_pointer; + first.node_pointer->previous = position.node_pointer->previous; + + position.node_pointer->previous->next = first.node_pointer; + position.node_pointer->previous = last.node_pointer; + + if (begin_iterator == position) + { + begin_iterator = first; + } + } + + + + inline void reorder(const iterator position, const iterator location) PLF_LIST_NOEXCEPT + { + reorder(position, location, location); + } + + + + void reserve(size_type reserve_amount) + { + if (reserve_amount == 0 || reserve_amount <= groups.element_allocator_pair.capacity) + { + return; + } + else if (reserve_amount < PLF_LIST_BLOCK_MIN) + { + reserve_amount = PLF_LIST_BLOCK_MIN; + } + else if (reserve_amount > max_size()) + { + reserve_amount = max_size(); + } + + + if (groups.block_pointer != NULL && node_pointer_allocator_pair.total_number_of_elements == 0) + { // edge case: has been filled with elements then clear()'d - some groups may be smaller than would be desired, should be replaced + group_size_type end_group_size = static_cast((groups.block_pointer + groups.size - 1)->beyond_end - (groups.block_pointer + groups.size - 1)->nodes); + + if (reserve_amount > end_group_size && end_group_size != PLF_LIST_BLOCK_MAX) // if last group isn't large enough, remove all groups + { + reset(); + } + else + { + size_type number_of_full_groups_needed = reserve_amount / PLF_LIST_BLOCK_MAX; + group_size_type remainder = static_cast(reserve_amount - (number_of_full_groups_needed * PLF_LIST_BLOCK_MAX)); + + // Remove any max_size groups which're not needed and any groups that're smaller than remainder: + for (group_pointer_type current_group = groups.block_pointer; current_group < groups.block_pointer + groups.size;) + { + const group_size_type current_group_size = static_cast(groups.block_pointer->beyond_end - groups.block_pointer->nodes); + + if (number_of_full_groups_needed != 0 && current_group_size == PLF_LIST_BLOCK_MAX) + { + --number_of_full_groups_needed; + ++current_group; + } + else if (remainder != 0 && current_group_size >= remainder) + { + remainder = 0; + ++current_group; + } + else + { + groups.remove(current_group); + } + } + + last_endpoint = groups.block_pointer->nodes; + } + } + + reserve_amount -= groups.element_allocator_pair.capacity; + + // To correct from possible reallocation caused by add_new: + const difference_type last_endpoint_group_number = groups.last_endpoint_group - groups.block_pointer; + + size_type number_of_full_groups = (reserve_amount / PLF_LIST_BLOCK_MAX); + reserve_amount -= (number_of_full_groups++ * PLF_LIST_BLOCK_MAX); // ++ to aid while loop below + + if (groups.block_pointer == NULL) // Previously uninitialized list or reset in above if statement; most common scenario + { + if (reserve_amount != 0) + { + groups.initialize(static_cast(((reserve_amount < PLF_LIST_BLOCK_MIN) ? PLF_LIST_BLOCK_MIN : reserve_amount))); + } + else + { + groups.initialize(PLF_LIST_BLOCK_MAX); + --number_of_full_groups; + } + } + else if (reserve_amount != 0) + { // Create a group at least as large as the last group - may allocate more than necessary, but better solution than creating a veyr small group in the middle of the group vector, I think: + const group_size_type last_endpoint_group_capacity = static_cast(groups.last_endpoint_group->beyond_end - groups.last_endpoint_group->nodes); + groups.add_new(static_cast((reserve_amount < last_endpoint_group_capacity) ? last_endpoint_group_capacity : reserve_amount)); + } + + while (--number_of_full_groups != 0) + { + groups.add_new(PLF_LIST_BLOCK_MAX); + } + + groups.last_endpoint_group = groups.block_pointer + last_endpoint_group_number; + } + + + + inline PLF_LIST_FORCE_INLINE void free_unused_memory() PLF_LIST_NOEXCEPT + { + groups.trim_trailing_groups(); + } + + + + void shrink_to_fit() + { + if ((last_endpoint == NULL) | (node_pointer_allocator_pair.total_number_of_elements == groups.element_allocator_pair.capacity)) // uninitialized list or full + { + return; + } + else if (node_pointer_allocator_pair.total_number_of_elements == 0) // Edge case + { + reset(); + return; + } + else if (node_allocator_pair.number_of_erased_nodes == 0 && last_endpoint == groups.last_endpoint_group->beyond_end) //edge case - currently no waste except for possible trailing groups + { + groups.trim_trailing_groups(); + return; + } + + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + list temp; + temp.reserve(node_pointer_allocator_pair.total_number_of_elements); + + #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT + if PLF_LIST_CONSTEXPR (std::is_move_assignable::value && std::is_move_constructible::value) // move elements if possible, otherwise copy them + { + temp.insert(temp.end_iterator, std::make_move_iterator(begin_iterator), std::make_move_iterator(end_iterator)); + } + else + #endif + { + temp.insert(temp.end_iterator, begin_iterator, end_iterator); + } + + *this = std::move(temp); + #else + list temp(*this); + reset(); + swap(temp); + #endif + } + + + +private: + + void append_process(list &source) // used by merge and splice + { + if (last_endpoint != groups.last_endpoint_group->beyond_end) + { // Add unused nodes to group's free list + const node_pointer_type back_node = last_endpoint - 1; + for (node_pointer_type current_node = groups.last_endpoint_group->beyond_end - 1; current_node != back_node; --current_node) + { + current_node->next = NULL; + current_node->previous = groups.last_endpoint_group->free_list_head; + groups.last_endpoint_group->free_list_head = current_node; + } + + node_allocator_pair.number_of_erased_nodes += static_cast(groups.last_endpoint_group->beyond_end - last_endpoint); + } + + groups.append(source.groups); + last_endpoint = source.last_endpoint; + node_pointer_allocator_pair.total_number_of_elements += source.node_pointer_allocator_pair.total_number_of_elements; + source.reset(); + } + + + + +public: + + void splice(iterator position, list &source) + { + assert(&source != this); + + if (source.node_pointer_allocator_pair.total_number_of_elements == 0) + { + return; + } + else if (node_pointer_allocator_pair.total_number_of_elements == 0) + { + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + *this = std::move(source); + #else + reset(); + swap(source); + #endif + + return; + } + + if (position.node_pointer == begin_iterator.node_pointer) // put source groups at front rather than back + { + swap(source); + position.node_pointer = end_iterator.node_pointer; + } + + position.node_pointer->previous->next = source.begin_iterator.node_pointer; + source.begin_iterator.node_pointer->previous = position.node_pointer->previous; + position.node_pointer->previous = source.end_node.previous; + source.end_node.previous->next = position.node_pointer; + + append_process(source); + } + + + + template + void merge(list &source, comparison_function compare) + { + assert(&source != this); + splice((source.node_pointer_allocator_pair.total_number_of_elements >= node_pointer_allocator_pair.total_number_of_elements) ? end_iterator : begin_iterator, source); + sort(compare); + } + + + + void merge(list &source) + { + assert(&source != this); + + if (source.node_pointer_allocator_pair.total_number_of_elements == 0) + { + return; + } + else if (node_pointer_allocator_pair.total_number_of_elements == 0) + { + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + *this = std::move(source); + #else + reset(); + swap(source); + #endif + + return; + } + + node_pointer_type current1 = begin_iterator.node_pointer->next, current2 = source.begin_iterator.node_pointer->next; + node_pointer_type previous = source.begin_iterator.node_pointer; + const node_pointer_type source_end = source.end_iterator.node_pointer, this_end = end_iterator.node_pointer; + + begin_iterator.node_pointer->next = source.begin_iterator.node_pointer; + source.begin_iterator.node_pointer->previous = begin_iterator.node_pointer; + + + while ((current1 != this_end) & (current2 != source_end)) + { + previous->next = current1; + current1->previous = previous; + previous = current1; + current1 = current1->next; + + previous->next = current2; + current2->previous = previous; + previous = current2; + current2 = current2->next; + } + + if (current1 != this_end) + { + previous->next = current1; + current1->previous = previous; + } + else + { + end_node.previous = source.end_node.previous; + source.end_node.previous->next = end_iterator.node_pointer; + } + + append_process(source); + } + + + + void reverse() PLF_LIST_NOEXCEPT + { + if (node_pointer_allocator_pair.total_number_of_elements > 1) + { + for (group_pointer_type current_group = groups.block_pointer; current_group != groups.last_endpoint_group; ++current_group) + { + const node_pointer_type end = current_group->beyond_end; + + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + if (current_node->next != NULL) // is not free list node + { // swap the pointers: + const node_pointer_type temp = current_node->next; + current_node->next = current_node->previous; + current_node->previous = temp; + } + } + } + + for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) + { + if (current_node->next != NULL) + { + const node_pointer_type temp = current_node->next; + current_node->next = current_node->previous; + current_node->previous = temp; + } + } + + const node_pointer_type temp = end_node.previous; + end_node.previous = begin_iterator.node_pointer; + begin_iterator.node_pointer = temp; + + end_node.previous->next = end_iterator.node_pointer; + begin_iterator.node_pointer->previous = end_iterator.node_pointer; + } + } + + + +private: + + // Used by unique() + struct eq + { + inline bool operator() (const element_type &a, const element_type &b) const PLF_LIST_NOEXCEPT + { + return a == b; + } + }; + + + + // Used by remove() + struct eq_to + { + const element_type value; + + explicit eq_to(const element_type store_value): + value(store_value) + {} + + eq_to() PLF_LIST_NOEXCEPT + {} + + inline bool operator() (const element_type compare_value) const PLF_LIST_NOEXCEPT + { + return value == compare_value; + } + }; + + + +public: + + template + size_type unique(comparison_function compare) + { + const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; + + if (original_number_of_elements > 1) + { + element_type *previous = &(begin_iterator.node_pointer->element); + + for (iterator current = ++iterator(begin_iterator); current != end_iterator;) + { + if (compare(*current, *previous)) + { + current = erase(current); + } + else + { + previous = &(current++.node_pointer->element); + } + } + } + + return original_number_of_elements - node_pointer_allocator_pair.total_number_of_elements; + } + + + + inline size_type unique() + { + return unique(eq()); + } + + + + template + size_type remove_if(predicate_function predicate) + { + const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; + + if (original_number_of_elements != 0) + { + for (group_pointer_type current_group = groups.block_pointer; current_group != groups.last_endpoint_group; ++current_group) + { + group_size_type num_elements = current_group->number_of_elements; + const node_pointer_type end = current_group->beyond_end; + + if (end - current_group->nodes != num_elements) // If there are erased nodes present in the group + { + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + if (current_node->next != NULL && predicate(current_node->element)) // is not free list node and validates predicate + { + erase(current_node); + + if (--num_elements == 0) // ie. group will be empty (and removed) now - nothing left to iterate over + { + --current_group; // As current group has been removed, subsequent groups have already shifted back by one, hence, the ++ to the current group in the for loop is unnecessary, and negated here + break; + } + } + } + } + else // No erased nodes in group + { + for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) + { + if (predicate(current_node->element)) + { + erase(current_node); + + if (--num_elements == 0) + { + --current_group; + break; + } + } + } + } + } + + group_size_type num_elements = groups.last_endpoint_group->number_of_elements; + + if (last_endpoint - groups.last_endpoint_group->nodes != num_elements) // If there are erased nodes present in the group + { + for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) + { + if (current_node->next != NULL && predicate(current_node->element)) + { + erase(current_node); + + if (--num_elements == 0) + { + break; + } + } + } + } + else + { + for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) + { + if (predicate(current_node->element)) + { + erase(current_node); + + if (--num_elements == 0) + { + break; + } + } + } + } + } + + return original_number_of_elements - node_pointer_allocator_pair.total_number_of_elements; + } + + + + inline size_type remove(const element_type &value) + { + return remove_if(eq_to(value)); + } + + + + void resize(const size_type number_of_elements, const element_type &value = element_type()) + { + if (node_pointer_allocator_pair.total_number_of_elements == number_of_elements) + { + return; + } + else if (number_of_elements == 0) + { + clear(); + return; + } + else if (node_pointer_allocator_pair.total_number_of_elements < number_of_elements) + { + insert(end_iterator, number_of_elements - node_pointer_allocator_pair.total_number_of_elements, value); + } + else // ie. node_pointer_allocator_pair.total_number_of_elements > number_of_elements + { + iterator current(end_node.previous); + + for (size_type number_to_remove = node_pointer_allocator_pair.total_number_of_elements - number_of_elements; number_to_remove != 0; --number_to_remove) + { + const node_pointer_type temp = current.node_pointer->previous; + erase(current); + current.node_pointer = temp; + } + } + } + + + + // Range assign: + template + inline void assign(const typename plf_enable_if_c::is_integer, iterator_type>::type first, const iterator_type last) + { + clear(); + insert(end_iterator, first, last); + groups.trim_trailing_groups(); + } + + + + // Fill assign: + inline void assign(const size_type number_of_elements, const element_type &value) + { + clear(); + reserve(number_of_elements); // Will return anyway if capacity already > number_of_elements + insert(end_iterator, number_of_elements, value); + } + + + + #ifdef PLF_LIST_INITIALIZER_LIST_SUPPORT + // Initializer-list assign: + inline void assign(const std::initializer_list &element_list) + { + clear(); + reserve(element_list.size()); + insert(end_iterator, element_list); + } + #endif + + + + inline allocator_type get_allocator() const PLF_LIST_NOEXCEPT + { + return element_allocator_type(); + } + + + + void swap(list &source) PLF_LIST_NOEXCEPT_SWAP(allocator_type) + { + #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT + list temp(std::move(source)); + source = std::move(*this); + *this = std::move(temp); + #else + groups.swap(source.groups); + + const node_pointer_type swap_end_node_previous = end_node.previous, swap_last_endpoint = last_endpoint; + const iterator swap_begin_iterator = begin_iterator; + const size_type swap_total_number_of_elements = node_pointer_allocator_pair.total_number_of_elements, swap_number_of_erased_nodes = node_allocator_pair.number_of_erased_nodes; + + last_endpoint = source.last_endpoint; + end_node.next = begin_iterator.node_pointer = (source.begin_iterator.node_pointer != source.end_iterator.node_pointer) ? source.begin_iterator.node_pointer : end_iterator.node_pointer; + end_node.previous = (source.begin_iterator.node_pointer != source.end_iterator.node_pointer) ? source.end_node.previous : end_iterator.node_pointer; + end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; + node_pointer_allocator_pair.total_number_of_elements = source.node_pointer_allocator_pair.total_number_of_elements; + node_allocator_pair.number_of_erased_nodes = source.node_allocator_pair.number_of_erased_nodes; + + source.last_endpoint = swap_last_endpoint; + source.end_node.next = source.begin_iterator.node_pointer = (swap_begin_iterator.node_pointer != end_iterator.node_pointer) ? swap_begin_iterator.node_pointer : source.end_iterator.node_pointer; + source.end_node.previous = (swap_begin_iterator.node_pointer != end_iterator.node_pointer) ? swap_end_node_previous : source.end_iterator.node_pointer; + source.end_node.previous->next = source.begin_iterator.node_pointer->previous = source.end_iterator.node_pointer; + source.node_pointer_allocator_pair.total_number_of_elements = swap_total_number_of_elements; + source.node_allocator_pair.number_of_erased_nodes = swap_number_of_erased_nodes; + #endif + } + +}; + + + +template +inline void swap(list &a, list &b) PLF_LIST_NOEXCEPT_SWAP(swap_element_allocator_type) +{ + a.swap(b); +} + + + +} // plf namespace + +#undef PLF_LIST_BLOCK_MAX +#undef PLF_LIST_BLOCK_MIN + +#undef PLF_LIST_FORCE_INLINE + +#undef PLF_LIST_INITIALIZER_LIST_SUPPORT +#undef PLF_LIST_TYPE_TRAITS_SUPPORT +#undef PLF_LIST_ALLOCATOR_TRAITS_SUPPORT +#undef PLF_LIST_VARIADICS_SUPPORT +#undef PLF_LIST_MOVE_SEMANTICS_SUPPORT +#undef PLF_LIST_NOEXCEPT +#undef PLF_LIST_NOEXCEPT_SWAP +#undef PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT +#undef PLF_LIST_CONSTEXPR + +#undef PLF_LIST_CONSTRUCT +#undef PLF_LIST_DESTROY +#undef PLF_LIST_ALLOCATE +#undef PLF_LIST_ALLOCATE_INITIALIZATION +#undef PLF_LIST_DEALLOCATE + + +#endif // PLF_LIST_H From 4b344c3d829ad180b62410cab738b353d148639f Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Jul 2019 18:04:03 +0200 Subject: [PATCH 02/10] Remove uneeded preprocessor defines --- src/list.h | 630 ++++++++++------------------------------------------- 1 file changed, 114 insertions(+), 516 deletions(-) diff --git a/src/list.h b/src/list.h index cfbfa1495eb8b..d6f3ea8443383 100644 --- a/src/list.h +++ b/src/list.h @@ -25,213 +25,38 @@ #define PLF_LIST_BLOCK_MIN static_cast((sizeof(node) * 8 > (sizeof(*this) + sizeof(group)) * 2) ? 8 : (((sizeof(*this) + sizeof(group)) * 2) / sizeof(node)) + 1) #define PLF_LIST_BLOCK_MAX 2048 +#define PLF_LIST_CONSTEXPR +#define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept +#define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept +// TODO: Switch to these when we move to C++17 +// #define PLF_LIST_CONSTEXPR constexpr +// #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) +// #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) -// Compiler-specific defines used by list: - +// Note: GCC creates faster code without forcing inline #if defined(_MSC_VER) - #define PLF_LIST_FORCE_INLINE __forceinline - - #if _MSC_VER < 1600 - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() - #elif _MSC_VER == 1600 - #define PLF_LIST_MOVE_SEMANTICS_SUPPORT - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() - #elif _MSC_VER == 1700 - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_MOVE_SEMANTICS_SUPPORT - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() - #elif _MSC_VER == 1800 - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_VARIADICS_SUPPORT // Variadics, in this context, means both variadic templates and variadic macros are supported - #define PLF_LIST_MOVE_SEMANTICS_SUPPORT - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) throw() - #define PLF_LIST_INITIALIZER_LIST_SUPPORT - #elif _MSC_VER >= 1900 - #define PLF_LIST_ALIGNMENT_SUPPORT - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_VARIADICS_SUPPORT - #define PLF_LIST_MOVE_SEMANTICS_SUPPORT - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) - #define PLF_LIST_INITIALIZER_LIST_SUPPORT - #endif - - #if defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L) - #define PLF_LIST_CONSTEXPR constexpr - #else - #define PLF_LIST_CONSTEXPR - #endif - -#elif defined(__cplusplus) && __cplusplus >= 201103L // C++11 support, at least - #define PLF_LIST_FORCE_INLINE // note: GCC creates faster code without forcing inline - - #if defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__clang__) // If compiler is GCC/G++ - #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 // 4.2 and below do not support variadic templates - #define PLF_LIST_VARIADICS_SUPPORT - #endif - #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 // 4.3 and below do not support initializer lists - #define PLF_LIST_INITIALIZER_LIST_SUPPORT - #endif - #if (__GNUC__ == 4 && __GNUC_MINOR__ < 6) || __GNUC__ < 4 - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #elif __GNUC__ < 6 - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept - #else // C++17 support - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) - #endif - #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4 - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #endif - #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4 - #define PLF_LIST_ALIGNMENT_SUPPORT - #endif - #if __GNUC__ >= 5 // GCC v4.9 and below do not support std::is_trivially_copyable - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #endif - #elif defined(__GLIBCXX__) // Using another compiler type with libstdc++ - we are assuming full c++11 compliance for compiler - which may not be true - #if __GLIBCXX__ >= 20080606 // libstdc++ 4.2 and below do not support variadic templates - #define PLF_LIST_VARIADICS_SUPPORT - #endif - #if __GLIBCXX__ >= 20090421 // libstdc++ 4.3 and below do not support initializer lists - #define PLF_LIST_INITIALIZER_LIST_SUPPORT - #endif - #if __GLIBCXX__ >= 20160111 - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) - #elif __GLIBCXX__ >= 20120322 - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept - #else - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #endif - #if __GLIBCXX__ >= 20130322 - #define PLF_LIST_ALIGNMENT_SUPPORT - #endif - #if __GLIBCXX__ >= 20150422 // libstdc++ v4.9 and below do not support std::is_trivially_copyable - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #endif - #elif defined(_LIBCPP_VERSION) - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_VARIADICS_SUPPORT - #define PLF_LIST_INITIALIZER_LIST_SUPPORT - #define PLF_LIST_ALIGNMENT_SUPPORT - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept - - #if !(defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)) - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #endif - #else // Assume type traits and initializer support for other compilers and standard libraries - #define PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #define PLF_LIST_ALIGNMENT_SUPPORT - #define PLF_LIST_VARIADICS_SUPPORT - #define PLF_LIST_INITIALIZER_LIST_SUPPORT - #define PLF_LIST_TYPE_TRAITS_SUPPORT - #define PLF_LIST_NOEXCEPT noexcept - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept - #endif - - #if __cplusplus >= 201703L - #if defined(__clang__) && ((__clang_major__ == 3 && __clang_minor__ == 9) || __clang_major__ > 3) - #define PLF_LIST_CONSTEXPR constexpr - #elif defined(__GNUC__) && __GNUC__ >= 7 - #define PLF_LIST_CONSTEXPR constexpr - #elif !defined(__clang__) && !defined(__GNUC__) - #define PLF_LIST_CONSTEXPR constexpr // assume correct C++17 implementation for other compilers - #else - #define PLF_LIST_CONSTEXPR - #endif - #else - #define PLF_LIST_CONSTEXPR - #endif - - #define PLF_LIST_MOVE_SEMANTICS_SUPPORT -#else - #define PLF_LIST_FORCE_INLINE - #define PLF_LIST_NOEXCEPT throw() - #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) - #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) - #define PLF_LIST_CONSTEXPR -#endif - - - -#ifdef PLF_LIST_ALLOCATOR_TRAITS_SUPPORT - #ifdef PLF_LIST_VARIADICS_SUPPORT - #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) std::allocator_traits::construct(allocator_instance, location, __VA_ARGS__) - #else - #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, data) std::allocator_traits::construct(allocator_instance, location, data) - #endif - - #define PLF_LIST_DESTROY(the_allocator, allocator_instance, location) std::allocator_traits::destroy(allocator_instance, location) - #define PLF_LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) std::allocator_traits::allocate(allocator_instance, size, hint) - #define PLF_LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) std::allocator_traits::allocate(*this, size, hint) - #define PLF_LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) std::allocator_traits::deallocate(allocator_instance, location, size) +#define PLF_LIST_FORCE_INLINE __forceinline #else - #ifdef PLF_LIST_VARIADICS_SUPPORT - #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) allocator_instance.construct(location, __VA_ARGS__) - #else - #define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, data) allocator_instance.construct(location, data) - #endif - - #define PLF_LIST_DESTROY(the_allocator, allocator_instance, location) allocator_instance.destroy(location) - #define PLF_LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) allocator_instance.allocate(size, hint) - #define PLF_LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) the_allocator::allocate(size, hint) - #define PLF_LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) allocator_instance.deallocate(location, size) +#define PLF_LIST_FORCE_INLINE #endif +// TODO: get rid of these defines +#define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) std::allocator_traits::construct(allocator_instance, location, __VA_ARGS__) +#define PLF_LIST_DESTROY(the_allocator, allocator_instance, location) std::allocator_traits::destroy(allocator_instance, location) +#define PLF_LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) std::allocator_traits::allocate(allocator_instance, size, hint) +#define PLF_LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) std::allocator_traits::allocate(*this, size, hint) +#define PLF_LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) std::allocator_traits::deallocate(allocator_instance, location, size) - - -#include // memmove, memcpy +#include // std::sort #include // assert +#include // memmove, memcpy +#include +#include // std::bidirectional_iterator_tag #include // std::numeric_limits #include // std::uninitialized_copy, std::allocator -#include // std::bidirectional_iterator_tag - - -#ifndef GFX_TIMSORT_HPP - #include // std::sort -#endif - -#ifdef PLF_LIST_TYPE_TRAITS_SUPPORT - #include // std::is_trivially_destructible, etc -#endif - -#ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT - #include // std::move -#endif - -#ifdef PLF_LIST_INITIALIZER_LIST_SUPPORT - #include -#endif +#include // std::is_trivially_destructible, etc +#include // std::move @@ -249,21 +74,12 @@ template ::size_type size_type; typedef typename std::allocator_traits::difference_type difference_type; typedef element_type & reference; typedef const element_type & const_reference; typedef typename std::allocator_traits::pointer pointer; typedef typename std::allocator_traits::const_pointer const_pointer; - #else - typedef typename element_allocator_type::size_type size_type; - typedef typename element_allocator_type::difference_type difference_type; - typedef typename element_allocator_type::reference reference; - typedef typename element_allocator_type::const_reference const_reference; - typedef typename element_allocator_type::pointer pointer; - typedef typename element_allocator_type::const_pointer const_pointer; - #endif // Iterator declarations: @@ -284,19 +100,11 @@ template ::template rebind_alloc group_allocator_type; typedef typename std::allocator_traits::template rebind_alloc node_allocator_type; typedef typename std::allocator_traits::pointer group_pointer_type; typedef typename std::allocator_traits::pointer node_pointer_type; typedef typename std::allocator_traits::template rebind_alloc node_pointer_allocator_type; - #else - typedef typename element_allocator_type::template rebind::other group_allocator_type; - typedef typename element_allocator_type::template rebind::other node_allocator_type; - typedef typename group_allocator_type::pointer group_pointer_type; - typedef typename node_allocator_type::pointer node_pointer_type; - typedef typename element_allocator_type::template rebind::other node_pointer_allocator_type; - #endif @@ -313,12 +121,10 @@ template node(node_pointer_type const next, node_pointer_type const previous, arguments&&... parameters): node_base(next, previous), element(std::forward(parameters) ...) {} - #endif }; @@ -360,7 +162,7 @@ template (beyond_end - nodes)); } @@ -450,18 +231,18 @@ template ::value) { std::memset(static_cast(this), 0, sizeof(group_vector)); } else - #endif { last_endpoint_group = NULL; block_pointer = NULL; @@ -494,8 +273,7 @@ template ::value) { std::memcpy(static_cast(this), &source, sizeof(group_vector)); } else - #endif { last_endpoint_group = std::move(source.last_endpoint_group); block_pointer = std::move(source.block_pointer); @@ -528,25 +304,22 @@ template ::value || !std::is_trivially_destructible::value) - #endif { clear(last_endpoint_node); // If clear has already been called, last_endpoint_node will already be == block_pointer->nodes, so no work will occur } @@ -563,13 +336,11 @@ template ::value || !std::is_trivially_destructible::value) - #endif { const node_pointer_type end = current_group->beyond_end; @@ -577,9 +348,7 @@ template nodes; current_node != end; ++current_node) { - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { if (current_node->next != NULL) // ie. is not part of free list { @@ -587,9 +356,7 @@ template ::value) - #endif { PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); @@ -600,16 +367,12 @@ template nodes; current_node != end; ++current_node) { - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); } - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); @@ -622,17 +385,13 @@ template number_of_elements = 0; } - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) - #endif { if ((last_endpoint_node - last_endpoint_group->nodes) != last_endpoint_group->number_of_elements) // If there are erased nodes present in the group { for (node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node) { - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { if (current_node->next != NULL) // is not part of free list ie. element has not already had it's destructor called { @@ -640,9 +399,7 @@ template ::value) - #endif { PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); @@ -653,16 +410,12 @@ template nodes; current_node != last_endpoint_node; ++current_node) { - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); } - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); @@ -683,19 +436,15 @@ template ::value && std::is_trivially_destructible::value) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memcpy(static_cast(&*block_pointer), static_cast(&*old_block), sizeof(group) * size); // reinterpret_cast necessary to deal with GCC 8 warnings } - #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) { std::uninitialized_copy(std::make_move_iterator(old_block), std::make_move_iterator(old_block + size), block_pointer); } - #endif else - #endif { // If allocator supplies non-trivial pointers it becomes necessary to destroy the group. uninitialized_copy will not work in this context as the copy constructor for "group" is overriden in C++03/98. The = operator for "group" has been overriden to make the following work: const group_pointer_type beyond_end = old_block + size; @@ -727,11 +476,7 @@ template nodes); - #else - PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group + 1, group(group_size, last_endpoint_group->nodes)); - #endif ++last_endpoint_group; // Doing this here instead of pre-construct to avoid need for a try-catch block element_allocator_pair.capacity += group_size; @@ -745,11 +490,7 @@ template = group_to_erase && last_searched_group != block_pointer) { @@ -768,19 +509,15 @@ template ::value && std::is_trivially_destructible::value) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memmove(static_cast(&*group_to_erase), static_cast(&*group_to_erase + 1), sizeof(group) * (--size - static_cast(&*group_to_erase - &*block_pointer))); } - #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) { std::move(group_to_erase + 1, block_pointer + size--, group_to_erase); } - #endif else - #endif { group_pointer_type back = block_pointer + size--; std::copy(group_to_erase + 1, back--, group_to_erase); @@ -802,14 +539,12 @@ template ::value && std::is_trivially_destructible::value) { std::memcpy(static_cast(&*temp_group), static_cast(&*group_to_erase), sizeof(group)); std::memmove(static_cast(&*group_to_erase), static_cast(&*group_to_erase + 1), sizeof(group) * ((size - 1) - static_cast(&*group_to_erase - &*block_pointer))); std::memcpy(static_cast(&*(block_pointer + size - 1)), static_cast(&*temp_group), sizeof(group)); } - #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) { PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, temp_group, std::move(*group_to_erase)); @@ -821,9 +556,7 @@ template ::value) // if all pointer types are trivial we can just copy using memcpy - faster - avoids constructors/destructors etc { char temp[sizeof(group_vector)]; @@ -1032,7 +764,6 @@ template (&source), static_cast(&temp), sizeof(group_vector)); } else - #endif { const group_pointer_type swap_last_endpoint_group = last_endpoint_group, swap_block_pointer = block_pointer, swap_last_searched_group = last_searched_group; const size_type swap_size = size, swap_element_capacity = element_allocator_pair.capacity, swap_capacity = group_allocator_pair.capacity; @@ -1055,7 +786,7 @@ template ::value && std::is_trivially_destructible::value) { // &* in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memcpy(static_cast(&*block_pointer + size), static_cast(&*source.block_pointer), sizeof(group) * source.size); } - #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) { std::uninitialized_copy(std::make_move_iterator(source.block_pointer), std::make_move_iterator(source.block_pointer + source.size), block_pointer + size); } - #endif else - #endif { group_pointer_type current_new_group = block_pointer + size; const group_pointer_type beyond_end_source = source.block_pointer + source.size; @@ -1149,28 +876,28 @@ template rh) const PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE bool operator == (const list_iterator rh) const noexcept { return (node_pointer == rh.node_pointer); } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const noexcept { return (node_pointer != rh.node_pointer); } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const noexcept { return (node_pointer != rh.node_pointer); } @@ -1191,7 +918,7 @@ template next; @@ -1200,7 +927,7 @@ template previous; @@ -1218,7 +945,7 @@ template &rh) PLF_LIST_NOEXCEPT + inline list_iterator & operator = (const list_iterator &rh) noexcept { node_pointer = rh.node_pointer; return *this; @@ -1243,38 +970,34 @@ template &&rh) PLF_LIST_NOEXCEPT + inline list_iterator & operator = (const list_iterator &&rh) noexcept { node_pointer = std::move(rh.node_pointer); return *this; } - #endif - list_iterator() PLF_LIST_NOEXCEPT: node_pointer(NULL) {} + list_iterator() noexcept: node_pointer(NULL) {} - list_iterator(const list_iterator &source) PLF_LIST_NOEXCEPT: node_pointer(source.node_pointer) {} + list_iterator(const list_iterator &source) noexcept: node_pointer(source.node_pointer) {} - list_iterator(const list_iterator &source) PLF_LIST_NOEXCEPT: node_pointer(source.node_pointer) {} + list_iterator(const list_iterator &source) noexcept: node_pointer(source.node_pointer) {} - #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT - list_iterator (const list_iterator &&source) PLF_LIST_NOEXCEPT: node_pointer(std::move(source.node_pointer)) {} + list_iterator (const list_iterator &&source) noexcept: node_pointer(std::move(source.node_pointer)) {} - list_iterator(const list_iterator &&source) PLF_LIST_NOEXCEPT: node_pointer(std::move(source.node_pointer)) {} - #endif + list_iterator(const list_iterator &&source) noexcept: node_pointer(std::move(source.node_pointer)) {} private: - list_iterator (const node_pointer_type node_p) PLF_LIST_NOEXCEPT: node_pointer(node_p) {} + list_iterator (const node_pointer_type node_p) noexcept: node_pointer(node_p) {} }; @@ -1295,28 +1018,28 @@ template rh) const PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE bool operator == (const list_reverse_iterator rh) const noexcept { return (node_pointer == rh.node_pointer); } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const noexcept { return (node_pointer != rh.node_pointer); } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const noexcept { return (node_pointer != rh.node_pointer); } @@ -1337,7 +1060,7 @@ template previous; @@ -1346,7 +1069,7 @@ template next; @@ -1364,7 +1087,7 @@ template &rh) PLF_LIST_NOEXCEPT + inline list_reverse_iterator & operator = (const list_reverse_iterator &rh) noexcept { node_pointer = rh.node_pointer; return *this; @@ -1389,41 +1112,37 @@ template &&rh) PLF_LIST_NOEXCEPT + inline list_reverse_iterator & operator = (const list_reverse_iterator &&rh) noexcept { node_pointer = std::move(rh.node_pointer); return *this; } - #endif - inline typename list::iterator base() const PLF_LIST_NOEXCEPT + inline typename list::iterator base() const noexcept { return typename list::iterator(node_pointer->next); } - list_reverse_iterator() PLF_LIST_NOEXCEPT: node_pointer(NULL) {} + list_reverse_iterator() noexcept: node_pointer(NULL) {} - list_reverse_iterator(const list_reverse_iterator &source) PLF_LIST_NOEXCEPT: node_pointer(source.node_pointer) {} + list_reverse_iterator(const list_reverse_iterator &source) noexcept: node_pointer(source.node_pointer) {} - #ifdef PLF_LIST_MOVE_SEMANTICS_SUPPORT - list_reverse_iterator (const list_reverse_iterator &&source) PLF_LIST_NOEXCEPT: node_pointer(std::move(source.node_pointer)) {} - #endif + list_reverse_iterator (const list_reverse_iterator &&source) noexcept: node_pointer(std::move(source.node_pointer)) {} private: - list_reverse_iterator (const node_pointer_type node_p) PLF_LIST_NOEXCEPT: node_pointer(node_p) {} + list_reverse_iterator (const node_pointer_type node_p) noexcept: node_pointer(node_p) {} }; @@ -1451,13 +1170,13 @@ template (&end_node), reinterpret_cast(&end_node)), last_endpoint(NULL), @@ -1526,10 +1245,9 @@ template &element_list, const element_allocator_type &alloc = element_allocator_type()): element_allocator_type(alloc), end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), @@ -1616,81 +1332,80 @@ template nodes; } - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, element); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(it.node_pointer, it.node_pointer->previous, element)); - #endif ++(groups.last_endpoint_group->number_of_elements); ++node_pointer_allocator_pair.total_number_of_elements; @@ -1816,11 +1527,7 @@ template free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, element); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, node(it.node_pointer, it.node_pointer->previous, element)); - #endif node_group->free_list_head = previous; ++(node_group->number_of_elements); @@ -1849,25 +1556,15 @@ template nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (std::is_nothrow_copy_constructible::value) // Avoid try-catch code generation { - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, element)); - #endif } else - #endif { try { - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, element)); - #endif } catch (...) { @@ -1896,7 +1593,6 @@ template nodes; } - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::move(element)); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(it.node_pointer, it.node_pointer->previous, std::move(element))); - #endif ++(groups.last_endpoint_group->number_of_elements); ++node_pointer_allocator_pair.total_number_of_elements; @@ -1942,11 +1634,7 @@ template free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::move(element)); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, node(it.node_pointer, it.node_pointer->previous, std::move(element))); - #endif node_group->free_list_head = previous; ++(node_group->number_of_elements); @@ -1975,25 +1663,16 @@ template nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (std::is_nothrow_move_constructible::value) { - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move(element)); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, std::move(element))); - #endif + } else - #endif { try { - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move(element)); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, node(end_iterator.node_pointer, end_iterator.node_pointer, std::move(element))); - #endif } catch (...) { @@ -2024,7 +1703,6 @@ template iterator emplace(const iterator it, arguments &&... parameters) // This is almost identical to the insert implementations above with the only changes being std::forward of element parameters and removal of VARIADICS support checking { @@ -2096,13 +1774,11 @@ template nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (std::is_nothrow_constructible::value) { PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward(parameters)...); } else - #endif { try { @@ -2150,25 +1826,15 @@ template ::value) { - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(last_endpoint + 1, previous, element)); - #endif } else - #endif { try { - #ifdef PLF_LIST_VARIADICS_SUPPORT PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element); - #else - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, node(last_endpoint + 1, previous, element)); - #endif } catch (...) { @@ -2366,18 +2032,15 @@ template &element_list) { // use range insert: return insert(it, element_list.begin(), element_list.end()); } - #endif - private: - inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers(group_pointer_type const group_to_process, const node_pointer_type beyond_end_node) PLF_LIST_NOEXCEPT + inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers(group_pointer_type const group_to_process, const node_pointer_type beyond_end_node) noexcept { for (node_pointer_type current_node = group_to_process->nodes; current_node != beyond_end_node; ++current_node) { @@ -2399,9 +2062,7 @@ template ::value)) - #endif { PLF_LIST_DESTROY(element_allocator_type, (*this), &(it.node_pointer->element)); // Destruct element } @@ -2471,9 +2132,7 @@ template (node_group->beyond_end - node_group->nodes); node_allocator_pair.number_of_erased_nodes -= group_size; - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) - #endif { destroy_all_node_pointers(node_group, node_group->beyond_end); } @@ -2493,9 +2152,7 @@ template ::value)) - #endif { destroy_all_node_pointers(node_group, last_endpoint); } @@ -2559,7 +2216,6 @@ template ::max_size(*this); - #else - return element_allocator_type::max_size(); - #endif } - inline size_type capacity() const PLF_LIST_NOEXCEPT + inline size_type capacity() const noexcept { return groups.element_allocator_pair.capacity; } - inline size_type approximate_memory_use() const PLF_LIST_NOEXCEPT + inline size_type approximate_memory_use() const noexcept { return static_cast(sizeof(*this) + (groups.element_allocator_pair.capacity * sizeof(node)) + (sizeof(group) * groups.group_allocator_pair.capacity)); } @@ -2660,7 +2311,7 @@ template next = *(node_pointer + 1); (*node_pointer)->previous = *(node_pointer - 1); - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer - 1); } } - #ifdef PLF_LIST_TYPE_TRAITS_SUPPORT if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - #endif { PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, back); } @@ -2796,7 +2443,7 @@ template next->previous = first.node_pointer->previous; first.node_pointer->previous->next = last.node_pointer->next; @@ -2815,7 +2462,7 @@ template ::value && std::is_move_constructible::value) // move elements if possible, otherwise copy them { temp.insert(temp.end_iterator, std::make_move_iterator(begin_iterator), std::make_move_iterator(end_iterator)); } else - #endif { temp.insert(temp.end_iterator, begin_iterator, end_iterator); } *this = std::move(temp); - #else - list temp(*this); - reset(); - swap(temp); - #endif + } @@ -2999,13 +2639,7 @@ template 1) { @@ -3137,7 +2765,7 @@ template &element_list) { @@ -3352,11 +2979,10 @@ template next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; - node_pointer_allocator_pair.total_number_of_elements = source.node_pointer_allocator_pair.total_number_of_elements; - node_allocator_pair.number_of_erased_nodes = source.node_allocator_pair.number_of_erased_nodes; - - source.last_endpoint = swap_last_endpoint; - source.end_node.next = source.begin_iterator.node_pointer = (swap_begin_iterator.node_pointer != end_iterator.node_pointer) ? swap_begin_iterator.node_pointer : source.end_iterator.node_pointer; - source.end_node.previous = (swap_begin_iterator.node_pointer != end_iterator.node_pointer) ? swap_end_node_previous : source.end_iterator.node_pointer; - source.end_node.previous->next = source.begin_iterator.node_pointer->previous = source.end_iterator.node_pointer; - source.node_pointer_allocator_pair.total_number_of_elements = swap_total_number_of_elements; - source.node_allocator_pair.number_of_erased_nodes = swap_number_of_erased_nodes; - #endif } }; @@ -3411,15 +3015,9 @@ inline void swap(list &a, list Date: Sat, 6 Jul 2019 18:06:45 +0200 Subject: [PATCH 03/10] Astyle --- src/list.h | 3857 ++++++++++++++++++++++++---------------------------- 1 file changed, 1815 insertions(+), 2042 deletions(-) diff --git a/src/list.h b/src/list.h index d6f3ea8443383..23cacd632339c 100644 --- a/src/list.h +++ b/src/list.h @@ -66,1197 +66,1125 @@ namespace plf -template > class list : private element_allocator_type +template > class + list : private element_allocator_type { -public: - // Standard container typedefs: - typedef element_type value_type; - typedef element_allocator_type allocator_type; - typedef unsigned short group_size_type; + public: + // Standard container typedefs: + typedef element_type value_type; + typedef element_allocator_type allocator_type; + typedef unsigned short group_size_type; typedef typename std::allocator_traits::size_type size_type; typedef typename std::allocator_traits::difference_type difference_type; - typedef element_type & reference; - typedef const element_type & const_reference; + typedef element_type &reference; + typedef const element_type &const_reference; typedef typename std::allocator_traits::pointer pointer; typedef typename std::allocator_traits::const_pointer const_pointer; - // Iterator declarations: - template class list_iterator; - typedef list_iterator iterator; - typedef list_iterator const_iterator; - friend class list_iterator; // Using 'iterator' typedef name here is illegal under C++03 - friend class list_iterator; + // Iterator declarations: + template class list_iterator; + typedef list_iterator iterator; + typedef list_iterator const_iterator; + friend class list_iterator; // Using 'iterator' typedef name here is illegal under C++03 + friend class list_iterator; - template class list_reverse_iterator; - typedef list_reverse_iterator reverse_iterator; - typedef list_reverse_iterator const_reverse_iterator; - friend class list_reverse_iterator; - friend class list_reverse_iterator; + template class list_reverse_iterator; + typedef list_reverse_iterator reverse_iterator; + typedef list_reverse_iterator const_reverse_iterator; + friend class list_reverse_iterator; + friend class list_reverse_iterator; -private: - struct group; // forward declarations for typedefs below - struct node; + private: + struct group; // forward declarations for typedefs below + struct node; - typedef typename std::allocator_traits::template rebind_alloc group_allocator_type; - typedef typename std::allocator_traits::template rebind_alloc node_allocator_type; - typedef typename std::allocator_traits::pointer group_pointer_type; - typedef typename std::allocator_traits::pointer node_pointer_type; - typedef typename std::allocator_traits::template rebind_alloc node_pointer_allocator_type; + typedef typename std::allocator_traits::template rebind_alloc + group_allocator_type; + typedef typename std::allocator_traits::template rebind_alloc + node_allocator_type; + typedef typename std::allocator_traits::pointer + group_pointer_type; + typedef typename std::allocator_traits::pointer + node_pointer_type; + typedef typename std::allocator_traits::template + rebind_alloc node_pointer_allocator_type; - struct node_base - { - node_pointer_type next, previous; + struct node_base { + node_pointer_type next, previous; - node_base() - {} + node_base() + {} - node_base(const node_pointer_type &n, const node_pointer_type &p): - next(n), - previous(p) - {} + node_base( const node_pointer_type &n, const node_pointer_type &p ): + next( n ), + previous( p ) + {} - node_base(node_pointer_type &&n, node_pointer_type &&p) noexcept: - next(std::move(n)), - previous(std::move(p)) + node_base( node_pointer_type &&n, node_pointer_type &&p ) noexcept: + next( std::move( n ) ), + previous( std::move( p ) ) {} - }; + }; - struct node : public node_base - { - element_type element; + struct node : public node_base { + element_type element; - node(const node_pointer_type next, const node_pointer_type previous, const element_type &source): - node_base(next, previous), - element(source) - {} + node( const node_pointer_type next, const node_pointer_type previous, const element_type &source ): + node_base( next, previous ), + element( source ) + {} - node(node_pointer_type &&next, node_pointer_type &&previous, element_type &&source) noexcept: - node_base(std::move(next), std::move(previous)), - element(std::move(source)) + node( node_pointer_type &&next, node_pointer_type &&previous, element_type &&source ) noexcept: + node_base( std::move( next ), std::move( previous ) ), + element( std::move( source ) ) {} template - node(node_pointer_type const next, node_pointer_type const previous, arguments&&... parameters): - node_base(next, previous), - element(std::forward(parameters) ...) + node( node_pointer_type const next, node_pointer_type const previous, arguments &&... parameters ): + node_base( next, previous ), + element( std::forward( parameters ) ... ) {} - }; + }; - struct group : public node_allocator_type - { - node_pointer_type nodes; - node_pointer_type free_list_head; - node_pointer_type beyond_end; - group_size_type number_of_elements; + struct group : public node_allocator_type { + node_pointer_type nodes; + node_pointer_type free_list_head; + node_pointer_type beyond_end; + group_size_type number_of_elements; - group() noexcept: - nodes(NULL), - free_list_head(NULL), - beyond_end(NULL), - number_of_elements(0) - {} + group() noexcept: + nodes( NULL ), + free_list_head( NULL ), + beyond_end( NULL ), + number_of_elements( 0 ) + {} - group(const group_size_type group_size, node_pointer_type const previous = NULL): - nodes(PLF_LIST_ALLOCATE_INITIALIZATION(node_allocator_type, group_size, previous)), - free_list_head(NULL), - beyond_end(nodes + group_size), - number_of_elements(0) + group( const group_size_type group_size, node_pointer_type const previous = NULL ): + nodes( PLF_LIST_ALLOCATE_INITIALIZATION( node_allocator_type, group_size, previous ) ), + free_list_head( NULL ), + beyond_end( nodes + group_size ), + number_of_elements( 0 ) {} - group & operator = (const group &source) noexcept // Actually a move operator, used by c++03 in group_vector's remove, expand_capacity and append - { - nodes = source.nodes; - free_list_head = source.free_list_head; - beyond_end = source.beyond_end; - number_of_elements = source.number_of_elements; - return *this; - } + group &operator = ( const group &source ) + noexcept { // Actually a move operator, used by c++03 in group_vector's remove, expand_capacity and append + nodes = source.nodes; + free_list_head = source.free_list_head; + beyond_end = source.beyond_end; + number_of_elements = source.number_of_elements; + return *this; + } - group(group &&source) noexcept: - node_allocator_type(source), - nodes(std::move(source.nodes)), - free_list_head(std::move(source.free_list_head)), - beyond_end(std::move(source.beyond_end)), - number_of_elements(source.number_of_elements) - { + group( group &&source ) noexcept: + node_allocator_type( source ), + nodes( std::move( source.nodes ) ), + free_list_head( std::move( source.free_list_head ) ), + beyond_end( std::move( source.beyond_end ) ), + number_of_elements( source.number_of_elements ) { source.nodes = NULL; source.beyond_end = NULL; } - group & operator = (group &&source) noexcept - { - nodes = std::move(source.nodes); - free_list_head = std::move(source.free_list_head); - beyond_end = std::move(source.beyond_end); - number_of_elements = std::move(source.number_of_elements); + group &operator = ( group &&source ) noexcept { + nodes = std::move( source.nodes ); + free_list_head = std::move( source.free_list_head ); + beyond_end = std::move( source.beyond_end ); + number_of_elements = std::move( source.number_of_elements ); source.nodes = NULL; source.beyond_end = NULL; return *this; } - ~group() noexcept - { - PLF_LIST_DEALLOCATE(node_allocator_type, (*this), nodes, static_cast(beyond_end - nodes)); - } - }; + ~group() noexcept { + PLF_LIST_DEALLOCATE( node_allocator_type, ( *this ), nodes, + static_cast( beyond_end - nodes ) ); + } + }; - class group_vector : private node_pointer_allocator_type - { - public: - group_pointer_type last_endpoint_group, block_pointer, last_searched_group; // last_endpoint_group is the last -active- group in the block. Other -inactive- (previously used, now empty of elements) groups may be stored after this group for future usage (to reduce deallocation/reallocation of nodes). block_pointer + size - 1 == the last group in the block, regardless of whether or not the group is active. - size_type size; + class group_vector : private node_pointer_allocator_type + { + public: + group_pointer_type last_endpoint_group, block_pointer, + last_searched_group; // last_endpoint_group is the last -active- group in the block. Other -inactive- (previously used, now empty of elements) groups may be stored after this group for future usage (to reduce deallocation/reallocation of nodes). block_pointer + size - 1 == the last group in the block, regardless of whether or not the group is active. + size_type size; - struct ebco_pair2 : allocator_type // empty-base-class optimisation - { - size_type capacity; // Total element capacity of all initialized groups - explicit ebco_pair2(const size_type number_of_elements) noexcept: capacity(number_of_elements) {}; - } element_allocator_pair; + struct ebco_pair2 : allocator_type { // empty-base-class optimisation + size_type capacity; // Total element capacity of all initialized groups + explicit ebco_pair2( const size_type number_of_elements ) noexcept: capacity( + number_of_elements ) {}; + } element_allocator_pair; - struct ebco_pair : group_allocator_type - { - size_type capacity; // Total group capacity - explicit ebco_pair(const size_type number_of_groups) noexcept: capacity(number_of_groups) {}; - } group_allocator_pair; + struct ebco_pair : group_allocator_type { + size_type capacity; // Total group capacity + explicit ebco_pair( const size_type number_of_groups ) noexcept: capacity( number_of_groups ) {}; + } group_allocator_pair; - group_vector() noexcept: - node_pointer_allocator_type(node_pointer_allocator_type()), - last_endpoint_group(NULL), - block_pointer(NULL), - last_searched_group(NULL), - size(0), - element_allocator_pair(0), - group_allocator_pair(0) - {} + group_vector() noexcept: + node_pointer_allocator_type( node_pointer_allocator_type() ), + last_endpoint_group( NULL ), + block_pointer( NULL ), + last_searched_group( NULL ), + size( 0 ), + element_allocator_pair( 0 ), + group_allocator_pair( 0 ) + {} - inline PLF_LIST_FORCE_INLINE void blank() noexcept - { - if PLF_LIST_CONSTEXPR (std::is_trivial::value) - { - std::memset(static_cast(this), 0, sizeof(group_vector)); - } - else - { - last_endpoint_group = NULL; - block_pointer = NULL; - last_searched_group = NULL; - size = 0; - element_allocator_pair.capacity = 0; - group_allocator_pair.capacity = 0; - } - } + inline PLF_LIST_FORCE_INLINE void blank() noexcept { + if PLF_LIST_CONSTEXPR( std::is_trivial::value ) { + std::memset( static_cast( this ), 0, sizeof( group_vector ) ); + } else { + last_endpoint_group = NULL; + block_pointer = NULL; + last_searched_group = NULL; + size = 0; + element_allocator_pair.capacity = 0; + group_allocator_pair.capacity = 0; + } + } - group_vector(group_vector &&source) noexcept: - last_endpoint_group(std::move(source.last_endpoint_group)), - block_pointer(std::move(source.block_pointer)), - last_searched_group(std::move(source.last_searched_group)), - size(source.size), - element_allocator_pair(source.element_allocator_pair.capacity), - group_allocator_pair(source.group_allocator_pair.capacity) - { - source.blank(); - } + group_vector( group_vector &&source ) noexcept: + last_endpoint_group( std::move( source.last_endpoint_group ) ), + block_pointer( std::move( source.block_pointer ) ), + last_searched_group( std::move( source.last_searched_group ) ), + size( source.size ), + element_allocator_pair( source.element_allocator_pair.capacity ), + group_allocator_pair( source.group_allocator_pair.capacity ) { + source.blank(); + } - group_vector & operator = (group_vector &&source) noexcept - { - if PLF_LIST_CONSTEXPR (std::is_trivial::value) - { - std::memcpy(static_cast(this), &source, sizeof(group_vector)); + group_vector &operator = ( group_vector &&source ) noexcept { + if PLF_LIST_CONSTEXPR( std::is_trivial::value ) { + std::memcpy( static_cast( this ), &source, sizeof( group_vector ) ); + } else { + last_endpoint_group = std::move( source.last_endpoint_group ); + block_pointer = std::move( source.block_pointer ); + last_searched_group = std::move( source.last_searched_group ); + size = source.size; + element_allocator_pair.capacity = source.element_allocator_pair.capacity; + group_allocator_pair.capacity = source.group_allocator_pair.capacity; } - else - { - last_endpoint_group = std::move(source.last_endpoint_group); - block_pointer = std::move(source.block_pointer); - last_searched_group = std::move(source.last_searched_group); - size = source.size; - element_allocator_pair.capacity = source.element_allocator_pair.capacity; - group_allocator_pair.capacity = source.group_allocator_pair.capacity; + + source.blank(); + return *this; } - source.blank(); - return *this; - } + ~group_vector() noexcept + {} - ~group_vector() noexcept - {} + void destroy_all_data( const node_pointer_type last_endpoint_node ) noexcept { + if( block_pointer == NULL ) { + return; + } - void destroy_all_data(const node_pointer_type last_endpoint_node) noexcept - { - if (block_pointer == NULL) - { - return; - } + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value || + !std::is_trivially_destructible::value ) { + clear( last_endpoint_node ); // If clear has already been called, last_endpoint_node will already be == block_pointer->nodes, so no work will occur + } - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) - { - clear(last_endpoint_node); // If clear has already been called, last_endpoint_node will already be == block_pointer->nodes, so no work will occur - } + const group_pointer_type end_group = block_pointer + size; + for( group_pointer_type current_group = block_pointer; current_group != end_group; + ++current_group ) { + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); + } - const group_pointer_type end_group = block_pointer + size; - for (group_pointer_type current_group = block_pointer; current_group != end_group; ++current_group) - { - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, current_group); - } + PLF_LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, block_pointer, + group_allocator_pair.capacity ); + blank(); + } - PLF_LIST_DEALLOCATE(group_allocator_type, group_allocator_pair, block_pointer, group_allocator_pair.capacity); - blank(); - } + void clear( const node_pointer_type last_endpoint_node ) noexcept { + for( group_pointer_type current_group = block_pointer; current_group != last_endpoint_group; + ++current_group ) { + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value || + !std::is_trivially_destructible::value ) { + const node_pointer_type end = current_group->beyond_end; - void clear(const node_pointer_type last_endpoint_node) noexcept - { - for (group_pointer_type current_group = block_pointer; current_group != last_endpoint_group; ++current_group) - { - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) - { - const node_pointer_type end = current_group->beyond_end; + if( ( end - current_group->nodes ) != + current_group->number_of_elements ) { // If there are erased nodes present in the group + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + if( current_node->next != NULL ) { // ie. is not part of free list + PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + } + } - if ((end - current_group->nodes) != current_group->number_of_elements) // If there are erased nodes present in the group - { - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - if (current_node->next != NULL) // ie. is not part of free list - { - PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + } + } + } else { + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + } + + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + } } - } - - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); } } - } - else - { - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); - } - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); - } - } + current_group->free_list_head = NULL; + current_group->number_of_elements = 0; } - } - current_group->free_list_head = NULL; - current_group->number_of_elements = 0; - } + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value || + !std::is_trivially_destructible::value ) { + if( ( last_endpoint_node - last_endpoint_group->nodes ) != + last_endpoint_group->number_of_elements ) { // If there are erased nodes present in the group + for( node_pointer_type current_node = last_endpoint_group->nodes; + current_node != last_endpoint_node; ++current_node ) { + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + if( current_node->next != + NULL ) { // is not part of free list ie. element has not already had it's destructor called + PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + } + } - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value || !std::is_trivially_destructible::value) - { - if ((last_endpoint_node - last_endpoint_group->nodes) != last_endpoint_group->number_of_elements) // If there are erased nodes present in the group - { - for (node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node) - { - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - if (current_node->next != NULL) // is not part of free list ie. element has not already had it's destructor called - { - PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + } } - } + } else { + for( node_pointer_type current_node = last_endpoint_group->nodes; + current_node != last_endpoint_node; ++current_node ) { + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + } - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + } + } } } - } - else - { - for (node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node) - { - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(element_allocator_type, element_allocator_pair, &(current_node->element)); - } - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->next)); - PLF_LIST_DESTROY(node_pointer_allocator_type, (*this), &(current_node->previous)); - } - } + last_endpoint_group->free_list_head = NULL; + last_endpoint_group->number_of_elements = 0; + last_searched_group = last_endpoint_group = block_pointer; } - } - last_endpoint_group->free_list_head = NULL; - last_endpoint_group->number_of_elements = 0; - last_searched_group = last_endpoint_group = block_pointer; - } + void expand_capacity( const size_type new_capacity ) { // used by add_new and append + group_pointer_type const old_block = block_pointer; + block_pointer = PLF_LIST_ALLOCATE( group_allocator_type, group_allocator_pair, new_capacity, 0 ); - void expand_capacity(const size_type new_capacity) // used by add_new and append - { - group_pointer_type const old_block = block_pointer; - block_pointer = PLF_LIST_ALLOCATE(group_allocator_type, group_allocator_pair, new_capacity, 0); + if PLF_LIST_CONSTEXPR( std::is_trivially_copyable::value && + std::is_trivially_destructible::value ) { + // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer + std::memcpy( static_cast( &*block_pointer ), static_cast( &*old_block ), + sizeof( group ) * size ); // reinterpret_cast necessary to deal with GCC 8 warnings + } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + std::uninitialized_copy( std::make_move_iterator( old_block ), + std::make_move_iterator( old_block + size ), block_pointer ); + } else { + // If allocator supplies non-trivial pointers it becomes necessary to destroy the group. uninitialized_copy will not work in this context as the copy constructor for "group" is overriden in C++03/98. The = operator for "group" has been overriden to make the following work: + const group_pointer_type beyond_end = old_block + size; + group_pointer_type current_new_group = block_pointer; - if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) - { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer - std::memcpy(static_cast(&*block_pointer), static_cast(&*old_block), sizeof(group) * size); // reinterpret_cast necessary to deal with GCC 8 warnings - } - else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) - { - std::uninitialized_copy(std::make_move_iterator(old_block), std::make_move_iterator(old_block + size), block_pointer); - } - else - { - // If allocator supplies non-trivial pointers it becomes necessary to destroy the group. uninitialized_copy will not work in this context as the copy constructor for "group" is overriden in C++03/98. The = operator for "group" has been overriden to make the following work: - const group_pointer_type beyond_end = old_block + size; - group_pointer_type current_new_group = block_pointer; + for( group_pointer_type current_group = old_block; current_group != beyond_end; ++current_group ) { + *( current_new_group++ ) = *( current_group ); - for (group_pointer_type current_group = old_block; current_group != beyond_end; ++current_group) - { - *(current_new_group++) = *(current_group); + current_group->nodes = NULL; + current_group->beyond_end = NULL; + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); + } + } - current_group->nodes = NULL; - current_group->beyond_end = NULL; - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, current_group); + last_searched_group = block_pointer + ( last_searched_group - + old_block ); // correct pointer post-reallocation + PLF_LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, old_block, + group_allocator_pair.capacity ); + group_allocator_pair.capacity = new_capacity; } - } - last_searched_group = block_pointer + (last_searched_group - old_block); // correct pointer post-reallocation - PLF_LIST_DEALLOCATE(group_allocator_type, group_allocator_pair, old_block, group_allocator_pair.capacity); - group_allocator_pair.capacity = new_capacity; - } + void add_new( const group_size_type group_size ) { + if( group_allocator_pair.capacity == size ) { + expand_capacity( group_allocator_pair.capacity * 2 ); + } - void add_new(const group_size_type group_size) - { - if (group_allocator_pair.capacity == size) - { - expand_capacity(group_allocator_pair.capacity * 2); - } + last_endpoint_group = block_pointer + size - 1; - last_endpoint_group = block_pointer + size - 1; + PLF_LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, last_endpoint_group + 1, group_size, + last_endpoint_group->nodes ); - PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group + 1, group_size, last_endpoint_group->nodes); + ++last_endpoint_group; // Doing this here instead of pre-construct to avoid need for a try-catch block + element_allocator_pair.capacity += group_size; + ++size; + } - ++last_endpoint_group; // Doing this here instead of pre-construct to avoid need for a try-catch block - element_allocator_pair.capacity += group_size; - ++size; - } + void initialize( const group_size_type + group_size ) { // For adding first group *only* when group vector is completely empty and block_pointer is NULL + last_endpoint_group = block_pointer = last_searched_group = PLF_LIST_ALLOCATE( group_allocator_type, + group_allocator_pair, 1, 0 ); + group_allocator_pair.capacity = 1; - void initialize(const group_size_type group_size) // For adding first group *only* when group vector is completely empty and block_pointer is NULL - { - last_endpoint_group = block_pointer = last_searched_group = PLF_LIST_ALLOCATE(group_allocator_type, group_allocator_pair, 1, 0); - group_allocator_pair.capacity = 1; + PLF_LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, last_endpoint_group, group_size ); - PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, last_endpoint_group, group_size); + size = 1; // Doing these here instead of pre-construct to avoid need for a try-catch block + element_allocator_pair.capacity = group_size; + } - size = 1; // Doing these here instead of pre-construct to avoid need for a try-catch block - element_allocator_pair.capacity = group_size; - } + void remove( group_pointer_type const group_to_erase ) noexcept { + if( last_searched_group >= group_to_erase && last_searched_group != block_pointer ) { + --last_searched_group; + } - void remove(group_pointer_type const group_to_erase) noexcept - { - if (last_searched_group >= group_to_erase && last_searched_group != block_pointer) - { - --last_searched_group; - } + element_allocator_pair.capacity -= static_cast( group_to_erase->beyond_end - + group_to_erase->nodes ); + + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, group_to_erase ); + + if PLF_LIST_CONSTEXPR( std::is_trivially_copyable::value && + std::is_trivially_destructible::value ) { + // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer + std::memmove( static_cast( &*group_to_erase ), static_cast( &*group_to_erase + 1 ), + sizeof( group ) * ( --size - static_cast( &*group_to_erase - &*block_pointer ) ) ); + } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + std::move( group_to_erase + 1, block_pointer + size--, group_to_erase ); + } else { + group_pointer_type back = block_pointer + size--; + std::copy( group_to_erase + 1, back--, group_to_erase ); + + back->nodes = NULL; + back->beyond_end = NULL; + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, back ); + } + } - element_allocator_pair.capacity -= static_cast(group_to_erase->beyond_end - group_to_erase->nodes); - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, group_to_erase); - if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) - { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer - std::memmove(static_cast(&*group_to_erase), static_cast(&*group_to_erase + 1), sizeof(group) * (--size - static_cast(&*group_to_erase - &*block_pointer))); - } - else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) - { - std::move(group_to_erase + 1, block_pointer + size--, group_to_erase); + void move_to_back( group_pointer_type const group_to_erase ) { + if( last_searched_group >= group_to_erase && last_searched_group != block_pointer ) { + --last_searched_group; } - else - { - group_pointer_type back = block_pointer + size--; - std::copy(group_to_erase + 1, back--, group_to_erase); - - back->nodes = NULL; - back->beyond_end = NULL; - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, back); - } - } - + group *temp_group = PLF_LIST_ALLOCATE( group_allocator_type, group_allocator_pair, 1, NULL ); + + if PLF_LIST_CONSTEXPR( std::is_trivially_copyable::value && + std::is_trivially_destructible::value ) { + std::memcpy( static_cast( &*temp_group ), static_cast( &*group_to_erase ), + sizeof( group ) ); + std::memmove( static_cast( &*group_to_erase ), static_cast( &*group_to_erase + 1 ), + sizeof( group ) * ( ( size - 1 ) - static_cast( &*group_to_erase - &*block_pointer ) ) ); + std::memcpy( static_cast( &*( block_pointer + size - 1 ) ), + static_cast( &*temp_group ), sizeof( group ) ); + } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + PLF_LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, + std::move( *group_to_erase ) ); + std::move( group_to_erase + 1, block_pointer + size, group_to_erase ); + *( block_pointer + size - 1 ) = std::move( *temp_group ); + + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, temp_group ); + } + } else { + PLF_LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, group() ); - void move_to_back(group_pointer_type const group_to_erase) - { - if (last_searched_group >= group_to_erase && last_searched_group != block_pointer) - { - --last_searched_group; - } + *temp_group = *group_to_erase; + std::copy( group_to_erase + 1, block_pointer + size, group_to_erase ); + *( block_pointer + --size ) = *temp_group; - group *temp_group = PLF_LIST_ALLOCATE(group_allocator_type, group_allocator_pair, 1, NULL); + temp_group->nodes = NULL; + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, temp_group ); + } - if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) - { - std::memcpy(static_cast(&*temp_group), static_cast(&*group_to_erase), sizeof(group)); - std::memmove(static_cast(&*group_to_erase), static_cast(&*group_to_erase + 1), sizeof(group) * ((size - 1) - static_cast(&*group_to_erase - &*block_pointer))); - std::memcpy(static_cast(&*(block_pointer + size - 1)), static_cast(&*temp_group), sizeof(group)); + PLF_LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, temp_group, 1 ); } - else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) - { - PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, temp_group, std::move(*group_to_erase)); - std::move(group_to_erase + 1, block_pointer + size, group_to_erase); - *(block_pointer + size - 1) = std::move(*temp_group); - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, temp_group); + + + group_pointer_type get_nearest_freelist_group( const node_pointer_type location_node ) + noexcept { // In working implementation this cannot throw + const group_pointer_type beyond_end_group = last_endpoint_group + 1; + group_pointer_type left = last_searched_group - 1, right = last_searched_group + 1, + freelist_group = NULL; + bool right_not_beyond_back = ( right < beyond_end_group ); + bool left_not_beyond_front = ( left >= block_pointer ); + + + if( location_node >= last_searched_group->nodes && + location_node < last_searched_group->beyond_end ) { // ie. location is within last_search_group + if( last_searched_group->free_list_head != + NULL ) { // if last_searched_group has previously-erased nodes + return last_searched_group; } - } - else - { - PLF_LIST_CONSTRUCT(group_allocator_type, group_allocator_pair, temp_group, group()); + } else { // search for the node group which location_node is located within, using last_searched_group as a starting point and searching left and right. Try and find the closest node group with reusable erased-element locations along the way: + group_pointer_type closest_freelist_left = ( last_searched_group->free_list_head == NULL ) ? NULL : + last_searched_group, closest_freelist_right = ( last_searched_group->free_list_head == NULL ) ? + NULL : last_searched_group; + + while( true ) { + if( right_not_beyond_back ) { + if( ( location_node < right->beyond_end ) && + ( location_node >= right->nodes ) ) { // location_node's group is found + if( right->free_list_head != NULL ) { // group has erased nodes, reuse them: + last_searched_group = right; + return right; + } + + difference_type left_distance; + + if( closest_freelist_right != NULL ) { + last_searched_group = right; + left_distance = right - closest_freelist_right; + + if( left_distance <= 2 ) { // ie. this group is close enough to location_node's group + return closest_freelist_right; + } + + freelist_group = closest_freelist_right; + } else { + last_searched_group = right; + left_distance = right - left; + } + + + // Otherwise find closest group with freelist - check an equal distance on the right to the distance we've checked on the left: + const group_pointer_type end_group = ( ( ( right + left_distance ) > beyond_end_group ) ? + beyond_end_group : ( right + left_distance - 1 ) ); + + while( ++right != end_group ) { + if( right->free_list_head != NULL ) { + return right; + } + } + + if( freelist_group != NULL ) { + return freelist_group; + } + + right_not_beyond_back = ( right < beyond_end_group ); + break; // group with reusable erased nodes not found yet, continue searching in loop below + } - *temp_group = *group_to_erase; - std::copy(group_to_erase + 1, block_pointer + size, group_to_erase); - *(block_pointer + --size) = *temp_group; + if( right->free_list_head != + NULL ) { // location_node's group not found, but a reusable location found + if( ( closest_freelist_right == NULL ) & ( closest_freelist_left == NULL ) ) { + closest_freelist_left = right; + } - temp_group->nodes = NULL; - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, temp_group); - } + closest_freelist_right = right; + } - PLF_LIST_DEALLOCATE(group_allocator_type, group_allocator_pair, temp_group, 1); - } + right_not_beyond_back = ( ++right < beyond_end_group ); + } + if( left_not_beyond_front ) { + if( ( location_node >= left->nodes ) && ( location_node < left->beyond_end ) ) { + if( left->free_list_head != NULL ) { + last_searched_group = left; + return left; + } - group_pointer_type get_nearest_freelist_group(const node_pointer_type location_node) noexcept // In working implementation this cannot throw - { - const group_pointer_type beyond_end_group = last_endpoint_group + 1; - group_pointer_type left = last_searched_group - 1, right = last_searched_group + 1, freelist_group = NULL; - bool right_not_beyond_back = (right < beyond_end_group); - bool left_not_beyond_front = (left >= block_pointer); + difference_type right_distance; + if( closest_freelist_left != NULL ) { + last_searched_group = left; + right_distance = closest_freelist_left - left; - if (location_node >= last_searched_group->nodes && location_node < last_searched_group->beyond_end) // ie. location is within last_search_group - { - if (last_searched_group->free_list_head != NULL) // if last_searched_group has previously-erased nodes - { - return last_searched_group; - } - } - else // search for the node group which location_node is located within, using last_searched_group as a starting point and searching left and right. Try and find the closest node group with reusable erased-element locations along the way: - { - group_pointer_type closest_freelist_left = (last_searched_group->free_list_head == NULL) ? NULL : last_searched_group, closest_freelist_right = (last_searched_group->free_list_head == NULL) ? NULL : last_searched_group; - - while (true) - { - if (right_not_beyond_back) - { - if ((location_node < right->beyond_end) && (location_node >= right->nodes)) // location_node's group is found - { - if (right->free_list_head != NULL) // group has erased nodes, reuse them: - { - last_searched_group = right; - return right; - } + if( right_distance <= 2 ) { + return closest_freelist_left; + } - difference_type left_distance; + freelist_group = closest_freelist_left; + } else { + last_searched_group = left; + right_distance = right - left; + } - if (closest_freelist_right != NULL) - { - last_searched_group = right; - left_distance = right - closest_freelist_right; + // Otherwise find closest group with freelist: + const group_pointer_type end_group = ( ( ( left - right_distance ) < block_pointer ) ? block_pointer + - 1 : ( left - right_distance ) + 1 ); - if (left_distance <= 2) // ie. this group is close enough to location_node's group - { - return closest_freelist_right; - } + while( --left != end_group ) { + if( left->free_list_head != NULL ) { + return left; + } + } - freelist_group = closest_freelist_right; - } - else - { - last_searched_group = right; - left_distance = right - left; - } + if( freelist_group != NULL ) { + return freelist_group; + } + left_not_beyond_front = ( left >= block_pointer ); + break; + } - // Otherwise find closest group with freelist - check an equal distance on the right to the distance we've checked on the left: - const group_pointer_type end_group = (((right + left_distance) > beyond_end_group) ? beyond_end_group : (right + left_distance - 1)); + if( left->free_list_head != NULL ) { + if( ( closest_freelist_left == NULL ) & ( closest_freelist_right == NULL ) ) { + closest_freelist_right = left; + } - while (++right != end_group) - { - if (right->free_list_head != NULL) - { - return right; + closest_freelist_left = left; } + + left_not_beyond_front = ( --left >= block_pointer ); } + } + } + - if (freelist_group != NULL) - { - return freelist_group; + // The node group which location_node is located within, is known at this point. Continue searching outwards from this group until a group is found with a reusable location: + while( true ) { + if( right_not_beyond_back ) { + if( right->free_list_head != NULL ) { + return right; } - right_not_beyond_back = (right < beyond_end_group); - break; // group with reusable erased nodes not found yet, continue searching in loop below + right_not_beyond_back = ( ++right < beyond_end_group ); } - if (right->free_list_head != NULL) // location_node's group not found, but a reusable location found - { - if ((closest_freelist_right == NULL) & (closest_freelist_left == NULL)) - { - closest_freelist_left = right; + if( left_not_beyond_front ) { + if( left->free_list_head != NULL ) { + return left; } - closest_freelist_right = right; + left_not_beyond_front = ( --left >= block_pointer ); } - - right_not_beyond_back = (++right < beyond_end_group); } + // Will never reach here on functioning implementations + } - if (left_not_beyond_front) - { - if ((location_node >= left->nodes) && (location_node < left->beyond_end)) - { - if (left->free_list_head != NULL) - { - last_searched_group = left; - return left; - } - difference_type right_distance; - if (closest_freelist_left != NULL) - { - last_searched_group = left; - right_distance = closest_freelist_left - left; + void swap( group_vector &source ) PLF_LIST_NOEXCEPT_SWAP( group_allocator_type ) { + if PLF_LIST_CONSTEXPR( + std::is_trivial::value ) { // if all pointer types are trivial we can just copy using memcpy - faster - avoids constructors/destructors etc + char temp[sizeof( group_vector )]; + std::memcpy( static_cast( &temp ), static_cast( this ), sizeof( group_vector ) ); + std::memcpy( static_cast( this ), static_cast( &source ), sizeof( group_vector ) ); + std::memcpy( static_cast( &source ), static_cast( &temp ), sizeof( group_vector ) ); + } else { + const group_pointer_type swap_last_endpoint_group = last_endpoint_group, + swap_block_pointer = block_pointer, swap_last_searched_group = last_searched_group; + const size_type swap_size = size, swap_element_capacity = element_allocator_pair.capacity, + swap_capacity = group_allocator_pair.capacity; + + last_endpoint_group = source.last_endpoint_group; + block_pointer = source.block_pointer; + last_searched_group = source.last_searched_group; + size = source.size; + element_allocator_pair.capacity = source.element_allocator_pair.capacity; + group_allocator_pair.capacity = source.group_allocator_pair.capacity; + + source.last_endpoint_group = swap_last_endpoint_group; + source.block_pointer = swap_block_pointer; + source.last_searched_group = swap_last_searched_group; + source.size = swap_size; + source.element_allocator_pair.capacity = swap_element_capacity; + source.group_allocator_pair.capacity = swap_capacity; + } + } - if (right_distance <= 2) - { - return closest_freelist_left; - } - freelist_group = closest_freelist_left; - } - else - { - last_searched_group = left; - right_distance = right - left; - } - // Otherwise find closest group with freelist: - const group_pointer_type end_group = (((left - right_distance) < block_pointer) ? block_pointer - 1 : (left - right_distance) + 1); + void trim_trailing_groups() noexcept { + const group_pointer_type beyond_last = block_pointer + size; - while (--left != end_group) - { - if (left->free_list_head != NULL) - { - return left; - } - } + for( group_pointer_type current_group = last_endpoint_group + 1; current_group != beyond_last; + ++current_group ) { + element_allocator_pair.capacity -= static_cast( current_group->beyond_end - + current_group->nodes ); + PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); + } - if (freelist_group != NULL) - { - return freelist_group; - } + size -= static_cast( beyond_last - ( last_endpoint_group + 1 ) ); + } - left_not_beyond_front = (left >= block_pointer); - break; - } - if (left->free_list_head != NULL) - { - if ((closest_freelist_left == NULL) & (closest_freelist_right == NULL)) - { - closest_freelist_right = left; - } - closest_freelist_left = left; - } + void append( group_vector &source ) { + source.trim_trailing_groups(); + trim_trailing_groups(); - left_not_beyond_front = (--left >= block_pointer); + if( size + source.size > group_allocator_pair.capacity ) { + expand_capacity( size + source.size ); } - } - } - - // The node group which location_node is located within, is known at this point. Continue searching outwards from this group until a group is found with a reusable location: - while (true) - { - if (right_not_beyond_back) - { - if (right->free_list_head != NULL) - { - return right; + if PLF_LIST_CONSTEXPR( std::is_trivially_copyable::value && + std::is_trivially_destructible::value ) { + // &* in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer + std::memcpy( static_cast( &*block_pointer + size ), + static_cast( &*source.block_pointer ), sizeof( group ) * source.size ); + } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + std::uninitialized_copy( std::make_move_iterator( source.block_pointer ), + std::make_move_iterator( source.block_pointer + source.size ), block_pointer + size ); + } else { + group_pointer_type current_new_group = block_pointer + size; + const group_pointer_type beyond_end_source = source.block_pointer + source.size; + + for( group_pointer_type current_group = source.block_pointer; current_group != beyond_end_source; + ++current_group ) { + *( current_new_group++ ) = *( current_group ); + + current_group->nodes = NULL; + current_group->beyond_end = NULL; + PLF_LIST_DESTROY( group_allocator_type, source.group_allocator_pair, current_group ); + } } - right_not_beyond_back = (++right < beyond_end_group); + PLF_LIST_DEALLOCATE( group_allocator_type, source.group_allocator_pair, source.block_pointer, + source.group_allocator_pair.capacity ); + size += source.size; + last_endpoint_group = block_pointer + size - 1; + element_allocator_pair.capacity += source.element_allocator_pair.capacity; + source.blank(); } + }; - if (left_not_beyond_front) - { - if (left->free_list_head != NULL) - { - return left; - } - - left_not_beyond_front = (--left >= block_pointer); - } - } - // Will never reach here on functioning implementations - } + // Implement const/non-const iterator switching pattern: + template struct choose; + template struct choose { + typedef IsTrue type; + }; - void swap(group_vector &source) PLF_LIST_NOEXCEPT_SWAP(group_allocator_type) - { - if PLF_LIST_CONSTEXPR (std::is_trivial::value) // if all pointer types are trivial we can just copy using memcpy - faster - avoids constructors/destructors etc - { - char temp[sizeof(group_vector)]; - std::memcpy(static_cast(&temp), static_cast(this), sizeof(group_vector)); - std::memcpy(static_cast(this), static_cast(&source), sizeof(group_vector)); - std::memcpy(static_cast(&source), static_cast(&temp), sizeof(group_vector)); - } - else - { - const group_pointer_type swap_last_endpoint_group = last_endpoint_group, swap_block_pointer = block_pointer, swap_last_searched_group = last_searched_group; - const size_type swap_size = size, swap_element_capacity = element_allocator_pair.capacity, swap_capacity = group_allocator_pair.capacity; - - last_endpoint_group = source.last_endpoint_group; - block_pointer = source.block_pointer; - last_searched_group = source.last_searched_group; - size = source.size; - element_allocator_pair.capacity = source.element_allocator_pair.capacity; - group_allocator_pair.capacity = source.group_allocator_pair.capacity; - - source.last_endpoint_group = swap_last_endpoint_group; - source.block_pointer = swap_block_pointer; - source.last_searched_group = swap_last_searched_group; - source.size = swap_size; - source.element_allocator_pair.capacity = swap_element_capacity; - source.group_allocator_pair.capacity = swap_capacity; - } - } + template struct choose { + typedef IsFalse type; + }; + public: - void trim_trailing_groups() noexcept + template class list_iterator { - const group_pointer_type beyond_last = block_pointer + size; + private: + node_pointer_type node_pointer; - for (group_pointer_type current_group = last_endpoint_group + 1; current_group != beyond_last; ++current_group) - { - element_allocator_pair.capacity -= static_cast(current_group->beyond_end - current_group->nodes); - PLF_LIST_DESTROY(group_allocator_type, group_allocator_pair, current_group); - } + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename list::value_type value_type; + typedef typename list::difference_type difference_type; + typedef typename choose::type + pointer; + typedef typename choose::type + reference; - size -= static_cast(beyond_last - (last_endpoint_group + 1)); - } + friend class list; - void append(group_vector &source) - { - source.trim_trailing_groups(); - trim_trailing_groups(); + inline PLF_LIST_FORCE_INLINE bool operator == ( const list_iterator rh ) const noexcept { + return ( node_pointer == rh.node_pointer ); + } - if (size + source.size > group_allocator_pair.capacity) - { - expand_capacity(size + source.size); - } - if PLF_LIST_CONSTEXPR (std::is_trivially_copyable::value && std::is_trivially_destructible::value) - { // &* in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer - std::memcpy(static_cast(&*block_pointer + size), static_cast(&*source.block_pointer), sizeof(group) * source.size); + + inline PLF_LIST_FORCE_INLINE bool operator == ( const list_iterator < !is_const > rh ) const + noexcept { + return ( node_pointer == rh.node_pointer ); } - else if PLF_LIST_CONSTEXPR (std::is_move_constructible::value) - { - std::uninitialized_copy(std::make_move_iterator(source.block_pointer), std::make_move_iterator(source.block_pointer + source.size), block_pointer + size); - } - else - { - group_pointer_type current_new_group = block_pointer + size; - const group_pointer_type beyond_end_source = source.block_pointer + source.size; - for (group_pointer_type current_group = source.block_pointer; current_group != beyond_end_source; ++current_group) - { - *(current_new_group++) = *(current_group); - current_group->nodes = NULL; - current_group->beyond_end = NULL; - PLF_LIST_DESTROY(group_allocator_type, source.group_allocator_pair, current_group); + + inline PLF_LIST_FORCE_INLINE bool operator != ( const list_iterator rh ) const noexcept { + return ( node_pointer != rh.node_pointer ); } - } - PLF_LIST_DEALLOCATE(group_allocator_type, source.group_allocator_pair, source.block_pointer, source.group_allocator_pair.capacity); - size += source.size; - last_endpoint_group = block_pointer + size - 1; - element_allocator_pair.capacity += source.element_allocator_pair.capacity; - source.blank(); - } - }; + inline PLF_LIST_FORCE_INLINE bool operator != ( const list_iterator < !is_const > rh ) const + noexcept { + return ( node_pointer != rh.node_pointer ); + } - // Implement const/non-const iterator switching pattern: - template struct choose; - template struct choose - { - typedef IsTrue type; - }; - template struct choose - { - typedef IsFalse type; - }; + inline PLF_LIST_FORCE_INLINE reference operator * () const { + return node_pointer->element; + } -public: - template class list_iterator - { - private: - node_pointer_type node_pointer; + inline PLF_LIST_FORCE_INLINE pointer operator -> () const { + return &( node_pointer->element ); + } - public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef typename list::value_type value_type; - typedef typename list::difference_type difference_type; - typedef typename choose::type pointer; - typedef typename choose::type reference; - friend class list; + inline PLF_LIST_FORCE_INLINE list_iterator &operator ++ () noexcept { + assert( node_pointer != NULL ); // covers uninitialised list_iterator + node_pointer = node_pointer->next; + return *this; + } - inline PLF_LIST_FORCE_INLINE bool operator == (const list_iterator rh) const noexcept - { - return (node_pointer == rh.node_pointer); - } + inline list_iterator operator ++( int ) noexcept { + const list_iterator copy( *this ); + ++*this; + return copy; + } - inline PLF_LIST_FORCE_INLINE bool operator == (const list_iterator rh) const noexcept - { - return (node_pointer == rh.node_pointer); - } + inline PLF_LIST_FORCE_INLINE list_iterator &operator -- () noexcept { + assert( node_pointer != NULL ); // covers uninitialised list_iterator + node_pointer = node_pointer->previous; + return *this; + } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const noexcept - { - return (node_pointer != rh.node_pointer); - } + inline list_iterator operator -- ( int ) noexcept { + const list_iterator copy( *this ); + --*this; + return copy; + } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_iterator rh) const noexcept - { - return (node_pointer != rh.node_pointer); - } + inline list_iterator &operator = ( const list_iterator &rh ) noexcept { + node_pointer = rh.node_pointer; + return *this; + } - inline PLF_LIST_FORCE_INLINE reference operator * () const - { - return node_pointer->element; - } + inline list_iterator &operator = ( const list_iterator < !is_const > &rh ) noexcept { + node_pointer = rh.node_pointer; + return *this; + } - inline PLF_LIST_FORCE_INLINE pointer operator -> () const - { - return &(node_pointer->element); - } + inline list_iterator &operator = ( const list_iterator &&rh ) noexcept { + node_pointer = std::move( rh.node_pointer ); + return *this; + } - inline PLF_LIST_FORCE_INLINE list_iterator & operator ++ () noexcept - { - assert(node_pointer != NULL); // covers uninitialised list_iterator - node_pointer = node_pointer->next; - return *this; - } + inline list_iterator &operator = ( const list_iterator < !is_const > &&rh ) noexcept { + node_pointer = std::move( rh.node_pointer ); + return *this; + } - inline list_iterator operator ++(int) noexcept - { - const list_iterator copy(*this); - ++*this; - return copy; - } + list_iterator() noexcept: node_pointer( NULL ) {} + list_iterator( const list_iterator &source ) noexcept: node_pointer( source.node_pointer ) {} + list_iterator( const list_iterator < !is_const > &source ) noexcept: node_pointer( + source.node_pointer ) {} - inline PLF_LIST_FORCE_INLINE list_iterator & operator -- () noexcept - { - assert(node_pointer != NULL); // covers uninitialised list_iterator - node_pointer = node_pointer->previous; - return *this; - } + list_iterator( const list_iterator &&source ) noexcept: node_pointer( std::move( + source.node_pointer ) ) {} + list_iterator( const list_iterator < !is_const > && + source ) noexcept: node_pointer( std::move( source.node_pointer ) ) {} + private: - inline list_iterator operator -- (int) noexcept - { - const list_iterator copy(*this); - --*this; - return copy; - } + list_iterator( const node_pointer_type node_p ) noexcept: node_pointer( node_p ) {} + }; - inline list_iterator & operator = (const list_iterator &rh) noexcept + + template class list_reverse_iterator { - node_pointer = rh.node_pointer; - return *this; - } + private: + node_pointer_type node_pointer; + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef typename list::value_type value_type; + typedef typename list::difference_type difference_type; + typedef typename choose::type + pointer; + typedef typename choose::type + reference; + friend class list; - inline list_iterator & operator = (const list_iterator &rh) noexcept - { - node_pointer = rh.node_pointer; - return *this; - } + inline PLF_LIST_FORCE_INLINE bool operator == ( const list_reverse_iterator rh ) const noexcept { + return ( node_pointer == rh.node_pointer ); + } - inline list_iterator & operator = (const list_iterator &&rh) noexcept - { - node_pointer = std::move(rh.node_pointer); - return *this; - } + inline PLF_LIST_FORCE_INLINE bool operator == ( const list_reverse_iterator < !is_const > rh ) const + noexcept { + return ( node_pointer == rh.node_pointer ); + } - inline list_iterator & operator = (const list_iterator &&rh) noexcept - { - node_pointer = std::move(rh.node_pointer); - return *this; - } + inline PLF_LIST_FORCE_INLINE bool operator != ( const list_reverse_iterator rh ) const noexcept { + return ( node_pointer != rh.node_pointer ); + } - list_iterator() noexcept: node_pointer(NULL) {} - list_iterator(const list_iterator &source) noexcept: node_pointer(source.node_pointer) {} - list_iterator(const list_iterator &source) noexcept: node_pointer(source.node_pointer) {} + inline PLF_LIST_FORCE_INLINE bool operator != ( const list_reverse_iterator < !is_const > rh ) const + noexcept { + return ( node_pointer != rh.node_pointer ); + } - list_iterator (const list_iterator &&source) noexcept: node_pointer(std::move(source.node_pointer)) {} - list_iterator(const list_iterator &&source) noexcept: node_pointer(std::move(source.node_pointer)) {} - private: + inline PLF_LIST_FORCE_INLINE reference operator * () const { + return node_pointer->element; + } - list_iterator (const node_pointer_type node_p) noexcept: node_pointer(node_p) {} - }; + inline PLF_LIST_FORCE_INLINE pointer operator -> () const { + return &( node_pointer->element ); + } - template class list_reverse_iterator - { - private: - node_pointer_type node_pointer; - public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef typename list::value_type value_type; - typedef typename list::difference_type difference_type; - typedef typename choose::type pointer; - typedef typename choose::type reference; + inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator ++ () noexcept { + assert( node_pointer != NULL ); // covers uninitialised list_reverse_iterator + node_pointer = node_pointer->previous; + return *this; + } - friend class list; - inline PLF_LIST_FORCE_INLINE bool operator == (const list_reverse_iterator rh) const noexcept - { - return (node_pointer == rh.node_pointer); - } + inline list_reverse_iterator operator ++( int ) noexcept { + const list_reverse_iterator copy( *this ); + ++*this; + return copy; + } - inline PLF_LIST_FORCE_INLINE bool operator == (const list_reverse_iterator rh) const noexcept - { - return (node_pointer == rh.node_pointer); - } + inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator -- () noexcept { + assert( node_pointer != NULL ); + node_pointer = node_pointer->next; + return *this; + } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const noexcept - { - return (node_pointer != rh.node_pointer); - } + inline list_reverse_iterator operator -- ( int ) noexcept { + const list_reverse_iterator copy( *this ); + --*this; + return copy; + } - inline PLF_LIST_FORCE_INLINE bool operator != (const list_reverse_iterator rh) const noexcept - { - return (node_pointer != rh.node_pointer); - } + inline list_reverse_iterator &operator = ( const list_reverse_iterator &rh ) noexcept { + node_pointer = rh.node_pointer; + return *this; + } - inline PLF_LIST_FORCE_INLINE reference operator * () const - { - return node_pointer->element; - } + inline list_reverse_iterator &operator = ( const list_reverse_iterator < !is_const > &rh ) + noexcept { + node_pointer = rh.node_pointer; + return *this; + } - inline PLF_LIST_FORCE_INLINE pointer operator -> () const - { - return &(node_pointer->element); - } + inline list_reverse_iterator &operator = ( const list_reverse_iterator &&rh ) noexcept { + node_pointer = std::move( rh.node_pointer ); + return *this; + } + inline list_reverse_iterator &operator = ( const list_reverse_iterator < !is_const > && + rh ) noexcept { + node_pointer = std::move( rh.node_pointer ); + return *this; + } - inline PLF_LIST_FORCE_INLINE list_reverse_iterator & operator ++ () noexcept - { - assert(node_pointer != NULL); // covers uninitialised list_reverse_iterator - node_pointer = node_pointer->previous; - return *this; - } + inline typename list::iterator base() const noexcept { + return typename list::iterator( node_pointer->next ); + } - inline list_reverse_iterator operator ++(int) noexcept - { - const list_reverse_iterator copy(*this); - ++*this; - return copy; - } + list_reverse_iterator() noexcept: node_pointer( NULL ) {} - inline PLF_LIST_FORCE_INLINE list_reverse_iterator & operator -- () noexcept - { - assert(node_pointer != NULL); - node_pointer = node_pointer->next; - return *this; - } + list_reverse_iterator( const list_reverse_iterator &source ) noexcept: node_pointer( + source.node_pointer ) {} + list_reverse_iterator( const list_reverse_iterator &&source ) noexcept: node_pointer( std::move( + source.node_pointer ) ) {} + private: - inline list_reverse_iterator operator -- (int) noexcept - { - const list_reverse_iterator copy(*this); - --*this; - return copy; - } + list_reverse_iterator( const node_pointer_type node_p ) noexcept: node_pointer( node_p ) {} + }; - inline list_reverse_iterator & operator = (const list_reverse_iterator &rh) noexcept - { - node_pointer = rh.node_pointer; - return *this; - } + private: + // Used by range-insert and range-constructor to prevent fill-insert and fill-constructor function calls mistakenly resolving to the range insert/constructor + template + struct plf_enable_if_c { + typedef T type; + }; + template + struct plf_enable_if_c { + }; - inline list_reverse_iterator & operator = (const list_reverse_iterator &rh) noexcept - { - node_pointer = rh.node_pointer; - return *this; - } + group_vector groups; + node_base end_node; + node_pointer_type + last_endpoint; // last_endpoint being NULL means no elements have been constructed, but there may still be groups available due to clear() or reservee() + iterator end_iterator, + begin_iterator; // end_iterator is always the last entry point in last group in list (or one past the end of group) - inline list_reverse_iterator & operator = (const list_reverse_iterator &&rh) noexcept - { - node_pointer = std::move(rh.node_pointer); - return *this; - } + struct ebco_pair1 : + node_pointer_allocator_type { // Packaging the group allocator with least-used member variables, for empty-base-class optimisation + size_type total_number_of_elements; + explicit ebco_pair1( const size_type total_num_elements ) noexcept: total_number_of_elements( + total_num_elements ) {} + } node_pointer_allocator_pair; + struct ebco_pair2 : node_allocator_type { + size_type number_of_erased_nodes; + explicit ebco_pair2( const size_type num_erased_nodes ) noexcept: number_of_erased_nodes( + num_erased_nodes ) {} + } node_allocator_pair; - inline list_reverse_iterator & operator = (const list_reverse_iterator &&rh) noexcept - { - node_pointer = std::move(rh.node_pointer); - return *this; - } - - - - inline typename list::iterator base() const noexcept - { - return typename list::iterator(node_pointer->next); - } - - - - list_reverse_iterator() noexcept: node_pointer(NULL) {} - - list_reverse_iterator(const list_reverse_iterator &source) noexcept: node_pointer(source.node_pointer) {} - - list_reverse_iterator (const list_reverse_iterator &&source) noexcept: node_pointer(std::move(source.node_pointer)) {} - - private: - - list_reverse_iterator (const node_pointer_type node_p) noexcept: node_pointer(node_p) {} - }; + public: -private: - - // Used by range-insert and range-constructor to prevent fill-insert and fill-constructor function calls mistakenly resolving to the range insert/constructor - template - struct plf_enable_if_c - { - typedef T type; - }; - - template - struct plf_enable_if_c - {}; - - - - group_vector groups; - node_base end_node; - node_pointer_type last_endpoint; // last_endpoint being NULL means no elements have been constructed, but there may still be groups available due to clear() or reservee() - iterator end_iterator, begin_iterator; // end_iterator is always the last entry point in last group in list (or one past the end of group) - - struct ebco_pair1 : node_pointer_allocator_type // Packaging the group allocator with least-used member variables, for empty-base-class optimisation - { - size_type total_number_of_elements; - explicit ebco_pair1(const size_type total_num_elements) noexcept: total_number_of_elements(total_num_elements) {} - } node_pointer_allocator_pair; - - struct ebco_pair2 : node_allocator_type - { - size_type number_of_erased_nodes; - explicit ebco_pair2(const size_type num_erased_nodes) noexcept: number_of_erased_nodes(num_erased_nodes) {} - } node_allocator_pair; - - - -public: - - // Default constructor: - - list() noexcept: - element_allocator_type(element_allocator_type()), - end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - {} + // Default constructor: + + list() noexcept: + element_allocator_type( element_allocator_type() ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) + {} - // Allocator-extended constructor: + // Allocator-extended constructor: - explicit list(const element_allocator_type &alloc): - element_allocator_type(alloc), - end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - {} + explicit list( const element_allocator_type &alloc ): + element_allocator_type( alloc ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) + {} - // Copy constructor: + // Copy constructor: - list(const list &source): - element_allocator_type(source), - end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - { - reserve(source.node_pointer_allocator_pair.total_number_of_elements); - insert(end_iterator, source.begin_iterator, source.end_iterator); - } + list( const list &source ): + element_allocator_type( source ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) { + reserve( source.node_pointer_allocator_pair.total_number_of_elements ); + insert( end_iterator, source.begin_iterator, source.end_iterator ); + } - // Allocator-extended copy constructor: + // Allocator-extended copy constructor: - list(const list &source, const allocator_type &alloc): - element_allocator_type(alloc), - end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - { - reserve(source.node_pointer_allocator_pair.total_number_of_elements); - insert(end_iterator, source.begin_iterator, source.end_iterator); - } + list( const list &source, const allocator_type &alloc ): + element_allocator_type( alloc ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) { + reserve( source.node_pointer_allocator_pair.total_number_of_elements ); + insert( end_iterator, source.begin_iterator, source.end_iterator ); + } // Move constructor: - list(list &&source) noexcept: - element_allocator_type(source), - groups(std::move(source.groups)), - end_node(std::move(source.end_node)), - last_endpoint(std::move(source.last_endpoint)), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator((source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? reinterpret_cast(&end_node) : std::move(source.begin_iterator)), - node_pointer_allocator_pair(source.node_pointer_allocator_pair.total_number_of_elements), - node_allocator_pair(source.node_allocator_pair.number_of_erased_nodes) - { + list( list &&source ) noexcept: + element_allocator_type( source ), + groups( std::move( source.groups ) ), + end_node( std::move( source.end_node ) ), + last_endpoint( std::move( source.last_endpoint ) ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( ( source.begin_iterator.node_pointer == source.end_iterator.node_pointer ) ? + reinterpret_cast( &end_node ) : std::move( source.begin_iterator ) ), + node_pointer_allocator_pair( source.node_pointer_allocator_pair.total_number_of_elements ), + node_allocator_pair( source.node_allocator_pair.number_of_erased_nodes ) { end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; source.groups.blank(); source.reset(); @@ -1266,16 +1194,16 @@ template (&end_node)), - begin_iterator((source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? reinterpret_cast(&end_node) : std::move(source.begin_iterator)), - node_pointer_allocator_pair(source.node_pointer_allocator_pair.total_number_of_elements), - node_allocator_pair(source.node_allocator_pair.number_of_erased_nodes) - { + list( list &&source, const allocator_type &alloc ): + element_allocator_type( alloc ), + groups( std::move( source.groups ) ), + end_node( std::move( source.end_node ) ), + last_endpoint( std::move( source.last_endpoint ) ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( ( source.begin_iterator.node_pointer == source.end_iterator.node_pointer ) ? + reinterpret_cast( &end_node ) : std::move( source.begin_iterator ) ), + node_pointer_allocator_pair( source.node_pointer_allocator_pair.total_number_of_elements ), + node_allocator_pair( source.node_allocator_pair.number_of_erased_nodes ) { end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; source.groups.blank(); source.reset(); @@ -1283,399 +1211,365 @@ template (&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - { - reserve(fill_number); - insert(end_iterator, fill_number, element); - } + list( const size_type fill_number, const element_type &element, + const element_allocator_type &alloc = element_allocator_type() ): + element_allocator_type( alloc ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) { + reserve( fill_number ); + insert( end_iterator, fill_number, element ); + } - // Range constructor: + // Range constructor: - template - list(const typename plf_enable_if_c::is_integer, iterator_type>::type &first, const iterator_type &last, const element_allocator_type &alloc = element_allocator_type()): - element_allocator_type(alloc), - end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - { - insert(end_iterator, first, last); - } + template + list( const typename plf_enable_if_c < !std::numeric_limits::is_integer, + iterator_type >::type &first, const iterator_type &last, + const element_allocator_type &alloc = element_allocator_type() ): + element_allocator_type( alloc ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) { + insert( end_iterator, first, last ); + } - // Initializer-list constructor: + // Initializer-list constructor: - list(const std::initializer_list &element_list, const element_allocator_type &alloc = element_allocator_type()): - element_allocator_type(alloc), - end_node(reinterpret_cast(&end_node), reinterpret_cast(&end_node)), - last_endpoint(NULL), - end_iterator(reinterpret_cast(&end_node)), - begin_iterator(reinterpret_cast(&end_node)), - node_pointer_allocator_pair(0), - node_allocator_pair(0) - { - reserve(element_list.size()); - insert(end_iterator, element_list); + list( const std::initializer_list &element_list, + const element_allocator_type &alloc = element_allocator_type() ): + element_allocator_type( alloc ), + end_node( reinterpret_cast( &end_node ), + reinterpret_cast( &end_node ) ), + last_endpoint( NULL ), + end_iterator( reinterpret_cast( &end_node ) ), + begin_iterator( reinterpret_cast( &end_node ) ), + node_pointer_allocator_pair( 0 ), + node_allocator_pair( 0 ) { + reserve( element_list.size() ); + insert( end_iterator, element_list ); } - ~list() noexcept - { - groups.destroy_all_data(last_endpoint); - } + ~list() noexcept { + groups.destroy_all_data( last_endpoint ); + } - inline iterator begin() noexcept - { - return begin_iterator; - } + inline iterator begin() noexcept { + return begin_iterator; + } - inline const_iterator begin() const noexcept - { - return begin_iterator; - } + inline const_iterator begin() const noexcept { + return begin_iterator; + } - inline iterator end() noexcept - { - return end_iterator; - } + inline iterator end() noexcept { + return end_iterator; + } - inline const_iterator end() const noexcept - { - return end_iterator; - } + inline const_iterator end() const noexcept { + return end_iterator; + } - inline const_iterator cbegin() const noexcept - { - return const_iterator(begin_iterator.node_pointer); - } + inline const_iterator cbegin() const noexcept { + return const_iterator( begin_iterator.node_pointer ); + } - inline const_iterator cend() const noexcept - { - return const_iterator(end_iterator.node_pointer); - } + inline const_iterator cend() const noexcept { + return const_iterator( end_iterator.node_pointer ); + } - inline reverse_iterator rbegin() const noexcept - { - return reverse_iterator(end_node.previous); - } + inline reverse_iterator rbegin() const noexcept { + return reverse_iterator( end_node.previous ); + } - inline reverse_iterator rend() const noexcept - { - return reverse_iterator(end_iterator.node_pointer); - } + inline reverse_iterator rend() const noexcept { + return reverse_iterator( end_iterator.node_pointer ); + } - inline const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(end_node.previous); - } + inline const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator( end_node.previous ); + } - inline const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(end_iterator.node_pointer); - } + inline const_reverse_iterator crend() const noexcept { + return const_reverse_iterator( end_iterator.node_pointer ); + } - inline reference front() - { - assert(begin_iterator.node_pointer != &end_node); - return begin_iterator.node_pointer->element; - } + inline reference front() { + assert( begin_iterator.node_pointer != &end_node ); + return begin_iterator.node_pointer->element; + } - inline const_reference front() const - { - assert(begin_iterator.node_pointer != &end_node); - return begin_iterator.node_pointer->element; - } + inline const_reference front() const { + assert( begin_iterator.node_pointer != &end_node ); + return begin_iterator.node_pointer->element; + } - inline reference back() - { - assert(end_node.previous != &end_node); - return end_node.previous->element; - } + inline reference back() { + assert( end_node.previous != &end_node ); + return end_node.previous->element; + } - inline const_reference back() const - { - assert(end_node.previous != &end_node); - return end_node.previous->element; - } + inline const_reference back() const { + assert( end_node.previous != &end_node ); + return end_node.previous->element; + } - void clear() noexcept - { - if (last_endpoint == NULL) - { - return; - } + void clear() noexcept { + if( last_endpoint == NULL ) { + return; + } - if (node_pointer_allocator_pair.total_number_of_elements != 0) - { - groups.clear(last_endpoint); + if( node_pointer_allocator_pair.total_number_of_elements != 0 ) { + groups.clear( last_endpoint ); + } + + end_node.next = reinterpret_cast( &end_node ); + end_node.previous = reinterpret_cast( &end_node ); + last_endpoint = groups.block_pointer->nodes; + begin_iterator.node_pointer = end_iterator.node_pointer; + node_pointer_allocator_pair.total_number_of_elements = 0; + node_allocator_pair.number_of_erased_nodes = 0; } - end_node.next = reinterpret_cast(&end_node); - end_node.previous = reinterpret_cast(&end_node); - last_endpoint = groups.block_pointer->nodes; - begin_iterator.node_pointer = end_iterator.node_pointer; - node_pointer_allocator_pair.total_number_of_elements = 0; - node_allocator_pair.number_of_erased_nodes = 0; - } + private: -private: + void reset() noexcept { + groups.destroy_all_data( last_endpoint ); + last_endpoint = NULL; + end_node.next = reinterpret_cast( &end_node ); + end_node.previous = reinterpret_cast( &end_node ); + begin_iterator.node_pointer = end_iterator.node_pointer; + node_pointer_allocator_pair.total_number_of_elements = 0; + node_allocator_pair.number_of_erased_nodes = 0; + } - void reset() noexcept - { - groups.destroy_all_data(last_endpoint); - last_endpoint = NULL; - end_node.next = reinterpret_cast(&end_node); - end_node.previous = reinterpret_cast(&end_node); - begin_iterator.node_pointer = end_iterator.node_pointer; - node_pointer_allocator_pair.total_number_of_elements = 0; - node_allocator_pair.number_of_erased_nodes = 0; - } + public: -public: + iterator insert( const iterator it, const element_type &element ) { + if( last_endpoint != NULL ) { // ie. list is not empty + if( node_allocator_pair.number_of_erased_nodes == 0 ) { // No erased nodes available for reuse + if( last_endpoint == + groups.last_endpoint_group->beyond_end ) { // last_endpoint is beyond the end of a group + if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - + 1 ) { // ie. there are no reusable groups available at the back of group vector + groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? + static_cast( node_pointer_allocator_pair.total_number_of_elements ) : + PLF_LIST_BLOCK_MAX ); + } else { + ++groups.last_endpoint_group; + } - iterator insert(const iterator it, const element_type &element) - { - if (last_endpoint != NULL) // ie. list is not empty - { - if (node_allocator_pair.number_of_erased_nodes == 0) // No erased nodes available for reuse - { - if (last_endpoint == groups.last_endpoint_group->beyond_end) // last_endpoint is beyond the end of a group - { - if (static_cast(groups.last_endpoint_group - groups.block_pointer) == groups.size - 1) // ie. there are no reusable groups available at the back of group vector - { - groups.add_new((node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX) ? static_cast(node_pointer_allocator_pair.total_number_of_elements) : PLF_LIST_BLOCK_MAX); - } - else - { - ++groups.last_endpoint_group; + last_endpoint = groups.last_endpoint_group->nodes; } - last_endpoint = groups.last_endpoint_group->nodes; - } + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, + it.node_pointer->previous, element ); - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, element); + ++( groups.last_endpoint_group->number_of_elements ); + ++node_pointer_allocator_pair.total_number_of_elements; - ++(groups.last_endpoint_group->number_of_elements); - ++node_pointer_allocator_pair.total_number_of_elements; + if( it.node_pointer == begin_iterator.node_pointer ) { + begin_iterator.node_pointer = last_endpoint; + } - if (it.node_pointer == begin_iterator.node_pointer) - { - begin_iterator.node_pointer = last_endpoint; - } + it.node_pointer->previous->next = last_endpoint; + it.node_pointer->previous = last_endpoint; - it.node_pointer->previous->next = last_endpoint; - it.node_pointer->previous = last_endpoint; + return iterator( last_endpoint++ ); + } else { + group_pointer_type const node_group = groups.get_nearest_freelist_group( ( + it.node_pointer != end_iterator.node_pointer ) ? it.node_pointer : end_node.previous ); + node_pointer_type const selected_node = node_group->free_list_head; + const node_pointer_type previous = node_group->free_list_head->previous; - return iterator(last_endpoint++); - } - else - { - group_pointer_type const node_group = groups.get_nearest_freelist_group((it.node_pointer != end_iterator.node_pointer) ? it.node_pointer : end_node.previous); - node_pointer_type const selected_node = node_group->free_list_head; - const node_pointer_type previous = node_group->free_list_head->previous; + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, + it.node_pointer->previous, element ); - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, element); + node_group->free_list_head = previous; + ++( node_group->number_of_elements ); + ++node_pointer_allocator_pair.total_number_of_elements; + --node_allocator_pair.number_of_erased_nodes; - node_group->free_list_head = previous; - ++(node_group->number_of_elements); - ++node_pointer_allocator_pair.total_number_of_elements; - --node_allocator_pair.number_of_erased_nodes; + it.node_pointer->previous->next = selected_node; + it.node_pointer->previous = selected_node; - it.node_pointer->previous->next = selected_node; - it.node_pointer->previous = selected_node; + if( it.node_pointer == begin_iterator.node_pointer ) { + begin_iterator.node_pointer = selected_node; + } - if (it.node_pointer == begin_iterator.node_pointer) - { - begin_iterator.node_pointer = selected_node; + return iterator( selected_node ); + } + } else { // list is empty + if( groups.block_pointer == + NULL ) { // In case of prior reserve/clear call as opposed to being uninitialized + groups.initialize( PLF_LIST_BLOCK_MIN ); } - return iterator(selected_node); - } - } - else // list is empty - { - if (groups.block_pointer == NULL) // In case of prior reserve/clear call as opposed to being uninitialized - { - groups.initialize(PLF_LIST_BLOCK_MIN); - } - - groups.last_endpoint_group->number_of_elements = 1; - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - node_pointer_allocator_pair.total_number_of_elements = 1; + groups.last_endpoint_group->number_of_elements = 1; + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; + node_pointer_allocator_pair.total_number_of_elements = 1; - if PLF_LIST_CONSTEXPR (std::is_nothrow_copy_constructible::value) // Avoid try-catch code generation - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element); - } - else - { - try - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element); - } - catch (...) - { - reset(); - throw; + if PLF_LIST_CONSTEXPR( + std::is_nothrow_copy_constructible::value ) { // Avoid try-catch code generation + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + end_iterator.node_pointer, end_iterator.node_pointer, element ); + } else { + try { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + end_iterator.node_pointer, end_iterator.node_pointer, element ); + } catch( ... ) { + reset(); + throw; + } } - } - return begin_iterator; + return begin_iterator; + } } - } - inline PLF_LIST_FORCE_INLINE void push_back(const element_type &element) - { - insert(end_iterator, element); - } + inline PLF_LIST_FORCE_INLINE void push_back( const element_type &element ) { + insert( end_iterator, element ); + } - inline PLF_LIST_FORCE_INLINE void push_front(const element_type &element) - { - insert(begin_iterator, element); - } + inline PLF_LIST_FORCE_INLINE void push_front( const element_type &element ) { + insert( begin_iterator, element ); + } - iterator insert(const iterator it, element_type &&element) // This is almost identical to the insert implementation above with the only change being std::move of the element - { - if (last_endpoint != NULL) - { - if (node_allocator_pair.number_of_erased_nodes == 0) - { - if (last_endpoint == groups.last_endpoint_group->beyond_end) - { - if (static_cast(groups.last_endpoint_group - groups.block_pointer) == groups.size - 1) - { - groups.add_new((node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX) ? static_cast(node_pointer_allocator_pair.total_number_of_elements) : PLF_LIST_BLOCK_MAX); - } - else - { + iterator insert( const iterator it, + element_type + &&element ) { // This is almost identical to the insert implementation above with the only change being std::move of the element + if( last_endpoint != NULL ) { + if( node_allocator_pair.number_of_erased_nodes == 0 ) { + if( last_endpoint == groups.last_endpoint_group->beyond_end ) { + if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - + 1 ) { + groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? + static_cast( node_pointer_allocator_pair.total_number_of_elements ) : + PLF_LIST_BLOCK_MAX ); + } else { ++groups.last_endpoint_group; } last_endpoint = groups.last_endpoint_group->nodes; } - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::move(element)); + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, + it.node_pointer->previous, std::move( element ) ); - ++(groups.last_endpoint_group->number_of_elements); + ++( groups.last_endpoint_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; - if (it.node_pointer == begin_iterator.node_pointer) - { + if( it.node_pointer == begin_iterator.node_pointer ) { begin_iterator.node_pointer = last_endpoint; } it.node_pointer->previous->next = last_endpoint; it.node_pointer->previous = last_endpoint; - return iterator(last_endpoint++); - } - else - { - group_pointer_type const node_group = groups.get_nearest_freelist_group((it.node_pointer != end_iterator.node_pointer) ? it.node_pointer : end_node.previous); + return iterator( last_endpoint++ ); + } else { + group_pointer_type const node_group = groups.get_nearest_freelist_group( ( + it.node_pointer != end_iterator.node_pointer ) ? it.node_pointer : end_node.previous ); node_pointer_type const selected_node = node_group->free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::move(element)); + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, + it.node_pointer->previous, std::move( element ) ); node_group->free_list_head = previous; - ++(node_group->number_of_elements); + ++( node_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; --node_allocator_pair.number_of_erased_nodes; it.node_pointer->previous->next = selected_node; it.node_pointer->previous = selected_node; - if (it.node_pointer == begin_iterator.node_pointer) - { + if( it.node_pointer == begin_iterator.node_pointer ) { begin_iterator.node_pointer = selected_node; } - return iterator(selected_node); + return iterator( selected_node ); } - } - else - { - if (groups.block_pointer == NULL) - { - groups.initialize(PLF_LIST_BLOCK_MIN); + } else { + if( groups.block_pointer == NULL ) { + groups.initialize( PLF_LIST_BLOCK_MIN ); } groups.last_endpoint_group->number_of_elements = 1; - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - if PLF_LIST_CONSTEXPR (std::is_nothrow_move_constructible::value) - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move(element)); + if PLF_LIST_CONSTEXPR( std::is_nothrow_move_constructible::value ) { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); - } - else - { - try - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move(element)); - } - catch (...) - { + } else { + try { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); + } catch( ... ) { reset(); throw; } @@ -1687,105 +1581,94 @@ template - iterator emplace(const iterator it, arguments &&... parameters) // This is almost identical to the insert implementations above with the only changes being std::forward of element parameters and removal of VARIADICS support checking - { - if (last_endpoint != NULL) - { - if (node_allocator_pair.number_of_erased_nodes == 0) - { - if (last_endpoint == groups.last_endpoint_group->beyond_end) - { - if (static_cast(groups.last_endpoint_group - groups.block_pointer) == groups.size - 1) - { - groups.add_new((node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX) ? static_cast(node_pointer_allocator_pair.total_number_of_elements) : PLF_LIST_BLOCK_MAX); - } - else - { + iterator emplace( const iterator it, + arguments &&... + parameters ) { // This is almost identical to the insert implementations above with the only changes being std::forward of element parameters and removal of VARIADICS support checking + if( last_endpoint != NULL ) { + if( node_allocator_pair.number_of_erased_nodes == 0 ) { + if( last_endpoint == groups.last_endpoint_group->beyond_end ) { + if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - + 1 ) { + groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? + static_cast( node_pointer_allocator_pair.total_number_of_elements ) : + PLF_LIST_BLOCK_MAX ); + } else { ++groups.last_endpoint_group; } last_endpoint = groups.last_endpoint_group->nodes; } - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::forward(parameters)...); + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, + it.node_pointer->previous, std::forward( parameters )... ); - ++(groups.last_endpoint_group->number_of_elements); + ++( groups.last_endpoint_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; - if (it.node_pointer == begin_iterator.node_pointer) - { + if( it.node_pointer == begin_iterator.node_pointer ) { begin_iterator.node_pointer = last_endpoint; } it.node_pointer->previous->next = last_endpoint; it.node_pointer->previous = last_endpoint; - return iterator(last_endpoint++); - } - else - { - group_pointer_type const node_group = groups.get_nearest_freelist_group((it.node_pointer != end_iterator.node_pointer) ? it.node_pointer : end_node.previous); + return iterator( last_endpoint++ ); + } else { + group_pointer_type const node_group = groups.get_nearest_freelist_group( ( + it.node_pointer != end_iterator.node_pointer ) ? it.node_pointer : end_node.previous ); node_pointer_type const selected_node = node_group->free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::forward(parameters)...); + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, + it.node_pointer->previous, std::forward( parameters )... ); node_group->free_list_head = previous; - ++(node_group->number_of_elements); + ++( node_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; --node_allocator_pair.number_of_erased_nodes; it.node_pointer->previous->next = selected_node; it.node_pointer->previous = selected_node; - if (it.node_pointer == begin_iterator.node_pointer) - { + if( it.node_pointer == begin_iterator.node_pointer ) { begin_iterator.node_pointer = selected_node; } - return iterator(selected_node); + return iterator( selected_node ); } - } - else - { - if (groups.block_pointer == NULL) - { - groups.initialize(PLF_LIST_BLOCK_MIN); + } else { + if( groups.block_pointer == NULL ) { + groups.initialize( PLF_LIST_BLOCK_MIN ); } groups.last_endpoint_group->number_of_elements = 1; - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - if PLF_LIST_CONSTEXPR (std::is_nothrow_constructible::value) - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward(parameters)...); - } - else - { - try - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward(parameters)...); - } - catch (...) - { + if PLF_LIST_CONSTEXPR( std::is_nothrow_constructible::value ) { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); + } else { + try { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); + } catch( ... ) { reset(); throw; } @@ -1798,437 +1681,410 @@ template - inline PLF_LIST_FORCE_INLINE reference emplace_back(arguments &&... parameters) - { - return (emplace(end_iterator, std::forward(parameters)...)).node_pointer->element; + inline PLF_LIST_FORCE_INLINE reference emplace_back( arguments &&... parameters ) { + return ( emplace( end_iterator, std::forward( parameters )... ) ).node_pointer->element; } template - inline PLF_LIST_FORCE_INLINE reference emplace_front(arguments &&... parameters) - { - return (emplace(begin_iterator, std::forward(parameters)...)).node_pointer->element; + inline PLF_LIST_FORCE_INLINE reference emplace_front( arguments &&... parameters ) { + return ( emplace( begin_iterator, + std::forward( parameters )... ) ).node_pointer->element; } - #endif - +#endif -private: - void group_fill_position(const element_type &element, group_size_type number_of_elements, node_pointer_type const position) - { - position->previous->next = last_endpoint; - groups.last_endpoint_group->number_of_elements += number_of_elements; - node_pointer_type previous = position->previous; + private: - do - { - if PLF_LIST_CONSTEXPR (std::is_nothrow_copy_constructible::value) - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element); - } - else - { - try - { - PLF_LIST_CONSTRUCT(node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element); - } - catch (...) - { - previous->next = position; - position->previous = --previous; - groups.last_endpoint_group->number_of_elements -= static_cast(number_of_elements - (last_endpoint - position)); - throw; + void group_fill_position( const element_type &element, group_size_type number_of_elements, + node_pointer_type const position ) { + position->previous->next = last_endpoint; + groups.last_endpoint_group->number_of_elements += number_of_elements; + node_pointer_type previous = position->previous; + + do { + if PLF_LIST_CONSTEXPR( std::is_nothrow_copy_constructible::value ) { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, + previous, element ); + } else { + try { + PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, + previous, element ); + } catch( ... ) { + previous->next = position; + position->previous = --previous; + groups.last_endpoint_group->number_of_elements -= static_cast + ( number_of_elements - ( last_endpoint - position ) ); + throw; + } } - } - previous = last_endpoint++; - } while (--number_of_elements != 0); + previous = last_endpoint++; + } while( --number_of_elements != 0 ); - previous->next = position; - position->previous = previous; - } + previous->next = position; + position->previous = previous; + } -public: + public: - // Fill insert + // Fill insert - iterator insert(iterator position, const size_type number_of_elements, const element_type &element) - { - if (number_of_elements == 0) - { - return end_iterator; - } - else if (number_of_elements == 1) - { - return insert(position, element); - } + iterator insert( iterator position, const size_type number_of_elements, + const element_type &element ) { + if( number_of_elements == 0 ) { + return end_iterator; + } else if( number_of_elements == 1 ) { + return insert( position, element ); + } - if (node_pointer_allocator_pair.total_number_of_elements == 0 && last_endpoint != NULL && (static_cast(groups.block_pointer->beyond_end - groups.block_pointer->nodes) < number_of_elements) && (static_cast(groups.block_pointer->beyond_end - groups.block_pointer->nodes) < PLF_LIST_BLOCK_MAX)) - { - reset(); - } + if( node_pointer_allocator_pair.total_number_of_elements == 0 && last_endpoint != NULL && + ( static_cast( groups.block_pointer->beyond_end - groups.block_pointer->nodes ) < + number_of_elements ) && + ( static_cast( groups.block_pointer->beyond_end - groups.block_pointer->nodes ) < + PLF_LIST_BLOCK_MAX ) ) { + reset(); + } - if (groups.block_pointer == NULL) // ie. Uninitialized list - { - if (number_of_elements > PLF_LIST_BLOCK_MAX) - { - size_type multiples = number_of_elements / PLF_LIST_BLOCK_MAX; - const group_size_type remainder = static_cast(number_of_elements - (multiples++ * PLF_LIST_BLOCK_MAX)); // ++ to aid while loop below - - // Create and fill first group: - if (remainder != 0) // make sure smallest block is first - { - if (remainder >= PLF_LIST_BLOCK_MIN) - { - groups.initialize(remainder); - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - group_fill_position(element, remainder, end_iterator.node_pointer); + if( groups.block_pointer == NULL ) { // ie. Uninitialized list + if( number_of_elements > PLF_LIST_BLOCK_MAX ) { + size_type multiples = number_of_elements / PLF_LIST_BLOCK_MAX; + const group_size_type remainder = static_cast( number_of_elements - + ( multiples++ * PLF_LIST_BLOCK_MAX ) ); // ++ to aid while loop below + + // Create and fill first group: + if( remainder != 0 ) { // make sure smallest block is first + if( remainder >= PLF_LIST_BLOCK_MIN ) { + groups.initialize( remainder ); + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; + group_fill_position( element, remainder, end_iterator.node_pointer ); + } else { + // Create first group as BLOCK_MIN size then subtract difference between BLOCK_MIN and remainder from next group: + groups.initialize( PLF_LIST_BLOCK_MIN ); + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; + group_fill_position( element, PLF_LIST_BLOCK_MIN, end_iterator.node_pointer ); + + groups.add_new( PLF_LIST_BLOCK_MAX - ( PLF_LIST_BLOCK_MIN - remainder ) ); + end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position( element, PLF_LIST_BLOCK_MAX - ( PLF_LIST_BLOCK_MIN - remainder ), + end_iterator.node_pointer ); + --multiples; + } + } else { + groups.initialize( PLF_LIST_BLOCK_MAX ); + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; + group_fill_position( element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer ); + --multiples; } - else - { // Create first group as BLOCK_MIN size then subtract difference between BLOCK_MIN and remainder from next group: - groups.initialize(PLF_LIST_BLOCK_MIN); - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - group_fill_position(element, PLF_LIST_BLOCK_MIN, end_iterator.node_pointer); - groups.add_new(PLF_LIST_BLOCK_MAX - (PLF_LIST_BLOCK_MIN - remainder)); + while( --multiples != 0 ) { + groups.add_new( PLF_LIST_BLOCK_MAX ); end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position(element, PLF_LIST_BLOCK_MAX - (PLF_LIST_BLOCK_MIN - remainder), end_iterator.node_pointer); - --multiples; + group_fill_position( element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer ); } - } - else - { - groups.initialize(PLF_LIST_BLOCK_MAX); - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - group_fill_position(element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer); - --multiples; - } - while (--multiples != 0) - { - groups.add_new(PLF_LIST_BLOCK_MAX); - end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position(element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer); + } else { + groups.initialize( ( number_of_elements < PLF_LIST_BLOCK_MIN ) ? PLF_LIST_BLOCK_MIN : + static_cast( number_of_elements ) ); // Construct first group + end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = + groups.last_endpoint_group->nodes; + group_fill_position( element, static_cast( number_of_elements ), + end_iterator.node_pointer ); } - } - else - { - groups.initialize((number_of_elements < PLF_LIST_BLOCK_MIN) ? PLF_LIST_BLOCK_MIN : static_cast(number_of_elements)); // Construct first group - end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - group_fill_position(element, static_cast(number_of_elements), end_iterator.node_pointer); - } - - node_pointer_allocator_pair.total_number_of_elements = number_of_elements; - return begin_iterator; - } - else - { - // Insert first element, then use up any erased nodes: - size_type remainder = number_of_elements - 1; - const iterator return_iterator = insert(position, element); + node_pointer_allocator_pair.total_number_of_elements = number_of_elements; + return begin_iterator; + } else { + // Insert first element, then use up any erased nodes: + size_type remainder = number_of_elements - 1; + const iterator return_iterator = insert( position, element ); - while (node_allocator_pair.number_of_erased_nodes != 0) - { - insert(position, element); - --node_allocator_pair.number_of_erased_nodes; + while( node_allocator_pair.number_of_erased_nodes != 0 ) { + insert( position, element ); + --node_allocator_pair.number_of_erased_nodes; - if (--remainder == 0) - { - return return_iterator; + if( --remainder == 0 ) { + return return_iterator; + } } - } - node_pointer_allocator_pair.total_number_of_elements += remainder; + node_pointer_allocator_pair.total_number_of_elements += remainder; - // then use up remainder of last_endpoint_group: - const group_size_type remaining_nodes_in_group = static_cast(groups.last_endpoint_group->beyond_end - last_endpoint); + // then use up remainder of last_endpoint_group: + const group_size_type remaining_nodes_in_group = static_cast + ( groups.last_endpoint_group->beyond_end - last_endpoint ); - if (remaining_nodes_in_group != 0) - { - if (remaining_nodes_in_group < remainder) - { - group_fill_position(element, remaining_nodes_in_group, position.node_pointer); - remainder -= remaining_nodes_in_group; - } - else - { - group_fill_position(element, static_cast(remainder), position.node_pointer); - return return_iterator; + if( remaining_nodes_in_group != 0 ) { + if( remaining_nodes_in_group < remainder ) { + group_fill_position( element, remaining_nodes_in_group, position.node_pointer ); + remainder -= remaining_nodes_in_group; + } else { + group_fill_position( element, static_cast( remainder ), position.node_pointer ); + return return_iterator; + } } - } - // use up trailing groups: - while ((groups.last_endpoint_group != (groups.block_pointer + groups.size - 1)) & (remainder != 0)) - { - last_endpoint = (++groups.last_endpoint_group)->nodes; - const group_size_type group_size = static_cast(groups.last_endpoint_group->beyond_end - groups.last_endpoint_group->nodes); + // use up trailing groups: + while( ( groups.last_endpoint_group != ( groups.block_pointer + groups.size - 1 ) ) & + ( remainder != 0 ) ) { + last_endpoint = ( ++groups.last_endpoint_group )->nodes; + const group_size_type group_size = static_cast + ( groups.last_endpoint_group->beyond_end - groups.last_endpoint_group->nodes ); - if (group_size < remainder) - { - group_fill_position(element, group_size, position.node_pointer); - remainder -= group_size; + if( group_size < remainder ) { + group_fill_position( element, group_size, position.node_pointer ); + remainder -= group_size; + } else { + group_fill_position( element, static_cast( remainder ), position.node_pointer ); + return return_iterator; + } } - else - { - group_fill_position(element, static_cast(remainder), position.node_pointer); - return return_iterator; + + size_type multiples = remainder / static_cast( PLF_LIST_BLOCK_MAX ); + remainder -= multiples * PLF_LIST_BLOCK_MAX; + + while( multiples-- != 0 ) { + groups.add_new( PLF_LIST_BLOCK_MAX ); + last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position( element, PLF_LIST_BLOCK_MAX, position.node_pointer ); } + + if( remainder != + 0 ) { // Bit annoying to create a large block to house a lower number of elements, but beats the alternatives + groups.add_new( PLF_LIST_BLOCK_MAX ); + last_endpoint = groups.last_endpoint_group->nodes; + group_fill_position( element, static_cast( remainder ), position.node_pointer ); + } + + return return_iterator; } + } + - size_type multiples = remainder / static_cast(PLF_LIST_BLOCK_MAX); - remainder -= multiples * PLF_LIST_BLOCK_MAX; - while (multiples-- != 0) - { - groups.add_new(PLF_LIST_BLOCK_MAX); - last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position(element, PLF_LIST_BLOCK_MAX, position.node_pointer); + // Range insert + + template + iterator insert( const iterator it, + typename plf_enable_if_c < !std::numeric_limits::is_integer, + iterator_type >::type first, const iterator_type last ) { + if( first == last ) { + return end_iterator; } - if (remainder != 0) // Bit annoying to create a large block to house a lower number of elements, but beats the alternatives - { - groups.add_new(PLF_LIST_BLOCK_MAX); - last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position(element, static_cast(remainder), position.node_pointer); + const iterator return_iterator = insert( it, *first ); + + while( ++first != last ) { + insert( it, *first ); } return return_iterator; } - } - // Range insert + // Initializer-list insert - template - iterator insert(const iterator it, typename plf_enable_if_c::is_integer, iterator_type>::type first, const iterator_type last) - { - if (first == last) + inline iterator insert( const iterator it, const std::initializer_list &element_list ) { - return end_iterator; + // use range insert: + return insert( it, element_list.begin(), element_list.end() ); } - const iterator return_iterator = insert(it, *first); - while(++first != last) - { - insert(it, *first); - } - - return return_iterator; - } - - - - // Initializer-list insert + private: - inline iterator insert(const iterator it, const std::initializer_list &element_list) - { // use range insert: - return insert(it, element_list.begin(), element_list.end()); + inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers( group_pointer_type const + group_to_process, const node_pointer_type beyond_end_node ) noexcept { + for( node_pointer_type current_node = group_to_process->nodes; current_node != beyond_end_node; + ++current_node ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, + &( current_node->next ) ); // Destruct element + PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, + &( current_node->previous ) ); // Destruct element + } } -private: - - inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers(group_pointer_type const group_to_process, const node_pointer_type beyond_end_node) noexcept - { - for (node_pointer_type current_node = group_to_process->nodes; current_node != beyond_end_node; ++current_node) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, &(current_node->next)); // Destruct element - PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, &(current_node->previous)); // Destruct element - } - } + public: -public: + // Single erase: + iterator erase( const const_iterator + it ) { // if uninitialized/invalid iterator supplied, function could generate an exception, hence no noexcept + assert( node_pointer_allocator_pair.total_number_of_elements != 0 ); + assert( it.node_pointer != NULL ); + assert( it.node_pointer != end_iterator.node_pointer ); - // Single erase: + if PLF_LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { + PLF_LIST_DESTROY( element_allocator_type, ( *this ), + &( it.node_pointer->element ) ); // Destruct element + } - iterator erase(const const_iterator it) // if uninitialized/invalid iterator supplied, function could generate an exception, hence no noexcept - { - assert(node_pointer_allocator_pair.total_number_of_elements != 0); - assert(it.node_pointer != NULL); - assert(it.node_pointer != end_iterator.node_pointer); + --node_pointer_allocator_pair.total_number_of_elements; + ++node_allocator_pair.number_of_erased_nodes; - if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) - { - PLF_LIST_DESTROY(element_allocator_type, (*this), &(it.node_pointer->element)); // Destruct element - } - --node_pointer_allocator_pair.total_number_of_elements; - ++node_allocator_pair.number_of_erased_nodes; + group_pointer_type node_group = groups.last_searched_group; + // find nearest group with reusable (erased element) memory location: + if( ( it.node_pointer < node_group->nodes ) || ( it.node_pointer >= node_group->beyond_end ) ) { + // Search left and right: + const group_pointer_type beyond_end_group = groups.last_endpoint_group + 1; + group_pointer_type left = node_group - 1; + bool right_not_beyond_back = ( ++node_group < beyond_end_group ); + bool left_not_beyond_front = ( left >= groups.block_pointer ); - group_pointer_type node_group = groups.last_searched_group; + while( true ) { + if( right_not_beyond_back ) { + if( ( it.node_pointer < node_group->beyond_end ) && + ( it.node_pointer >= node_group->nodes ) ) { // usable location found + break; + } - // find nearest group with reusable (erased element) memory location: - if ((it.node_pointer < node_group->nodes) || (it.node_pointer >= node_group->beyond_end)) - { - // Search left and right: - const group_pointer_type beyond_end_group = groups.last_endpoint_group + 1; - group_pointer_type left = node_group - 1; - bool right_not_beyond_back = (++node_group < beyond_end_group); - bool left_not_beyond_front = (left >= groups.block_pointer); - - while (true) - { - if (right_not_beyond_back) - { - if ((it.node_pointer < node_group->beyond_end) && (it.node_pointer >= node_group->nodes)) // usable location found - { - break; + right_not_beyond_back = ( ++node_group < beyond_end_group ); } - right_not_beyond_back = (++node_group < beyond_end_group); - } + if( left_not_beyond_front ) { + if( ( it.node_pointer >= left->nodes ) && + ( it.node_pointer < left->beyond_end ) ) { // usable location found + node_group = left; + break; + } - if (left_not_beyond_front) - { - if ((it.node_pointer >= left->nodes) && (it.node_pointer < left->beyond_end)) // usable location found - { - node_group = left; - break; + left_not_beyond_front = ( --left >= groups.block_pointer ); } - - left_not_beyond_front = (--left >= groups.block_pointer); } + + groups.last_searched_group = node_group; } - groups.last_searched_group = node_group; - } + it.node_pointer->next->previous = it.node_pointer->previous; + it.node_pointer->previous->next = it.node_pointer->next; - it.node_pointer->next->previous = it.node_pointer->previous; - it.node_pointer->previous->next = it.node_pointer->next; + if( it.node_pointer == begin_iterator.node_pointer ) { + begin_iterator.node_pointer = it.node_pointer->next; + } - if (it.node_pointer == begin_iterator.node_pointer) - { - begin_iterator.node_pointer = it.node_pointer->next; - } + const iterator return_iterator( it.node_pointer->next ); - const iterator return_iterator(it.node_pointer->next); + if( --( node_group->number_of_elements ) != + 0 ) { // ie. group is not empty yet, add node to free list + it.node_pointer->next = + NULL; // next == NULL so that destructor can detect the free list item as opposed to non-free-list item + it.node_pointer->previous = node_group->free_list_head; + node_group->free_list_head = it.node_pointer; + return return_iterator; + } else if( node_group != + groups.last_endpoint_group-- ) { // remove group (and decrement active back group) + const group_size_type group_size = static_cast( node_group->beyond_end - + node_group->nodes ); + node_allocator_pair.number_of_erased_nodes -= group_size; - if (--(node_group->number_of_elements) != 0) // ie. group is not empty yet, add node to free list - { - it.node_pointer->next = NULL; // next == NULL so that destructor can detect the free list item as opposed to non-free-list item - it.node_pointer->previous = node_group->free_list_head; - node_group->free_list_head = it.node_pointer; - return return_iterator; - } - else if (node_group != groups.last_endpoint_group--) // remove group (and decrement active back group) - { - const group_size_type group_size = static_cast(node_group->beyond_end - node_group->nodes); - node_allocator_pair.number_of_erased_nodes -= group_size; - - if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) - { - destroy_all_node_pointers(node_group, node_group->beyond_end); - } + if PLF_LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { + destroy_all_node_pointers( node_group, node_group->beyond_end ); + } - node_group->free_list_head = NULL; + node_group->free_list_head = NULL; - if ((group_size == PLF_LIST_BLOCK_MAX) | (node_group >= groups.last_endpoint_group - 1)) // Preserve only last (active) group or second/third-to-last group - seems to be best for performance under high-modification benchmarks - { - groups.move_to_back(node_group); - } - else - { - groups.remove(node_group); - } + if( ( group_size == PLF_LIST_BLOCK_MAX ) | ( node_group >= groups.last_endpoint_group - + 1 ) ) { // Preserve only last (active) group or second/third-to-last group - seems to be best for performance under high-modification benchmarks + groups.move_to_back( node_group ); + } else { + groups.remove( node_group ); + } - return return_iterator; - } - else // clear back group, leave trailing - { - if PLF_LIST_CONSTEXPR (!(std::is_trivially_destructible::value)) - { - destroy_all_node_pointers(node_group, last_endpoint); - } + return return_iterator; + } else { // clear back group, leave trailing + if PLF_LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { + destroy_all_node_pointers( node_group, last_endpoint ); + } - node_group->free_list_head = NULL; + node_group->free_list_head = NULL; - if (node_pointer_allocator_pair.total_number_of_elements != 0) - { - node_allocator_pair.number_of_erased_nodes -= static_cast(last_endpoint - node_group->nodes); - last_endpoint = groups.last_endpoint_group->beyond_end; - } - else - { - groups.last_endpoint_group = groups.block_pointer; // If number of elements is zero, it indicates that this was the first group in the vector. In which case the last_endpoint_group would be invalid at this point due to the decrement in the above else-if statement. So it needs to be reset, as it will not be reset in the function call below. - clear(); - } + if( node_pointer_allocator_pair.total_number_of_elements != 0 ) { + node_allocator_pair.number_of_erased_nodes -= static_cast + ( last_endpoint - node_group->nodes ); + last_endpoint = groups.last_endpoint_group->beyond_end; + } else { + groups.last_endpoint_group = + groups.block_pointer; // If number of elements is zero, it indicates that this was the first group in the vector. In which case the last_endpoint_group would be invalid at this point due to the decrement in the above else-if statement. So it needs to be reset, as it will not be reset in the function call below. + clear(); + } - return return_iterator; + return return_iterator; + } } - } - // Range-erase: + // Range-erase: - inline void erase(const const_iterator iterator1, const const_iterator iterator2) // if uninitialized/invalid iterator supplied, function could generate an exception - { - for (const_iterator current = iterator1; current != iterator2;) - { - current = erase(current); + inline void erase( const const_iterator iterator1, + const const_iterator + iterator2 ) { // if uninitialized/invalid iterator supplied, function could generate an exception + for( const_iterator current = iterator1; current != iterator2; ) { + current = erase( current ); + } } - } - inline void pop_back() // Exception will occur on empty list - { - erase(iterator(end_node.previous)); - } + inline void pop_back() { // Exception will occur on empty list + erase( iterator( end_node.previous ) ); + } - inline void pop_front() // Exception will occur on empty list - { - erase(begin_iterator); - } + inline void pop_front() { // Exception will occur on empty list + erase( begin_iterator ); + } - inline list & operator = (const list &source) - { - assert (&source != this); + inline list &operator = ( const list &source ) { + assert( &source != this ); - clear(); - reserve(source.node_pointer_allocator_pair.total_number_of_elements); - insert(end_iterator, source.begin_iterator, source.end_iterator); + clear(); + reserve( source.node_pointer_allocator_pair.total_number_of_elements ); + insert( end_iterator, source.begin_iterator, source.end_iterator ); - return *this; - } + return *this; + } // Move assignment - list & operator = (list &&source) PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(allocator_type) - { - assert (&source != this); + list &operator = ( list &&source ) PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT( allocator_type ) { + assert( &source != this ); // Move source values across: - groups.destroy_all_data(last_endpoint); - - groups = std::move(source.groups); - end_node = std::move(source.end_node); - last_endpoint = std::move(source.last_endpoint); - begin_iterator.node_pointer = (source.begin_iterator.node_pointer == source.end_iterator.node_pointer) ? end_iterator.node_pointer : std::move(source.begin_iterator.node_pointer); - node_pointer_allocator_pair.total_number_of_elements = source.node_pointer_allocator_pair.total_number_of_elements; + groups.destroy_all_data( last_endpoint ); + + groups = std::move( source.groups ); + end_node = std::move( source.end_node ); + last_endpoint = std::move( source.last_endpoint ); + begin_iterator.node_pointer = ( source.begin_iterator.node_pointer == + source.end_iterator.node_pointer ) ? end_iterator.node_pointer : std::move( + source.begin_iterator.node_pointer ); + node_pointer_allocator_pair.total_number_of_elements = + source.node_pointer_allocator_pair.total_number_of_elements; node_allocator_pair.number_of_erased_nodes = source.node_allocator_pair.number_of_erased_nodes; end_node.previous->next = begin_iterator.node_pointer->previous = end_iterator.node_pointer; @@ -2240,770 +2096,687 @@ template ::max_size( *this ); + } - inline size_type max_size() const noexcept - { - return std::allocator_traits::max_size(*this); - } + inline size_type capacity() const noexcept { + return groups.element_allocator_pair.capacity; + } - inline size_type capacity() const noexcept - { - return groups.element_allocator_pair.capacity; - } + inline size_type approximate_memory_use() const noexcept { + return static_cast( sizeof( *this ) + ( groups.element_allocator_pair.capacity * sizeof( + node ) ) + ( sizeof( group ) * groups.group_allocator_pair.capacity ) ); + } - inline size_type approximate_memory_use() const noexcept - { - return static_cast(sizeof(*this) + (groups.element_allocator_pair.capacity * sizeof(node)) + (sizeof(group) * groups.group_allocator_pair.capacity)); - } + private: -private: + struct less { + inline bool operator()( const element_type &a, const element_type &b ) const noexcept { + return a < b; + } + }; - struct less - { - inline bool operator() (const element_type &a, const element_type &b) const noexcept - { - return a < b; - } - }; + // Function-object to redirect the sort function to sort pointers by the elements they point to, not the pointer value + template + struct sort_dereferencer { + comparison_function stored_instance; - // Function-object to redirect the sort function to sort pointers by the elements they point to, not the pointer value - template - struct sort_dereferencer - { - comparison_function stored_instance; + explicit sort_dereferencer( const comparison_function &function_instance ): + stored_instance( function_instance ) + {} - explicit sort_dereferencer(const comparison_function &function_instance): - stored_instance(function_instance) - {} + sort_dereferencer() noexcept + {} - sort_dereferencer() noexcept - {} + inline bool operator()( const node_pointer_type first, const node_pointer_type second ) { + return stored_instance( first->element, second->element ); + } + }; - inline bool operator() (const node_pointer_type first, const node_pointer_type second) - { - return stored_instance(first->element, second->element); - } - }; + public: -public: + template + void sort( comparison_function compare ) { + if( node_pointer_allocator_pair.total_number_of_elements < 2 ) { + return; + } - template - void sort(comparison_function compare) - { - if (node_pointer_allocator_pair.total_number_of_elements < 2) - { - return; - } + node_pointer_type *const node_pointers = PLF_LIST_ALLOCATE( node_pointer_allocator_type, + node_pointer_allocator_pair, node_pointer_allocator_pair.total_number_of_elements, NULL ); + node_pointer_type *node_pointer = node_pointers; - node_pointer_type * const node_pointers = PLF_LIST_ALLOCATE(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer_allocator_pair.total_number_of_elements, NULL); - node_pointer_type *node_pointer = node_pointers; + // According to the C++ standard, construction of a pointer (of any type) may not trigger an exception - hence, no try-catch blocks are necessary for constructing the pointers: + for( group_pointer_type current_group = groups.block_pointer; + current_group != groups.last_endpoint_group; ++current_group ) { + const node_pointer_type end = current_group->beyond_end; - // According to the C++ standard, construction of a pointer (of any type) may not trigger an exception - hence, no try-catch blocks are necessary for constructing the pointers: - for (group_pointer_type current_group = groups.block_pointer; current_group != groups.last_endpoint_group; ++current_group) - { - const node_pointer_type end = current_group->beyond_end; - - if ((end - current_group->nodes) != current_group->number_of_elements) // If there are erased nodes present in the group - { - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - if (current_node->next != NULL) // is not free list node - { - PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); + if( ( end - current_group->nodes ) != + current_group->number_of_elements ) { // If there are erased nodes present in the group + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + if( current_node->next != NULL ) { // is not free list node + PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + current_node ); + } + } + } else { + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + current_node ); } } } - else - { - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); - } - } - } - if ((last_endpoint - groups.last_endpoint_group->nodes) != groups.last_endpoint_group->number_of_elements) // If there are erased nodes present in the group - { - for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) - { - if (current_node->next != NULL) - { - PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); + if( ( last_endpoint - groups.last_endpoint_group->nodes ) != + groups.last_endpoint_group->number_of_elements ) { // If there are erased nodes present in the group + for( node_pointer_type current_node = groups.last_endpoint_group->nodes; + current_node != last_endpoint; ++current_node ) { + if( current_node->next != NULL ) { + PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + current_node ); + } + } + } else { + for( node_pointer_type current_node = groups.last_endpoint_group->nodes; + current_node != last_endpoint; ++current_node ) { + PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + current_node ); } } - } - else - { - for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) - { - PLF_LIST_CONSTRUCT(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node); - } - } - #ifdef GFX_TIMSORT_HPP - gfx::timsort(node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, sort_dereferencer(compare)); - #else - std::sort(node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, sort_dereferencer(compare)); - #endif +#ifdef GFX_TIMSORT_HPP + gfx::timsort( node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, + sort_dereferencer( compare ) ); +#else + std::sort( node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, + sort_dereferencer( compare ) ); +#endif - begin_iterator.node_pointer = node_pointers[0]; - begin_iterator.node_pointer->next = node_pointers[1]; - begin_iterator.node_pointer->previous = end_iterator.node_pointer; + begin_iterator.node_pointer = node_pointers[0]; + begin_iterator.node_pointer->next = node_pointers[1]; + begin_iterator.node_pointer->previous = end_iterator.node_pointer; - end_node.next = node_pointers[0]; - end_node.previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 1]; - end_node.previous->next = end_iterator.node_pointer; - end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 2]; + end_node.next = node_pointers[0]; + end_node.previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 1]; + end_node.previous->next = end_iterator.node_pointer; + end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - + 2]; - node_pointer_type * const back = node_pointers + node_pointer_allocator_pair.total_number_of_elements - 1; + node_pointer_type *const back = node_pointers + node_pointer_allocator_pair.total_number_of_elements + - 1; - for(node_pointer = node_pointers + 1; node_pointer != back; ++node_pointer) - { - (*node_pointer)->next = *(node_pointer + 1); - (*node_pointer)->previous = *(node_pointer - 1); + for( node_pointer = node_pointers + 1; node_pointer != back; ++node_pointer ) { + ( *node_pointer )->next = *( node_pointer + 1 ); + ( *node_pointer )->previous = *( node_pointer - 1 ); - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer - 1); + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer - 1 ); + } } - } - if PLF_LIST_CONSTEXPR (!std::is_trivially_destructible::value) - { - PLF_LIST_DESTROY(node_pointer_allocator_type, node_pointer_allocator_pair, back); - } + if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, back ); + } - PLF_LIST_DEALLOCATE(node_pointer_allocator_type, node_pointer_allocator_pair, node_pointers, node_pointer_allocator_pair.total_number_of_elements); - } + PLF_LIST_DEALLOCATE( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointers, + node_pointer_allocator_pair.total_number_of_elements ); + } - inline void sort() - { - sort(less()); - } + inline void sort() { + sort( less() ); + } - void reorder(const iterator position, const iterator first, const iterator last) noexcept - { - last.node_pointer->next->previous = first.node_pointer->previous; - first.node_pointer->previous->next = last.node_pointer->next; + void reorder( const iterator position, const iterator first, const iterator last ) noexcept { + last.node_pointer->next->previous = first.node_pointer->previous; + first.node_pointer->previous->next = last.node_pointer->next; - last.node_pointer->next = position.node_pointer; - first.node_pointer->previous = position.node_pointer->previous; + last.node_pointer->next = position.node_pointer; + first.node_pointer->previous = position.node_pointer->previous; - position.node_pointer->previous->next = first.node_pointer; - position.node_pointer->previous = last.node_pointer; + position.node_pointer->previous->next = first.node_pointer; + position.node_pointer->previous = last.node_pointer; - if (begin_iterator == position) - { - begin_iterator = first; + if( begin_iterator == position ) { + begin_iterator = first; + } } - } - inline void reorder(const iterator position, const iterator location) noexcept - { - reorder(position, location, location); - } + inline void reorder( const iterator position, const iterator location ) noexcept { + reorder( position, location, location ); + } - void reserve(size_type reserve_amount) - { - if (reserve_amount == 0 || reserve_amount <= groups.element_allocator_pair.capacity) - { - return; - } - else if (reserve_amount < PLF_LIST_BLOCK_MIN) - { - reserve_amount = PLF_LIST_BLOCK_MIN; - } - else if (reserve_amount > max_size()) - { - reserve_amount = max_size(); - } + void reserve( size_type reserve_amount ) { + if( reserve_amount == 0 || reserve_amount <= groups.element_allocator_pair.capacity ) { + return; + } else if( reserve_amount < PLF_LIST_BLOCK_MIN ) { + reserve_amount = PLF_LIST_BLOCK_MIN; + } else if( reserve_amount > max_size() ) { + reserve_amount = max_size(); + } - if (groups.block_pointer != NULL && node_pointer_allocator_pair.total_number_of_elements == 0) - { // edge case: has been filled with elements then clear()'d - some groups may be smaller than would be desired, should be replaced - group_size_type end_group_size = static_cast((groups.block_pointer + groups.size - 1)->beyond_end - (groups.block_pointer + groups.size - 1)->nodes); + if( groups.block_pointer != NULL && node_pointer_allocator_pair.total_number_of_elements == 0 ) { + // edge case: has been filled with elements then clear()'d - some groups may be smaller than would be desired, should be replaced + group_size_type end_group_size = static_cast( ( groups.block_pointer + groups.size + - 1 )->beyond_end - ( groups.block_pointer + groups.size - 1 )->nodes ); - if (reserve_amount > end_group_size && end_group_size != PLF_LIST_BLOCK_MAX) // if last group isn't large enough, remove all groups - { - reset(); - } - else - { - size_type number_of_full_groups_needed = reserve_amount / PLF_LIST_BLOCK_MAX; - group_size_type remainder = static_cast(reserve_amount - (number_of_full_groups_needed * PLF_LIST_BLOCK_MAX)); - - // Remove any max_size groups which're not needed and any groups that're smaller than remainder: - for (group_pointer_type current_group = groups.block_pointer; current_group < groups.block_pointer + groups.size;) - { - const group_size_type current_group_size = static_cast(groups.block_pointer->beyond_end - groups.block_pointer->nodes); - - if (number_of_full_groups_needed != 0 && current_group_size == PLF_LIST_BLOCK_MAX) - { - --number_of_full_groups_needed; - ++current_group; - } - else if (remainder != 0 && current_group_size >= remainder) - { - remainder = 0; - ++current_group; - } - else - { - groups.remove(current_group); + if( reserve_amount > end_group_size && + end_group_size != PLF_LIST_BLOCK_MAX ) { // if last group isn't large enough, remove all groups + reset(); + } else { + size_type number_of_full_groups_needed = reserve_amount / PLF_LIST_BLOCK_MAX; + group_size_type remainder = static_cast( reserve_amount - + ( number_of_full_groups_needed * PLF_LIST_BLOCK_MAX ) ); + + // Remove any max_size groups which're not needed and any groups that're smaller than remainder: + for( group_pointer_type current_group = groups.block_pointer; + current_group < groups.block_pointer + groups.size; ) { + const group_size_type current_group_size = static_cast + ( groups.block_pointer->beyond_end - groups.block_pointer->nodes ); + + if( number_of_full_groups_needed != 0 && current_group_size == PLF_LIST_BLOCK_MAX ) { + --number_of_full_groups_needed; + ++current_group; + } else if( remainder != 0 && current_group_size >= remainder ) { + remainder = 0; + ++current_group; + } else { + groups.remove( current_group ); + } } - } - last_endpoint = groups.block_pointer->nodes; + last_endpoint = groups.block_pointer->nodes; + } } - } - reserve_amount -= groups.element_allocator_pair.capacity; + reserve_amount -= groups.element_allocator_pair.capacity; - // To correct from possible reallocation caused by add_new: - const difference_type last_endpoint_group_number = groups.last_endpoint_group - groups.block_pointer; + // To correct from possible reallocation caused by add_new: + const difference_type last_endpoint_group_number = groups.last_endpoint_group - + groups.block_pointer; - size_type number_of_full_groups = (reserve_amount / PLF_LIST_BLOCK_MAX); - reserve_amount -= (number_of_full_groups++ * PLF_LIST_BLOCK_MAX); // ++ to aid while loop below + size_type number_of_full_groups = ( reserve_amount / PLF_LIST_BLOCK_MAX ); + reserve_amount -= ( number_of_full_groups++ * PLF_LIST_BLOCK_MAX ); // ++ to aid while loop below - if (groups.block_pointer == NULL) // Previously uninitialized list or reset in above if statement; most common scenario - { - if (reserve_amount != 0) - { - groups.initialize(static_cast(((reserve_amount < PLF_LIST_BLOCK_MIN) ? PLF_LIST_BLOCK_MIN : reserve_amount))); + if( groups.block_pointer == + NULL ) { // Previously uninitialized list or reset in above if statement; most common scenario + if( reserve_amount != 0 ) { + groups.initialize( static_cast( ( ( reserve_amount < PLF_LIST_BLOCK_MIN ) ? + PLF_LIST_BLOCK_MIN : reserve_amount ) ) ); + } else { + groups.initialize( PLF_LIST_BLOCK_MAX ); + --number_of_full_groups; + } + } else if( reserve_amount != 0 ) { + // Create a group at least as large as the last group - may allocate more than necessary, but better solution than creating a veyr small group in the middle of the group vector, I think: + const group_size_type last_endpoint_group_capacity = static_cast + ( groups.last_endpoint_group->beyond_end - groups.last_endpoint_group->nodes ); + groups.add_new( static_cast( ( reserve_amount < last_endpoint_group_capacity ) ? + last_endpoint_group_capacity : reserve_amount ) ); } - else - { - groups.initialize(PLF_LIST_BLOCK_MAX); - --number_of_full_groups; + + while( --number_of_full_groups != 0 ) { + groups.add_new( PLF_LIST_BLOCK_MAX ); } - } - else if (reserve_amount != 0) - { // Create a group at least as large as the last group - may allocate more than necessary, but better solution than creating a veyr small group in the middle of the group vector, I think: - const group_size_type last_endpoint_group_capacity = static_cast(groups.last_endpoint_group->beyond_end - groups.last_endpoint_group->nodes); - groups.add_new(static_cast((reserve_amount < last_endpoint_group_capacity) ? last_endpoint_group_capacity : reserve_amount)); - } - while (--number_of_full_groups != 0) - { - groups.add_new(PLF_LIST_BLOCK_MAX); + groups.last_endpoint_group = groups.block_pointer + last_endpoint_group_number; } - groups.last_endpoint_group = groups.block_pointer + last_endpoint_group_number; - } - - inline PLF_LIST_FORCE_INLINE void free_unused_memory() noexcept - { - groups.trim_trailing_groups(); - } + inline PLF_LIST_FORCE_INLINE void free_unused_memory() noexcept { + groups.trim_trailing_groups(); + } - void shrink_to_fit() - { - if ((last_endpoint == NULL) | (node_pointer_allocator_pair.total_number_of_elements == groups.element_allocator_pair.capacity)) // uninitialized list or full - { - return; - } - else if (node_pointer_allocator_pair.total_number_of_elements == 0) // Edge case - { - reset(); - return; - } - else if (node_allocator_pair.number_of_erased_nodes == 0 && last_endpoint == groups.last_endpoint_group->beyond_end) //edge case - currently no waste except for possible trailing groups - { - groups.trim_trailing_groups(); - return; - } + void shrink_to_fit() { + if( ( last_endpoint == NULL ) | ( node_pointer_allocator_pair.total_number_of_elements == + groups.element_allocator_pair.capacity ) ) { // uninitialized list or full + return; + } else if( node_pointer_allocator_pair.total_number_of_elements == 0 ) { // Edge case + reset(); + return; + } else if( node_allocator_pair.number_of_erased_nodes == 0 && + last_endpoint == + groups.last_endpoint_group->beyond_end ) { //edge case - currently no waste except for possible trailing groups + groups.trim_trailing_groups(); + return; + } list temp; - temp.reserve(node_pointer_allocator_pair.total_number_of_elements); + temp.reserve( node_pointer_allocator_pair.total_number_of_elements ); - if PLF_LIST_CONSTEXPR (std::is_move_assignable::value && std::is_move_constructible::value) // move elements if possible, otherwise copy them - { - temp.insert(temp.end_iterator, std::make_move_iterator(begin_iterator), std::make_move_iterator(end_iterator)); - } - else - { - temp.insert(temp.end_iterator, begin_iterator, end_iterator); + if PLF_LIST_CONSTEXPR( std::is_move_assignable::value && + std::is_move_constructible::value ) { // move elements if possible, otherwise copy them + temp.insert( temp.end_iterator, std::make_move_iterator( begin_iterator ), + std::make_move_iterator( end_iterator ) ); + } else { + temp.insert( temp.end_iterator, begin_iterator, end_iterator ); } - *this = std::move(temp); + *this = std::move( temp ); + + } - } + private: -private: + void append_process( list &source ) { // used by merge and splice + if( last_endpoint != groups.last_endpoint_group->beyond_end ) { + // Add unused nodes to group's free list + const node_pointer_type back_node = last_endpoint - 1; + for( node_pointer_type current_node = groups.last_endpoint_group->beyond_end - 1; + current_node != back_node; --current_node ) { + current_node->next = NULL; + current_node->previous = groups.last_endpoint_group->free_list_head; + groups.last_endpoint_group->free_list_head = current_node; + } - void append_process(list &source) // used by merge and splice - { - if (last_endpoint != groups.last_endpoint_group->beyond_end) - { // Add unused nodes to group's free list - const node_pointer_type back_node = last_endpoint - 1; - for (node_pointer_type current_node = groups.last_endpoint_group->beyond_end - 1; current_node != back_node; --current_node) - { - current_node->next = NULL; - current_node->previous = groups.last_endpoint_group->free_list_head; - groups.last_endpoint_group->free_list_head = current_node; + node_allocator_pair.number_of_erased_nodes += static_cast + ( groups.last_endpoint_group->beyond_end - last_endpoint ); } - node_allocator_pair.number_of_erased_nodes += static_cast(groups.last_endpoint_group->beyond_end - last_endpoint); + groups.append( source.groups ); + last_endpoint = source.last_endpoint; + node_pointer_allocator_pair.total_number_of_elements += + source.node_pointer_allocator_pair.total_number_of_elements; + source.reset(); } - groups.append(source.groups); - last_endpoint = source.last_endpoint; - node_pointer_allocator_pair.total_number_of_elements += source.node_pointer_allocator_pair.total_number_of_elements; - source.reset(); - } + public: -public: + void splice( iterator position, list &source ) { + assert( &source != this ); - void splice(iterator position, list &source) - { - assert(&source != this); + if( source.node_pointer_allocator_pair.total_number_of_elements == 0 ) { + return; + } else if( node_pointer_allocator_pair.total_number_of_elements == 0 ) { + *this = std::move( source ); + return; + } - if (source.node_pointer_allocator_pair.total_number_of_elements == 0) - { - return; - } - else if (node_pointer_allocator_pair.total_number_of_elements == 0) - { - *this = std::move(source); - return; - } + if( position.node_pointer == + begin_iterator.node_pointer ) { // put source groups at front rather than back + swap( source ); + position.node_pointer = end_iterator.node_pointer; + } - if (position.node_pointer == begin_iterator.node_pointer) // put source groups at front rather than back - { - swap(source); - position.node_pointer = end_iterator.node_pointer; + position.node_pointer->previous->next = source.begin_iterator.node_pointer; + source.begin_iterator.node_pointer->previous = position.node_pointer->previous; + position.node_pointer->previous = source.end_node.previous; + source.end_node.previous->next = position.node_pointer; + + append_process( source ); } - position.node_pointer->previous->next = source.begin_iterator.node_pointer; - source.begin_iterator.node_pointer->previous = position.node_pointer->previous; - position.node_pointer->previous = source.end_node.previous; - source.end_node.previous->next = position.node_pointer; - append_process(source); - } + template + void merge( list &source, comparison_function compare ) { + assert( &source != this ); + splice( ( source.node_pointer_allocator_pair.total_number_of_elements >= + node_pointer_allocator_pair.total_number_of_elements ) ? end_iterator : begin_iterator, source ); + sort( compare ); + } - template - void merge(list &source, comparison_function compare) - { - assert(&source != this); - splice((source.node_pointer_allocator_pair.total_number_of_elements >= node_pointer_allocator_pair.total_number_of_elements) ? end_iterator : begin_iterator, source); - sort(compare); - } + void merge( list &source ) { + assert( &source != this ); + if( source.node_pointer_allocator_pair.total_number_of_elements == 0 ) { + return; + } else if( node_pointer_allocator_pair.total_number_of_elements == 0 ) { + *this = std::move( source ); + return; + } - void merge(list &source) - { - assert(&source != this); + node_pointer_type current1 = begin_iterator.node_pointer->next, + current2 = source.begin_iterator.node_pointer->next; + node_pointer_type previous = source.begin_iterator.node_pointer; + const node_pointer_type source_end = source.end_iterator.node_pointer, + this_end = end_iterator.node_pointer; - if (source.node_pointer_allocator_pair.total_number_of_elements == 0) - { - return; - } - else if (node_pointer_allocator_pair.total_number_of_elements == 0) - { - *this = std::move(source); - return; - } + begin_iterator.node_pointer->next = source.begin_iterator.node_pointer; + source.begin_iterator.node_pointer->previous = begin_iterator.node_pointer; - node_pointer_type current1 = begin_iterator.node_pointer->next, current2 = source.begin_iterator.node_pointer->next; - node_pointer_type previous = source.begin_iterator.node_pointer; - const node_pointer_type source_end = source.end_iterator.node_pointer, this_end = end_iterator.node_pointer; - begin_iterator.node_pointer->next = source.begin_iterator.node_pointer; - source.begin_iterator.node_pointer->previous = begin_iterator.node_pointer; + while( ( current1 != this_end ) & ( current2 != source_end ) ) { + previous->next = current1; + current1->previous = previous; + previous = current1; + current1 = current1->next; + previous->next = current2; + current2->previous = previous; + previous = current2; + current2 = current2->next; + } - while ((current1 != this_end) & (current2 != source_end)) - { - previous->next = current1; - current1->previous = previous; - previous = current1; - current1 = current1->next; - - previous->next = current2; - current2->previous = previous; - previous = current2; - current2 = current2->next; - } + if( current1 != this_end ) { + previous->next = current1; + current1->previous = previous; + } else { + end_node.previous = source.end_node.previous; + source.end_node.previous->next = end_iterator.node_pointer; + } - if (current1 != this_end) - { - previous->next = current1; - current1->previous = previous; - } - else - { - end_node.previous = source.end_node.previous; - source.end_node.previous->next = end_iterator.node_pointer; + append_process( source ); } - append_process(source); - } + void reverse() noexcept { + if( node_pointer_allocator_pair.total_number_of_elements > 1 ) { + for( group_pointer_type current_group = groups.block_pointer; + current_group != groups.last_endpoint_group; ++current_group ) { + const node_pointer_type end = current_group->beyond_end; - void reverse() noexcept - { - if (node_pointer_allocator_pair.total_number_of_elements > 1) - { - for (group_pointer_type current_group = groups.block_pointer; current_group != groups.last_endpoint_group; ++current_group) - { - const node_pointer_type end = current_group->beyond_end; + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + if( current_node->next != NULL ) { // is not free list node + // swap the pointers: + const node_pointer_type temp = current_node->next; + current_node->next = current_node->previous; + current_node->previous = temp; + } + } + } - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - if (current_node->next != NULL) // is not free list node - { // swap the pointers: + for( node_pointer_type current_node = groups.last_endpoint_group->nodes; + current_node != last_endpoint; ++current_node ) { + if( current_node->next != NULL ) { const node_pointer_type temp = current_node->next; current_node->next = current_node->previous; current_node->previous = temp; } } - } - - for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) - { - if (current_node->next != NULL) - { - const node_pointer_type temp = current_node->next; - current_node->next = current_node->previous; - current_node->previous = temp; - } - } - const node_pointer_type temp = end_node.previous; - end_node.previous = begin_iterator.node_pointer; - begin_iterator.node_pointer = temp; + const node_pointer_type temp = end_node.previous; + end_node.previous = begin_iterator.node_pointer; + begin_iterator.node_pointer = temp; - end_node.previous->next = end_iterator.node_pointer; - begin_iterator.node_pointer->previous = end_iterator.node_pointer; + end_node.previous->next = end_iterator.node_pointer; + begin_iterator.node_pointer->previous = end_iterator.node_pointer; + } } - } -private: + private: - // Used by unique() - struct eq - { - inline bool operator() (const element_type &a, const element_type &b) const noexcept - { - return a == b; - } - }; + // Used by unique() + struct eq { + inline bool operator()( const element_type &a, const element_type &b ) const noexcept { + return a == b; + } + }; - // Used by remove() - struct eq_to - { - const element_type value; + // Used by remove() + struct eq_to { + const element_type value; - explicit eq_to(const element_type store_value): - value(store_value) - {} + explicit eq_to( const element_type store_value ): + value( store_value ) + {} - eq_to() noexcept - {} + eq_to() noexcept + {} - inline bool operator() (const element_type compare_value) const noexcept - { - return value == compare_value; - } - }; + inline bool operator()( const element_type compare_value ) const noexcept { + return value == compare_value; + } + }; -public: + public: - template - size_type unique(comparison_function compare) - { - const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; + template + size_type unique( comparison_function compare ) { + const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; - if (original_number_of_elements > 1) - { - element_type *previous = &(begin_iterator.node_pointer->element); + if( original_number_of_elements > 1 ) { + element_type *previous = &( begin_iterator.node_pointer->element ); - for (iterator current = ++iterator(begin_iterator); current != end_iterator;) - { - if (compare(*current, *previous)) - { - current = erase(current); - } - else - { - previous = &(current++.node_pointer->element); + for( iterator current = ++iterator( begin_iterator ); current != end_iterator; ) { + if( compare( *current, *previous ) ) { + current = erase( current ); + } else { + previous = &( current++.node_pointer->element ); + } } } + + return original_number_of_elements - node_pointer_allocator_pair.total_number_of_elements; } - return original_number_of_elements - node_pointer_allocator_pair.total_number_of_elements; - } + inline size_type unique() { + return unique( eq() ); + } - inline size_type unique() - { - return unique(eq()); - } + template + size_type remove_if( predicate_function predicate ) { + const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; - template - size_type remove_if(predicate_function predicate) - { - const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; + if( original_number_of_elements != 0 ) { + for( group_pointer_type current_group = groups.block_pointer; + current_group != groups.last_endpoint_group; ++current_group ) { + group_size_type num_elements = current_group->number_of_elements; + const node_pointer_type end = current_group->beyond_end; - if (original_number_of_elements != 0) - { - for (group_pointer_type current_group = groups.block_pointer; current_group != groups.last_endpoint_group; ++current_group) - { - group_size_type num_elements = current_group->number_of_elements; - const node_pointer_type end = current_group->beyond_end; + if( end - current_group->nodes != num_elements ) { // If there are erased nodes present in the group + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + if( current_node->next != NULL && + predicate( current_node->element ) ) { // is not free list node and validates predicate + erase( current_node ); - if (end - current_group->nodes != num_elements) // If there are erased nodes present in the group - { - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - if (current_node->next != NULL && predicate(current_node->element)) // is not free list node and validates predicate - { - erase(current_node); - - if (--num_elements == 0) // ie. group will be empty (and removed) now - nothing left to iterate over - { - --current_group; // As current group has been removed, subsequent groups have already shifted back by one, hence, the ++ to the current group in the for loop is unnecessary, and negated here - break; + if( --num_elements == + 0 ) { // ie. group will be empty (and removed) now - nothing left to iterate over + --current_group; // As current group has been removed, subsequent groups have already shifted back by one, hence, the ++ to the current group in the for loop is unnecessary, and negated here + break; + } } } - } - } - else // No erased nodes in group - { - for (node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node) - { - if (predicate(current_node->element)) - { - erase(current_node); - - if (--num_elements == 0) - { - --current_group; - break; + } else { // No erased nodes in group + for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { + if( predicate( current_node->element ) ) { + erase( current_node ); + + if( --num_elements == 0 ) { + --current_group; + break; + } } } } } - } - group_size_type num_elements = groups.last_endpoint_group->number_of_elements; + group_size_type num_elements = groups.last_endpoint_group->number_of_elements; - if (last_endpoint - groups.last_endpoint_group->nodes != num_elements) // If there are erased nodes present in the group - { - for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) - { - if (current_node->next != NULL && predicate(current_node->element)) - { - erase(current_node); + if( last_endpoint - groups.last_endpoint_group->nodes != + num_elements ) { // If there are erased nodes present in the group + for( node_pointer_type current_node = groups.last_endpoint_group->nodes; + current_node != last_endpoint; ++current_node ) { + if( current_node->next != NULL && predicate( current_node->element ) ) { + erase( current_node ); - if (--num_elements == 0) - { - break; + if( --num_elements == 0 ) { + break; + } } } - } - } - else - { - for (node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node) - { - if (predicate(current_node->element)) - { - erase(current_node); - - if (--num_elements == 0) - { - break; + } else { + for( node_pointer_type current_node = groups.last_endpoint_group->nodes; + current_node != last_endpoint; ++current_node ) { + if( predicate( current_node->element ) ) { + erase( current_node ); + + if( --num_elements == 0 ) { + break; + } } } } } - } - return original_number_of_elements - node_pointer_allocator_pair.total_number_of_elements; - } + return original_number_of_elements - node_pointer_allocator_pair.total_number_of_elements; + } - inline size_type remove(const element_type &value) - { - return remove_if(eq_to(value)); - } + inline size_type remove( const element_type &value ) { + return remove_if( eq_to( value ) ); + } - void resize(const size_type number_of_elements, const element_type &value = element_type()) - { - if (node_pointer_allocator_pair.total_number_of_elements == number_of_elements) - { - return; - } - else if (number_of_elements == 0) - { - clear(); - return; - } - else if (node_pointer_allocator_pair.total_number_of_elements < number_of_elements) - { - insert(end_iterator, number_of_elements - node_pointer_allocator_pair.total_number_of_elements, value); - } - else // ie. node_pointer_allocator_pair.total_number_of_elements > number_of_elements - { - iterator current(end_node.previous); - - for (size_type number_to_remove = node_pointer_allocator_pair.total_number_of_elements - number_of_elements; number_to_remove != 0; --number_to_remove) - { - const node_pointer_type temp = current.node_pointer->previous; - erase(current); - current.node_pointer = temp; + void resize( const size_type number_of_elements, const element_type &value = element_type() ) { + if( node_pointer_allocator_pair.total_number_of_elements == number_of_elements ) { + return; + } else if( number_of_elements == 0 ) { + clear(); + return; + } else if( node_pointer_allocator_pair.total_number_of_elements < number_of_elements ) { + insert( end_iterator, number_of_elements - node_pointer_allocator_pair.total_number_of_elements, + value ); + } else { // ie. node_pointer_allocator_pair.total_number_of_elements > number_of_elements + iterator current( end_node.previous ); + + for( size_type number_to_remove = node_pointer_allocator_pair.total_number_of_elements - + number_of_elements; number_to_remove != 0; --number_to_remove ) { + const node_pointer_type temp = current.node_pointer->previous; + erase( current ); + current.node_pointer = temp; + } } } - } - // Range assign: - template - inline void assign(const typename plf_enable_if_c::is_integer, iterator_type>::type first, const iterator_type last) - { - clear(); - insert(end_iterator, first, last); - groups.trim_trailing_groups(); - } + // Range assign: + template + inline void assign( const typename plf_enable_if_c < + !std::numeric_limits::is_integer, iterator_type >::type first, + const iterator_type last ) { + clear(); + insert( end_iterator, first, last ); + groups.trim_trailing_groups(); + } - // Fill assign: - inline void assign(const size_type number_of_elements, const element_type &value) - { - clear(); - reserve(number_of_elements); // Will return anyway if capacity already > number_of_elements - insert(end_iterator, number_of_elements, value); - } + // Fill assign: + inline void assign( const size_type number_of_elements, const element_type &value ) { + clear(); + reserve( number_of_elements ); // Will return anyway if capacity already > number_of_elements + insert( end_iterator, number_of_elements, value ); + } // Initializer-list assign: - inline void assign(const std::initializer_list &element_list) - { + inline void assign( const std::initializer_list &element_list ) { clear(); - reserve(element_list.size()); - insert(end_iterator, element_list); + reserve( element_list.size() ); + insert( end_iterator, element_list ); } - inline allocator_type get_allocator() const noexcept - { - return element_allocator_type(); - } + inline allocator_type get_allocator() const noexcept { + return element_allocator_type(); + } - void swap(list &source) PLF_LIST_NOEXCEPT_SWAP(allocator_type) - { - list temp(std::move(source)); - source = std::move(*this); - *this = std::move(temp); - } + void swap( list &source ) PLF_LIST_NOEXCEPT_SWAP( allocator_type ) { + list temp( std::move( source ) ); + source = std::move( *this ); + *this = std::move( temp ); + } }; template -inline void swap(list &a, list &b) PLF_LIST_NOEXCEPT_SWAP(swap_element_allocator_type) +inline void swap( list &a, + list &b ) PLF_LIST_NOEXCEPT_SWAP( + swap_element_allocator_type ) { - a.swap(b); + a.swap( b ); } From d9b4f87094a887915da671818b7eeb378a167e7e Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Jul 2019 18:33:28 +0200 Subject: [PATCH 04/10] Fix style Also remove a couple of #endif's that I missed in the previous commit --- src/list.h | 574 +++++++++++------------------------------------------ 1 file changed, 121 insertions(+), 453 deletions(-) diff --git a/src/list.h b/src/list.h index 23cacd632339c..4f9c443f79140 100644 --- a/src/list.h +++ b/src/list.h @@ -17,11 +17,10 @@ // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. - +#pragma once #ifndef PLF_LIST_H #define PLF_LIST_H - #define PLF_LIST_BLOCK_MIN static_cast((sizeof(node) * 8 > (sizeof(*this) + sizeof(group)) * 2) ? 8 : (((sizeof(*this) + sizeof(group)) * 2) / sizeof(node)) + 1) #define PLF_LIST_BLOCK_MAX 2048 @@ -58,30 +57,24 @@ #include // std::is_trivially_destructible, etc #include // std::move - - - namespace plf { - - template > class list : private element_allocator_type { public: // Standard container typedefs: - typedef element_type value_type; - typedef element_allocator_type allocator_type; - typedef unsigned short group_size_type; - - typedef typename std::allocator_traits::size_type size_type; - typedef typename std::allocator_traits::difference_type difference_type; - typedef element_type &reference; - typedef const element_type &const_reference; - typedef typename std::allocator_traits::pointer pointer; - typedef typename std::allocator_traits::const_pointer const_pointer; + typedef element_type value_type; + typedef element_allocator_type allocator_type; + typedef unsigned short group_size_type; + typedef typename std::allocator_traits::size_type size_type; + typedef typename std::allocator_traits::difference_type difference_type; + typedef element_type &reference; + typedef const element_type &const_reference; + typedef typename std::allocator_traits::pointer pointer; + typedef typename std::allocator_traits::const_pointer const_pointer; // Iterator declarations: template class list_iterator; @@ -96,7 +89,6 @@ template ; friend class list_reverse_iterator; - private: struct group; // forward declarations for typedefs below struct node; @@ -112,8 +104,6 @@ template ::template rebind_alloc node_pointer_allocator_type; - - struct node_base { node_pointer_type next, previous; @@ -132,8 +122,6 @@ template node( node_pointer_type const next, node_pointer_type const previous, arguments &&... parameters ): node_base( next, previous ), @@ -156,15 +142,12 @@ template ( beyond_end - nodes ) ); } }; - - - class group_vector : private node_pointer_allocator_type { public: - group_pointer_type last_endpoint_group, block_pointer, - last_searched_group; // last_endpoint_group is the last -active- group in the block. Other -inactive- (previously used, now empty of elements) groups may be stored after this group for future usage (to reduce deallocation/reallocation of nodes). block_pointer + size - 1 == the last group in the block, regardless of whether or not the group is active. + // last_endpoint_group is the last -active- group in the block. Other -inactive- (previously used, now empty of elements) groups may be stored after this group for future usage (to reduce deallocation/reallocation of nodes). block_pointer + size - 1 == the last group in the block, regardless of whether or not the group is active. + group_pointer_type last_endpoint_group, block_pointer, last_searched_group; size_type size; - struct ebco_pair2 : allocator_type { // empty-base-class optimisation size_type capacity; // Total element capacity of all initialized groups explicit ebco_pair2( const size_type number_of_elements ) noexcept: capacity( @@ -241,8 +215,6 @@ template ::value ) { std::memset( static_cast( this ), 0, sizeof( group_vector ) ); @@ -268,8 +238,6 @@ template ::value ) { std::memcpy( static_cast( this ), &source, sizeof( group_vector ) ); @@ -297,13 +264,9 @@ template ::value ) { const node_pointer_type end = current_group->beyond_end; - if( ( end - current_group->nodes ) != - current_group->number_of_elements ) { // If there are erased nodes present in the group + if( ( end - current_group->nodes ) != current_group->number_of_elements ) { + // If there are erased nodes present in the group for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { if( current_node->next != NULL ) { // ie. is not part of free list @@ -368,13 +329,13 @@ template ::value || !std::is_trivially_destructible::value ) { - if( ( last_endpoint_node - last_endpoint_group->nodes ) != - last_endpoint_group->number_of_elements ) { // If there are erased nodes present in the group + if( ( last_endpoint_node - last_endpoint_group->nodes ) != last_endpoint_group->number_of_elements ) { + // If there are erased nodes present in the group for( node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node ) { if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - if( current_node->next != - NULL ) { // is not part of free list ie. element has not already had it's destructor called + if( current_node->next != NULL ) { + // is not part of free list ie. element has not already had it's destructor called PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); } } @@ -404,8 +365,6 @@ template ::value && std::is_trivially_destructible::value ) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer - std::memcpy( static_cast( &*block_pointer ), static_cast( &*old_block ), - sizeof( group ) * size ); // reinterpret_cast necessary to deal with GCC 8 warnings + // reinterpret_cast necessary to deal with GCC 8 warnings + std::memcpy( static_cast( &*block_pointer ), static_cast( &*old_block ), sizeof( group ) * size ); } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { std::uninitialized_copy( std::make_move_iterator( old_block ), std::make_move_iterator( old_block + size ), block_pointer ); @@ -432,15 +391,13 @@ template = group_to_erase && last_searched_group != block_pointer ) { --last_searched_group; @@ -499,8 +452,6 @@ template = group_to_erase && last_searched_group != block_pointer ) { --last_searched_group; @@ -539,10 +490,8 @@ template = block_pointer ); - if( location_node >= last_searched_group->nodes && - location_node < last_searched_group->beyond_end ) { // ie. location is within last_search_group - if( last_searched_group->free_list_head != - NULL ) { // if last_searched_group has previously-erased nodes + // ie. location is within last_search_group + if( location_node >= last_searched_group->nodes && location_node < last_searched_group->beyond_end ) { + // if last_searched_group has previously-erased nodes + if( last_searched_group->free_list_head != NULL ) { return last_searched_group; } } else { // search for the node group which location_node is located within, using last_searched_group as a starting point and searching left and right. Try and find the closest node group with reusable erased-element locations along the way: @@ -563,9 +512,10 @@ template beyond_end ) && - ( location_node >= right->nodes ) ) { // location_node's group is found - if( right->free_list_head != NULL ) { // group has erased nodes, reuse them: + // location_node's group is found + if( ( location_node < right->beyond_end ) && ( location_node >= right->nodes ) ) { + // group has erased nodes, reuse them: + if( right->free_list_head != NULL ) { last_searched_group = right; return right; } @@ -605,8 +555,8 @@ template free_list_head != - NULL ) { // location_node's group not found, but a reusable location found + // location_node's group not found, but a reusable location found + if( right->free_list_head != NULL ) { if( ( closest_freelist_right == NULL ) & ( closest_freelist_left == NULL ) ) { closest_freelist_left = right; } @@ -617,7 +567,6 @@ template = left->nodes ) && ( location_node < left->beyond_end ) ) { if( left->free_list_head != NULL ) { @@ -672,7 +621,6 @@ template ::value ) { // if all pointer types are trivial we can just copy using memcpy - faster - avoids constructors/destructors etc @@ -726,8 +672,6 @@ template ( beyond_last - ( last_endpoint_group + 1 ) ); } - - void append( group_vector &source ) { source.trim_trailing_groups(); trim_trailing_groups(); @@ -782,8 +724,6 @@ template struct choose; @@ -795,7 +735,6 @@ template class list_iterator @@ -814,105 +753,76 @@ template rh ) const + inline PLF_LIST_FORCE_INLINE bool operator==( const list_iterator < !is_const > rh ) const noexcept { return ( node_pointer == rh.node_pointer ); } - - - inline PLF_LIST_FORCE_INLINE bool operator != ( const list_iterator rh ) const noexcept { + inline PLF_LIST_FORCE_INLINE bool operator!=( const list_iterator rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - - - inline PLF_LIST_FORCE_INLINE bool operator != ( const list_iterator < !is_const > rh ) const + inline PLF_LIST_FORCE_INLINE bool operator!=( const list_iterator < !is_const > rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - - - inline PLF_LIST_FORCE_INLINE reference operator * () const { + inline PLF_LIST_FORCE_INLINE reference operator*() const { return node_pointer->element; } - - - inline PLF_LIST_FORCE_INLINE pointer operator -> () const { + inline PLF_LIST_FORCE_INLINE pointer operator->() const { return &( node_pointer->element ); } - - - inline PLF_LIST_FORCE_INLINE list_iterator &operator ++ () noexcept { + inline PLF_LIST_FORCE_INLINE list_iterator &operator++() noexcept { assert( node_pointer != NULL ); // covers uninitialised list_iterator node_pointer = node_pointer->next; return *this; } - - - inline list_iterator operator ++( int ) noexcept { + inline list_iterator operator++( int ) noexcept { const list_iterator copy( *this ); ++*this; return copy; } - - - inline PLF_LIST_FORCE_INLINE list_iterator &operator -- () noexcept { + inline PLF_LIST_FORCE_INLINE list_iterator &operator--() noexcept { assert( node_pointer != NULL ); // covers uninitialised list_iterator node_pointer = node_pointer->previous; return *this; } - - - inline list_iterator operator -- ( int ) noexcept { + inline list_iterator operator--( int ) noexcept { const list_iterator copy( *this ); --*this; return copy; } - - - inline list_iterator &operator = ( const list_iterator &rh ) noexcept { + inline list_iterator &operator=( const list_iterator &rh ) noexcept { node_pointer = rh.node_pointer; return *this; } - - - inline list_iterator &operator = ( const list_iterator < !is_const > &rh ) noexcept { + inline list_iterator &operator=( const list_iterator < !is_const > &rh ) noexcept { node_pointer = rh.node_pointer; return *this; } - - - inline list_iterator &operator = ( const list_iterator &&rh ) noexcept { + inline list_iterator &operator=( const list_iterator &&rh ) noexcept { node_pointer = std::move( rh.node_pointer ); return *this; } - - inline list_iterator &operator = ( const list_iterator < !is_const > &&rh ) noexcept { + inline list_iterator &operator=( const list_iterator < !is_const > &&rh ) noexcept { node_pointer = std::move( rh.node_pointer ); return *this; } - - list_iterator() noexcept: node_pointer( NULL ) {} list_iterator( const list_iterator &source ) noexcept: node_pointer( source.node_pointer ) {} @@ -931,9 +841,6 @@ template class list_reverse_iterator { private: @@ -941,7 +848,7 @@ template ::type pointer; @@ -950,112 +857,82 @@ template rh ) const + inline PLF_LIST_FORCE_INLINE bool operator==( const list_reverse_iterator < !is_const > rh ) const noexcept { return ( node_pointer == rh.node_pointer ); } - - - inline PLF_LIST_FORCE_INLINE bool operator != ( const list_reverse_iterator rh ) const noexcept { + inline PLF_LIST_FORCE_INLINE bool operator!=( const list_reverse_iterator rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - - - inline PLF_LIST_FORCE_INLINE bool operator != ( const list_reverse_iterator < !is_const > rh ) const + inline PLF_LIST_FORCE_INLINE bool operator!=( const list_reverse_iterator < !is_const > rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - - - inline PLF_LIST_FORCE_INLINE reference operator * () const { + inline PLF_LIST_FORCE_INLINE reference operator*() const { return node_pointer->element; } - - - inline PLF_LIST_FORCE_INLINE pointer operator -> () const { + inline PLF_LIST_FORCE_INLINE pointer operator->() const { return &( node_pointer->element ); } - - - inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator ++ () noexcept { + inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator++() noexcept { assert( node_pointer != NULL ); // covers uninitialised list_reverse_iterator node_pointer = node_pointer->previous; return *this; } - - - inline list_reverse_iterator operator ++( int ) noexcept { + inline list_reverse_iterator operator++( int ) noexcept { const list_reverse_iterator copy( *this ); ++*this; return copy; } - - - inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator -- () noexcept { + inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator--() noexcept { assert( node_pointer != NULL ); node_pointer = node_pointer->next; return *this; } - - - inline list_reverse_iterator operator -- ( int ) noexcept { + inline list_reverse_iterator operator--( int ) noexcept { const list_reverse_iterator copy( *this ); --*this; return copy; } - - - inline list_reverse_iterator &operator = ( const list_reverse_iterator &rh ) noexcept { + inline list_reverse_iterator &operator=( const list_reverse_iterator &rh ) noexcept { node_pointer = rh.node_pointer; return *this; } - - - inline list_reverse_iterator &operator = ( const list_reverse_iterator < !is_const > &rh ) + inline list_reverse_iterator &operator=( const list_reverse_iterator < !is_const > &rh ) noexcept { node_pointer = rh.node_pointer; return *this; } - - - inline list_reverse_iterator &operator = ( const list_reverse_iterator &&rh ) noexcept { + inline list_reverse_iterator &operator=( const list_reverse_iterator &&rh ) noexcept { node_pointer = std::move( rh.node_pointer ); return *this; } - - inline list_reverse_iterator &operator = ( const list_reverse_iterator < !is_const > && + inline list_reverse_iterator &operator=( const list_reverse_iterator < !is_const > && rh ) noexcept { node_pointer = std::move( rh.node_pointer ); return *this; } - - inline typename list::iterator base() const noexcept { return typename list::iterator( node_pointer->next ); } - - list_reverse_iterator() noexcept: node_pointer( NULL ) {} list_reverse_iterator( const list_reverse_iterator &source ) noexcept: node_pointer( @@ -1069,8 +946,6 @@ template { }; - - group_vector groups; node_base end_node; node_pointer_type last_endpoint; // last_endpoint being NULL means no elements have been constructed, but there may still be groups available due to clear() or reservee() - iterator end_iterator, - begin_iterator; // end_iterator is always the last entry point in last group in list (or one past the end of group) + iterator begin_iterator; + iterator end_iterator; // end_iterator is always the last entry point in last group in list (or one past the end of group) - struct ebco_pair1 : - node_pointer_allocator_type { // Packaging the group allocator with least-used member variables, for empty-base-class optimisation + // Packaging the group allocator with least-used member variables, for empty-base-class optimisation + struct ebco_pair1 : node_pointer_allocator_type { size_type total_number_of_elements; explicit ebco_pair1( const size_type total_num_elements ) noexcept: total_number_of_elements( total_num_elements ) {} @@ -1105,12 +978,9 @@ template ( &end_node ), @@ -1122,10 +992,7 @@ template ( &end_node ), @@ -1137,10 +1004,7 @@ template ( &end_node ), @@ -1154,10 +1018,7 @@ template ( &end_node ), @@ -1171,10 +1032,7 @@ template list( const typename plf_enable_if_c < !std::numeric_limits::is_integer, iterator_type >::type &first, const iterator_type &last, @@ -1246,10 +1095,7 @@ template ( end_iterator, first, last ); } - - // Initializer-list constructor: - list( const std::initializer_list &element_list, const element_allocator_type &alloc = element_allocator_type() ): element_allocator_type( alloc ), @@ -1264,103 +1110,70 @@ template element; } - - inline const_reference front() const { assert( begin_iterator.node_pointer != &end_node ); return begin_iterator.node_pointer->element; } - - inline reference back() { assert( end_node.previous != &end_node ); return end_node.previous->element; } - - inline const_reference back() const { assert( end_node.previous != &end_node ); return end_node.previous->element; } - - void clear() noexcept { if( last_endpoint == NULL ) { return; @@ -1378,11 +1191,8 @@ template beyond_end ) { // last_endpoint is beyond the end of a group - if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - - 1 ) { // ie. there are no reusable groups available at the back of group vector + // ie. list is not empty + if( last_endpoint != NULL ) { + // No erased nodes available for reuse + if( node_allocator_pair.number_of_erased_nodes == 0 ) { + // last_endpoint is beyond the end of a group + if( last_endpoint == groups.last_endpoint_group->beyond_end ) { + // ie. there are no reusable groups available at the back of group vector + if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - 1 ) { groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? static_cast( node_pointer_allocator_pair.total_number_of_elements ) : PLF_LIST_BLOCK_MAX ); @@ -1454,8 +1262,8 @@ template beyond_end ) { @@ -1579,26 +1380,17 @@ template - iterator emplace( const iterator it, - arguments &&... - parameters ) { // This is almost identical to the insert implementations above with the only changes being std::forward of element parameters and removal of VARIADICS support checking + iterator emplace( const iterator it, arguments &&... parameters ) { if( last_endpoint != NULL ) { if( node_allocator_pair.number_of_erased_nodes == 0 ) { if( last_endpoint == groups.last_endpoint_group->beyond_end ) { @@ -1678,26 +1470,17 @@ template inline PLF_LIST_FORCE_INLINE reference emplace_back( arguments &&... parameters ) { return ( emplace( end_iterator, std::forward( parameters )... ) ).node_pointer->element; } - - template inline PLF_LIST_FORCE_INLINE reference emplace_front( arguments &&... parameters ) { return ( emplace( begin_iterator, std::forward( parameters )... ) ).node_pointer->element; } - -#endif - - - private: void group_fill_position( const element_type &element, group_size_type number_of_elements, @@ -1730,12 +1513,9 @@ template previous = previous; } - - public: // Fill insert - iterator insert( iterator position, const size_type number_of_elements, const element_type &element ) { if( number_of_elements == 0 ) { @@ -1744,7 +1524,6 @@ template ( groups.block_pointer->beyond_end - groups.block_pointer->nodes ) < number_of_elements ) && @@ -1753,7 +1532,6 @@ template PLF_LIST_BLOCK_MAX ) { size_type multiples = number_of_elements / PLF_LIST_BLOCK_MAX; @@ -1835,7 +1613,6 @@ template iterator insert( const iterator it, typename plf_enable_if_c < !std::numeric_limits::is_integer, @@ -1893,17 +1667,13 @@ template &element_list ) { // use range insert: return insert( it, element_list.begin(), element_list.end() ); } - private: inline PLF_LIST_FORCE_INLINE void destroy_all_node_pointers( group_pointer_type const @@ -1917,15 +1687,11 @@ template next; } - const iterator return_iterator( it.node_pointer->next ); - if( --( node_group->number_of_elements ) != - 0 ) { // ie. group is not empty yet, add node to free list - it.node_pointer->next = - NULL; // next == NULL so that destructor can detect the free list item as opposed to non-free-list item + // ie. group is not empty yet, add node to free list + if( --( node_group->number_of_elements ) != 0 ) { + // next == NULL so that destructor can detect the free list item as opposed to non-free-list item + it.node_pointer->next = NULL; it.node_pointer->previous = node_group->free_list_head; node_group->free_list_head = it.node_pointer; return return_iterator; - } else if( node_group != - groups.last_endpoint_group-- ) { // remove group (and decrement active back group) + } else if( node_group != groups.last_endpoint_group-- ) { + // remove group (and decrement active back group) const group_size_type group_size = static_cast( node_group->beyond_end - node_group->nodes ); node_allocator_pair.number_of_erased_nodes -= group_size; @@ -2002,8 +1766,8 @@ template free_list_head = NULL; - if( ( group_size == PLF_LIST_BLOCK_MAX ) | ( node_group >= groups.last_endpoint_group - - 1 ) ) { // Preserve only last (active) group or second/third-to-last group - seems to be best for performance under high-modification benchmarks + // Preserve only last (active) group or second/third-to-last group - seems to be best for performance under high-modification benchmarks + if( ( group_size == PLF_LIST_BLOCK_MAX ) | ( node_group >= groups.last_endpoint_group - 1 ) ) { groups.move_to_back( node_group ); } else { groups.remove( node_group ); @@ -2022,43 +1786,32 @@ template nodes ); last_endpoint = groups.last_endpoint_group->beyond_end; } else { - groups.last_endpoint_group = - groups.block_pointer; // If number of elements is zero, it indicates that this was the first group in the vector. In which case the last_endpoint_group would be invalid at this point due to the decrement in the above else-if statement. So it needs to be reset, as it will not be reset in the function call below. + // If number of elements is zero, it indicates that this was the first group in the vector. In which case the last_endpoint_group would be invalid at this point due to the decrement in the above else-if statement. So it needs to be reset, as it will not be reset in the function call below. + groups.last_endpoint_group = groups.block_pointer; clear(); } - return return_iterator; } } - - // Range-erase: - - inline void erase( const const_iterator iterator1, - const const_iterator - iterator2 ) { // if uninitialized/invalid iterator supplied, function could generate an exception + // if uninitialized/invalid iterator supplied, function could generate an exception + inline void erase( const const_iterator iterator1, const const_iterator iterator2 ) { for( const_iterator current = iterator1; current != iterator2; ) { current = erase( current ); } } - - inline void pop_back() { // Exception will occur on empty list erase( iterator( end_node.previous ) ); } - - inline void pop_front() { // Exception will occur on empty list erase( begin_iterator ); } - - - inline list &operator = ( const list &source ) { + inline list &operator=( const list &source ) { assert( &source != this ); clear(); @@ -2068,10 +1821,8 @@ template ::max_size( *this ); } - - inline size_type capacity() const noexcept { return groups.element_allocator_pair.capacity; } - - inline size_type approximate_memory_use() const noexcept { return static_cast( sizeof( *this ) + ( groups.element_allocator_pair.capacity * sizeof( node ) ) + ( sizeof( group ) * groups.group_allocator_pair.capacity ) ); } - - private: - struct less { inline bool operator()( const element_type &a, const element_type &b ) const noexcept { return a < b; } }; - - // Function-object to redirect the sort function to sort pointers by the elements they point to, not the pointer value template struct sort_dereferencer { @@ -2182,11 +1914,8 @@ template void sort( comparison_function compare ) { if( node_pointer_allocator_pair.total_number_of_elements < 2 ) { @@ -2197,7 +1926,6 @@ template ( compare ) ); -#else std::sort( node_pointers, node_pointers + node_pointer_allocator_pair.total_number_of_elements, sort_dereferencer( compare ) ); -#endif begin_iterator.node_pointer = node_pointers[0]; begin_iterator.node_pointer->next = node_pointers[1]; @@ -2252,11 +1974,10 @@ template next = end_iterator.node_pointer; - end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - - 2]; + end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 2]; - node_pointer_type *const back = node_pointers + node_pointer_allocator_pair.total_number_of_elements - - 1; + node_pointer_type *const back = node_pointers + + node_pointer_allocator_pair.total_number_of_elements - 1; for( node_pointer = node_pointers + 1; node_pointer != back; ++node_pointer ) { ( *node_pointer )->next = *( node_pointer + 1 ); @@ -2275,14 +1996,10 @@ template next->previous = first.node_pointer->previous; first.node_pointer->previous->next = last.node_pointer->next; @@ -2298,14 +2015,10 @@ template ( ( groups.block_pointer + groups.size - 1 )->beyond_end - ( groups.block_pointer + groups.size - 1 )->nodes ); - if( reserve_amount > end_group_size && - end_group_size != PLF_LIST_BLOCK_MAX ) { // if last group isn't large enough, remove all groups + // if last group isn't large enough, remove all groups + if( reserve_amount > end_group_size && end_group_size != PLF_LIST_BLOCK_MAX ) { reset(); } else { size_type number_of_full_groups_needed = reserve_amount / PLF_LIST_BLOCK_MAX; @@ -2359,8 +2071,8 @@ template ( ( ( reserve_amount < PLF_LIST_BLOCK_MIN ) ? PLF_LIST_BLOCK_MIN : reserve_amount ) ) ); @@ -2383,14 +2095,10 @@ template void merge( list &source, comparison_function compare ) { assert( &source != this ); @@ -2485,8 +2185,6 @@ template 1 ) { for( group_pointer_type current_group = groups.block_pointer; @@ -2566,8 +2262,6 @@ template @@ -2618,14 +2308,10 @@ template size_type remove_if( predicate_function predicate ) { const size_type original_number_of_elements = node_pointer_allocator_pair.total_number_of_elements; @@ -2636,15 +2322,17 @@ template number_of_elements; const node_pointer_type end = current_group->beyond_end; - if( end - current_group->nodes != num_elements ) { // If there are erased nodes present in the group + // If there are erased nodes present in the group + if( end - current_group->nodes != num_elements ) { for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { - if( current_node->next != NULL && - predicate( current_node->element ) ) { // is not free list node and validates predicate + // is not free list node and validates predicate + if( current_node->next != NULL && predicate( current_node->element ) ) { erase( current_node ); - if( --num_elements == - 0 ) { // ie. group will be empty (and removed) now - nothing left to iterate over - --current_group; // As current group has been removed, subsequent groups have already shifted back by one, hence, the ++ to the current group in the for loop is unnecessary, and negated here + // ie. group will be empty (and removed) now - nothing left to iterate over + if( --num_elements == 0 ) { + // As current group has been removed, subsequent groups have already shifted back by one, hence, the ++ to the current group in the for loop is unnecessary, and negated here + --current_group; break; } } @@ -2665,8 +2353,8 @@ template number_of_elements; - if( last_endpoint - groups.last_endpoint_group->nodes != - num_elements ) { // If there are erased nodes present in the group + // If there are erased nodes present in the group + if( last_endpoint - groups.last_endpoint_group->nodes != num_elements ) { for( node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node ) { if( current_node->next != NULL && predicate( current_node->element ) ) { @@ -2694,14 +2382,10 @@ template inline void assign( const typename plf_enable_if_c < @@ -2735,8 +2417,6 @@ template &element_list ) { clear(); @@ -2753,24 +2431,17 @@ template inline void swap( list &a, list &b ) PLF_LIST_NOEXCEPT_SWAP( @@ -2779,8 +2450,6 @@ inline void swap( list &a, a.swap( b ); } - - } // plf namespace #undef PLF_LIST_BLOCK_MAX @@ -2798,5 +2467,4 @@ inline void swap( list &a, #undef PLF_LIST_ALLOCATE_INITIALIZATION #undef PLF_LIST_DEALLOCATE - #endif // PLF_LIST_H From 195bdadc588177012cbb864d329958c500fbbcc2 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Jul 2019 18:37:52 +0200 Subject: [PATCH 05/10] Use cata namespace --- src/list.h | 387 +++++++++++++++++++++++++++-------------------------- 1 file changed, 195 insertions(+), 192 deletions(-) diff --git a/src/list.h b/src/list.h index 4f9c443f79140..5383a1e163a35 100644 --- a/src/list.h +++ b/src/list.h @@ -1,3 +1,6 @@ +// This software is a modified version of the original. +// The original license is as follows: + // Copyright (c) 2019, Matthew Bentley (mattreecebentley@gmail.com) www.plflib.org // zLib license (https://www.zlib.net/zlib_license.html): @@ -18,34 +21,34 @@ // 3. This notice may not be removed or altered from any source distribution. #pragma once -#ifndef PLF_LIST_H -#define PLF_LIST_H +#ifndef LIST_H +#define LIST_H -#define PLF_LIST_BLOCK_MIN static_cast((sizeof(node) * 8 > (sizeof(*this) + sizeof(group)) * 2) ? 8 : (((sizeof(*this) + sizeof(group)) * 2) / sizeof(node)) + 1) -#define PLF_LIST_BLOCK_MAX 2048 +#define LIST_BLOCK_MIN static_cast((sizeof(node) * 8 > (sizeof(*this) + sizeof(group)) * 2) ? 8 : (((sizeof(*this) + sizeof(group)) * 2) / sizeof(node)) + 1) +#define LIST_BLOCK_MAX 2048 -#define PLF_LIST_CONSTEXPR -#define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept -#define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept +#define LIST_CONSTEXPR +#define LIST_NOEXCEPT_SWAP(the_allocator) noexcept +#define LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept // TODO: Switch to these when we move to C++17 -// #define PLF_LIST_CONSTEXPR constexpr -// #define PLF_LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) -// #define PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) +// #define LIST_CONSTEXPR constexpr +// #define LIST_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits::propagate_on_container_swap::value) +// #define LIST_NOEXCEPT_MOVE_ASSIGNMENT(the_allocator) noexcept(std::allocator_traits::is_always_equal::value) // Note: GCC creates faster code without forcing inline #if defined(_MSC_VER) -#define PLF_LIST_FORCE_INLINE __forceinline +#define LIST_FORCE_INLINE __forceinline #else -#define PLF_LIST_FORCE_INLINE +#define LIST_FORCE_INLINE #endif // TODO: get rid of these defines -#define PLF_LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) std::allocator_traits::construct(allocator_instance, location, __VA_ARGS__) -#define PLF_LIST_DESTROY(the_allocator, allocator_instance, location) std::allocator_traits::destroy(allocator_instance, location) -#define PLF_LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) std::allocator_traits::allocate(allocator_instance, size, hint) -#define PLF_LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) std::allocator_traits::allocate(*this, size, hint) -#define PLF_LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) std::allocator_traits::deallocate(allocator_instance, location, size) +#define LIST_CONSTRUCT(the_allocator, allocator_instance, location, ...) std::allocator_traits::construct(allocator_instance, location, __VA_ARGS__) +#define LIST_DESTROY(the_allocator, allocator_instance, location) std::allocator_traits::destroy(allocator_instance, location) +#define LIST_ALLOCATE(the_allocator, allocator_instance, size, hint) std::allocator_traits::allocate(allocator_instance, size, hint) +#define LIST_ALLOCATE_INITIALIZATION(the_allocator, size, hint) std::allocator_traits::allocate(*this, size, hint) +#define LIST_DEALLOCATE(the_allocator, allocator_instance, location, size) std::allocator_traits::deallocate(allocator_instance, location, size) #include // std::sort #include // assert @@ -57,7 +60,7 @@ #include // std::is_trivially_destructible, etc #include // std::move -namespace plf +namespace cata { template > class @@ -156,7 +159,7 @@ template ( beyond_end - nodes ) ); } }; @@ -225,8 +228,8 @@ template ::value ) { + inline LIST_FORCE_INLINE void blank() noexcept { + if LIST_CONSTEXPR( std::is_trivial::value ) { std::memset( static_cast( this ), 0, sizeof( group_vector ) ); } else { last_endpoint_group = NULL; @@ -249,7 +252,7 @@ template ::value ) { + if LIST_CONSTEXPR( std::is_trivial::value ) { std::memcpy( static_cast( this ), &source, sizeof( group_vector ) ); } else { last_endpoint_group = std::move( source.last_endpoint_group ); @@ -272,7 +275,7 @@ template ::value || + if LIST_CONSTEXPR( !std::is_trivially_destructible::value || !std::is_trivially_destructible::value ) { clear( last_endpoint_node ); // If clear has already been called, last_endpoint_node will already be == block_pointer->nodes, so no work will occur } @@ -280,10 +283,10 @@ template ::value || + if LIST_CONSTEXPR( !std::is_trivially_destructible::value || !std::is_trivially_destructible::value ) { const node_pointer_type end = current_group->beyond_end; if( ( end - current_group->nodes ) != current_group->number_of_elements ) { // If there are erased nodes present in the group for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { if( current_node->next != NULL ) { // ie. is not part of free list - PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); } } - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); } } } else { for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); } - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); } } } @@ -327,34 +330,34 @@ template number_of_elements = 0; } - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value || + if LIST_CONSTEXPR( !std::is_trivially_destructible::value || !std::is_trivially_destructible::value ) { if( ( last_endpoint_node - last_endpoint_group->nodes ) != last_endpoint_group->number_of_elements ) { // If there are erased nodes present in the group for( node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node ) { - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { if( current_node->next != NULL ) { // is not part of free list ie. element has not already had it's destructor called - PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); } } - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); } } } else { for( node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node ) { - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( element_allocator_type, element_allocator_pair, &( current_node->element ) ); } - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); - PLF_LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->next ) ); + LIST_DESTROY( node_pointer_allocator_type, ( *this ), &( current_node->previous ) ); } } } @@ -367,14 +370,14 @@ template ::value && + if LIST_CONSTEXPR( std::is_trivially_copyable::value && std::is_trivially_destructible::value ) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer // reinterpret_cast necessary to deal with GCC 8 warnings std::memcpy( static_cast( &*block_pointer ), static_cast( &*old_block ), sizeof( group ) * size ); - } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + } else if LIST_CONSTEXPR( std::is_move_constructible::value ) { std::uninitialized_copy( std::make_move_iterator( old_block ), std::make_move_iterator( old_block + size ), block_pointer ); } else { @@ -387,13 +390,13 @@ template nodes = NULL; current_group->beyond_end = NULL; - PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); + LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); } } // correct pointer post-reallocation last_searched_group = block_pointer + ( last_searched_group - old_block ); - PLF_LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, old_block, + LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, old_block, group_allocator_pair.capacity ); group_allocator_pair.capacity = new_capacity; } @@ -405,7 +408,7 @@ template nodes ); ++last_endpoint_group; // Doing this here instead of pre-construct to avoid need for a try-catch block @@ -415,11 +418,11 @@ template ( group_to_erase->beyond_end - group_to_erase->nodes ); - PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, group_to_erase ); + LIST_DESTROY( group_allocator_type, group_allocator_pair, group_to_erase ); - if PLF_LIST_CONSTEXPR( std::is_trivially_copyable::value && + if LIST_CONSTEXPR( std::is_trivially_copyable::value && std::is_trivially_destructible::value ) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memmove( static_cast( &*group_to_erase ), static_cast( &*group_to_erase + 1 ), sizeof( group ) * ( --size - static_cast( &*group_to_erase - &*block_pointer ) ) ); - } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + } else if LIST_CONSTEXPR( std::is_move_constructible::value ) { std::move( group_to_erase + 1, block_pointer + size--, group_to_erase ); } else { group_pointer_type back = block_pointer + size--; @@ -448,7 +451,7 @@ template nodes = NULL; back->beyond_end = NULL; - PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, back ); + LIST_DESTROY( group_allocator_type, group_allocator_pair, back ); } } @@ -457,9 +460,9 @@ template ::value && + if LIST_CONSTEXPR( std::is_trivially_copyable::value && std::is_trivially_destructible::value ) { std::memcpy( static_cast( &*temp_group ), static_cast( &*group_to_erase ), sizeof( group ) ); @@ -467,27 +470,27 @@ template ( &*group_to_erase - &*block_pointer ) ) ); std::memcpy( static_cast( &*( block_pointer + size - 1 ) ), static_cast( &*temp_group ), sizeof( group ) ); - } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { - PLF_LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, + } else if LIST_CONSTEXPR( std::is_move_constructible::value ) { + LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, std::move( *group_to_erase ) ); std::move( group_to_erase + 1, block_pointer + size, group_to_erase ); *( block_pointer + size - 1 ) = std::move( *temp_group ); - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, temp_group ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( group_allocator_type, group_allocator_pair, temp_group ); } } else { - PLF_LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, group() ); + LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, group() ); *temp_group = *group_to_erase; std::copy( group_to_erase + 1, block_pointer + size, group_to_erase ); *( block_pointer + --size ) = *temp_group; temp_group->nodes = NULL; - PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, temp_group ); + LIST_DESTROY( group_allocator_type, group_allocator_pair, temp_group ); } - PLF_LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, temp_group, 1 ); + LIST_DEALLOCATE( group_allocator_type, group_allocator_pair, temp_group, 1 ); } // In working implementation this cannot throw @@ -643,8 +646,8 @@ template ::value ) { // if all pointer types are trivial we can just copy using memcpy - faster - avoids constructors/destructors etc char temp[sizeof( group_vector )]; std::memcpy( static_cast( &temp ), static_cast( this ), sizeof( group_vector ) ); @@ -679,7 +682,7 @@ template ( current_group->beyond_end - current_group->nodes ); - PLF_LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); + LIST_DESTROY( group_allocator_type, group_allocator_pair, current_group ); } size -= static_cast( beyond_last - ( last_endpoint_group + 1 ) ); @@ -693,12 +696,12 @@ template ::value && + if LIST_CONSTEXPR( std::is_trivially_copyable::value && std::is_trivially_destructible::value ) { // &* in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memcpy( static_cast( &*block_pointer + size ), static_cast( &*source.block_pointer ), sizeof( group ) * source.size ); - } else if PLF_LIST_CONSTEXPR( std::is_move_constructible::value ) { + } else if LIST_CONSTEXPR( std::is_move_constructible::value ) { std::uninitialized_copy( std::make_move_iterator( source.block_pointer ), std::make_move_iterator( source.block_pointer + source.size ), block_pointer + size ); } else { @@ -711,11 +714,11 @@ template nodes = NULL; current_group->beyond_end = NULL; - PLF_LIST_DESTROY( group_allocator_type, source.group_allocator_pair, current_group ); + LIST_DESTROY( group_allocator_type, source.group_allocator_pair, current_group ); } } - PLF_LIST_DEALLOCATE( group_allocator_type, source.group_allocator_pair, source.block_pointer, + LIST_DEALLOCATE( group_allocator_type, source.group_allocator_pair, source.block_pointer, source.group_allocator_pair.capacity ); size += source.size; last_endpoint_group = block_pointer + size - 1; @@ -753,33 +756,33 @@ template rh ) const + inline LIST_FORCE_INLINE bool operator==( const list_iterator < !is_const > rh ) const noexcept { return ( node_pointer == rh.node_pointer ); } - inline PLF_LIST_FORCE_INLINE bool operator!=( const list_iterator rh ) const noexcept { + inline LIST_FORCE_INLINE bool operator!=( const list_iterator rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - inline PLF_LIST_FORCE_INLINE bool operator!=( const list_iterator < !is_const > rh ) const + inline LIST_FORCE_INLINE bool operator!=( const list_iterator < !is_const > rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - inline PLF_LIST_FORCE_INLINE reference operator*() const { + inline LIST_FORCE_INLINE reference operator*() const { return node_pointer->element; } - inline PLF_LIST_FORCE_INLINE pointer operator->() const { + inline LIST_FORCE_INLINE pointer operator->() const { return &( node_pointer->element ); } - inline PLF_LIST_FORCE_INLINE list_iterator &operator++() noexcept { + inline LIST_FORCE_INLINE list_iterator &operator++() noexcept { assert( node_pointer != NULL ); // covers uninitialised list_iterator node_pointer = node_pointer->next; return *this; @@ -791,7 +794,7 @@ template previous; return *this; @@ -857,33 +860,33 @@ template rh ) const + inline LIST_FORCE_INLINE bool operator==( const list_reverse_iterator < !is_const > rh ) const noexcept { return ( node_pointer == rh.node_pointer ); } - inline PLF_LIST_FORCE_INLINE bool operator!=( const list_reverse_iterator rh ) const noexcept { + inline LIST_FORCE_INLINE bool operator!=( const list_reverse_iterator rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - inline PLF_LIST_FORCE_INLINE bool operator!=( const list_reverse_iterator < !is_const > rh ) const + inline LIST_FORCE_INLINE bool operator!=( const list_reverse_iterator < !is_const > rh ) const noexcept { return ( node_pointer != rh.node_pointer ); } - inline PLF_LIST_FORCE_INLINE reference operator*() const { + inline LIST_FORCE_INLINE reference operator*() const { return node_pointer->element; } - inline PLF_LIST_FORCE_INLINE pointer operator->() const { + inline LIST_FORCE_INLINE pointer operator->() const { return &( node_pointer->element ); } - inline PLF_LIST_FORCE_INLINE list_reverse_iterator &operator++() noexcept { + inline LIST_FORCE_INLINE list_reverse_iterator &operator++() noexcept { assert( node_pointer != NULL ); // covers uninitialised list_reverse_iterator node_pointer = node_pointer->previous; return *this; @@ -895,7 +898,7 @@ template next; return *this; @@ -1214,9 +1217,9 @@ template beyond_end ) { // ie. there are no reusable groups available at the back of group vector if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - 1 ) { - groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? + groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < LIST_BLOCK_MAX ) ? static_cast( node_pointer_allocator_pair.total_number_of_elements ) : - PLF_LIST_BLOCK_MAX ); + LIST_BLOCK_MAX ); } else { ++groups.last_endpoint_group; } @@ -1224,7 +1227,7 @@ template nodes; } - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, element ); ++( groups.last_endpoint_group->number_of_elements ); @@ -1244,7 +1247,7 @@ template free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, element ); node_group->free_list_head = previous; @@ -1264,7 +1267,7 @@ template number_of_elements = 1; @@ -1272,13 +1275,13 @@ template nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - if PLF_LIST_CONSTEXPR( + if LIST_CONSTEXPR( std::is_nothrow_copy_constructible::value ) { // Avoid try-catch code generation - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element ); } else { try { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, element ); } catch( ... ) { reset(); @@ -1290,11 +1293,11 @@ template beyond_end ) { if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - 1 ) { - groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? + groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < LIST_BLOCK_MAX ) ? static_cast( node_pointer_allocator_pair.total_number_of_elements ) : - PLF_LIST_BLOCK_MAX ); + LIST_BLOCK_MAX ); } else { ++groups.last_endpoint_group; } @@ -1315,7 +1318,7 @@ template nodes; } - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::move( element ) ); ++( groups.last_endpoint_group->number_of_elements ); @@ -1335,7 +1338,7 @@ template free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::move( element ) ); node_group->free_list_head = previous; @@ -1354,7 +1357,7 @@ template number_of_elements = 1; @@ -1362,13 +1365,13 @@ template nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - if PLF_LIST_CONSTEXPR( std::is_nothrow_move_constructible::value ) { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + if LIST_CONSTEXPR( std::is_nothrow_move_constructible::value ) { + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); } else { try { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); } catch( ... ) { reset(); @@ -1380,11 +1383,11 @@ template beyond_end ) { if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - 1 ) { - groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < PLF_LIST_BLOCK_MAX ) ? + groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < LIST_BLOCK_MAX ) ? static_cast( node_pointer_allocator_pair.total_number_of_elements ) : - PLF_LIST_BLOCK_MAX ); + LIST_BLOCK_MAX ); } else { ++groups.last_endpoint_group; } @@ -1406,7 +1409,7 @@ template nodes; } - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, it.node_pointer, it.node_pointer->previous, std::forward( parameters )... ); ++( groups.last_endpoint_group->number_of_elements ); @@ -1426,7 +1429,7 @@ template free_list_head; const node_pointer_type previous = node_group->free_list_head->previous; - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, it.node_pointer->previous, std::forward( parameters )... ); node_group->free_list_head = previous; @@ -1445,7 +1448,7 @@ template number_of_elements = 1; @@ -1453,12 +1456,12 @@ template nodes; node_pointer_allocator_pair.total_number_of_elements = 1; - if PLF_LIST_CONSTEXPR( std::is_nothrow_constructible::value ) { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + if LIST_CONSTEXPR( std::is_nothrow_constructible::value ) { + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); } else { try { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); } catch( ... ) { reset(); @@ -1471,12 +1474,12 @@ template - inline PLF_LIST_FORCE_INLINE reference emplace_back( arguments &&... parameters ) { + inline LIST_FORCE_INLINE reference emplace_back( arguments &&... parameters ) { return ( emplace( end_iterator, std::forward( parameters )... ) ).node_pointer->element; } template - inline PLF_LIST_FORCE_INLINE reference emplace_front( arguments &&... parameters ) { + inline LIST_FORCE_INLINE reference emplace_front( arguments &&... parameters ) { return ( emplace( begin_iterator, std::forward( parameters )... ) ).node_pointer->element; } @@ -1490,12 +1493,12 @@ template previous; do { - if PLF_LIST_CONSTEXPR( std::is_nothrow_copy_constructible::value ) { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, + if LIST_CONSTEXPR( std::is_nothrow_copy_constructible::value ) { + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element ); } else { try { - PLF_LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, + LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, previous, element ); } catch( ... ) { previous->next = position; @@ -1528,52 +1531,52 @@ template ( groups.block_pointer->beyond_end - groups.block_pointer->nodes ) < number_of_elements ) && ( static_cast( groups.block_pointer->beyond_end - groups.block_pointer->nodes ) < - PLF_LIST_BLOCK_MAX ) ) { + LIST_BLOCK_MAX ) ) { reset(); } if( groups.block_pointer == NULL ) { // ie. Uninitialized list - if( number_of_elements > PLF_LIST_BLOCK_MAX ) { - size_type multiples = number_of_elements / PLF_LIST_BLOCK_MAX; + if( number_of_elements > LIST_BLOCK_MAX ) { + size_type multiples = number_of_elements / LIST_BLOCK_MAX; const group_size_type remainder = static_cast( number_of_elements - - ( multiples++ * PLF_LIST_BLOCK_MAX ) ); // ++ to aid while loop below + ( multiples++ * LIST_BLOCK_MAX ) ); // ++ to aid while loop below // Create and fill first group: if( remainder != 0 ) { // make sure smallest block is first - if( remainder >= PLF_LIST_BLOCK_MIN ) { + if( remainder >= LIST_BLOCK_MIN ) { groups.initialize( remainder ); end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; group_fill_position( element, remainder, end_iterator.node_pointer ); } else { // Create first group as BLOCK_MIN size then subtract difference between BLOCK_MIN and remainder from next group: - groups.initialize( PLF_LIST_BLOCK_MIN ); + groups.initialize( LIST_BLOCK_MIN ); end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - group_fill_position( element, PLF_LIST_BLOCK_MIN, end_iterator.node_pointer ); + group_fill_position( element, LIST_BLOCK_MIN, end_iterator.node_pointer ); - groups.add_new( PLF_LIST_BLOCK_MAX - ( PLF_LIST_BLOCK_MIN - remainder ) ); + groups.add_new( LIST_BLOCK_MAX - ( LIST_BLOCK_MIN - remainder ) ); end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position( element, PLF_LIST_BLOCK_MAX - ( PLF_LIST_BLOCK_MIN - remainder ), + group_fill_position( element, LIST_BLOCK_MAX - ( LIST_BLOCK_MIN - remainder ), end_iterator.node_pointer ); --multiples; } } else { - groups.initialize( PLF_LIST_BLOCK_MAX ); + groups.initialize( LIST_BLOCK_MAX ); end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; - group_fill_position( element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer ); + group_fill_position( element, LIST_BLOCK_MAX, end_iterator.node_pointer ); --multiples; } while( --multiples != 0 ) { - groups.add_new( PLF_LIST_BLOCK_MAX ); + groups.add_new( LIST_BLOCK_MAX ); end_node.previous = last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position( element, PLF_LIST_BLOCK_MAX, end_iterator.node_pointer ); + group_fill_position( element, LIST_BLOCK_MAX, end_iterator.node_pointer ); } } else { - groups.initialize( ( number_of_elements < PLF_LIST_BLOCK_MIN ) ? PLF_LIST_BLOCK_MIN : + groups.initialize( ( number_of_elements < LIST_BLOCK_MIN ) ? LIST_BLOCK_MIN : static_cast( number_of_elements ) ); // Construct first group end_node.next = end_node.previous = last_endpoint = begin_iterator.node_pointer = groups.last_endpoint_group->nodes; @@ -1629,18 +1632,18 @@ template ( PLF_LIST_BLOCK_MAX ); - remainder -= multiples * PLF_LIST_BLOCK_MAX; + size_type multiples = remainder / static_cast( LIST_BLOCK_MAX ); + remainder -= multiples * LIST_BLOCK_MAX; while( multiples-- != 0 ) { - groups.add_new( PLF_LIST_BLOCK_MAX ); + groups.add_new( LIST_BLOCK_MAX ); last_endpoint = groups.last_endpoint_group->nodes; - group_fill_position( element, PLF_LIST_BLOCK_MAX, position.node_pointer ); + group_fill_position( element, LIST_BLOCK_MAX, position.node_pointer ); } if( remainder != 0 ) { // Bit annoying to create a large block to house a lower number of elements, but beats the alternatives - groups.add_new( PLF_LIST_BLOCK_MAX ); + groups.add_new( LIST_BLOCK_MAX ); last_endpoint = groups.last_endpoint_group->nodes; group_fill_position( element, static_cast( remainder ), position.node_pointer ); } @@ -1676,13 +1679,13 @@ template nodes; current_node != beyond_end_node; ++current_node ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, + LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, &( current_node->next ) ); // Destruct element - PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, + LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, &( current_node->previous ) ); // Destruct element } } @@ -1696,8 +1699,8 @@ template ::value ) ) { - PLF_LIST_DESTROY( element_allocator_type, ( *this ), + if LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { + LIST_DESTROY( element_allocator_type, ( *this ), &( it.node_pointer->element ) ); // Destruct element } @@ -1760,14 +1763,14 @@ template nodes ); node_allocator_pair.number_of_erased_nodes -= group_size; - if PLF_LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { + if LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { destroy_all_node_pointers( node_group, node_group->beyond_end ); } node_group->free_list_head = NULL; // Preserve only last (active) group or second/third-to-last group - seems to be best for performance under high-modification benchmarks - if( ( group_size == PLF_LIST_BLOCK_MAX ) | ( node_group >= groups.last_endpoint_group - 1 ) ) { + if( ( group_size == LIST_BLOCK_MAX ) | ( node_group >= groups.last_endpoint_group - 1 ) ) { groups.move_to_back( node_group ); } else { groups.remove( node_group ); @@ -1775,7 +1778,7 @@ template ::value ) ) { + if LIST_CONSTEXPR( !( std::is_trivially_destructible::value ) ) { destroy_all_node_pointers( node_group, last_endpoint ); } @@ -1822,7 +1825,7 @@ template number_of_elements ) { // If there are erased nodes present in the group for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { if( current_node->next != NULL ) { // is not free list node - PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node ); } } } else { for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { - PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node ); } } @@ -1952,14 +1955,14 @@ template nodes; current_node != last_endpoint; ++current_node ) { if( current_node->next != NULL ) { - PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node ); } } } else { for( node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node ) { - PLF_LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, + LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, current_node ); } } @@ -1983,16 +1986,16 @@ template next = *( node_pointer + 1 ); ( *node_pointer )->previous = *( node_pointer - 1 ); - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer - 1 ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer - 1 ); } } - if PLF_LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { - PLF_LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, back ); + if LIST_CONSTEXPR( !std::is_trivially_destructible::value ) { + LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, back ); } - PLF_LIST_DEALLOCATE( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointers, + LIST_DEALLOCATE( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointers, node_pointer_allocator_pair.total_number_of_elements ); } @@ -2022,8 +2025,8 @@ template max_size() ) { reserve_amount = max_size(); } @@ -2034,12 +2037,12 @@ template beyond_end - ( groups.block_pointer + groups.size - 1 )->nodes ); // if last group isn't large enough, remove all groups - if( reserve_amount > end_group_size && end_group_size != PLF_LIST_BLOCK_MAX ) { + if( reserve_amount > end_group_size && end_group_size != LIST_BLOCK_MAX ) { reset(); } else { - size_type number_of_full_groups_needed = reserve_amount / PLF_LIST_BLOCK_MAX; + size_type number_of_full_groups_needed = reserve_amount / LIST_BLOCK_MAX; group_size_type remainder = static_cast( reserve_amount - - ( number_of_full_groups_needed * PLF_LIST_BLOCK_MAX ) ); + ( number_of_full_groups_needed * LIST_BLOCK_MAX ) ); // Remove any max_size groups which're not needed and any groups that're smaller than remainder: for( group_pointer_type current_group = groups.block_pointer; @@ -2047,7 +2050,7 @@ template ( groups.block_pointer->beyond_end - groups.block_pointer->nodes ); - if( number_of_full_groups_needed != 0 && current_group_size == PLF_LIST_BLOCK_MAX ) { + if( number_of_full_groups_needed != 0 && current_group_size == LIST_BLOCK_MAX ) { --number_of_full_groups_needed; ++current_group; } else if( remainder != 0 && current_group_size >= remainder ) { @@ -2068,16 +2071,16 @@ template ( ( ( reserve_amount < PLF_LIST_BLOCK_MIN ) ? - PLF_LIST_BLOCK_MIN : reserve_amount ) ) ); + groups.initialize( static_cast( ( ( reserve_amount < LIST_BLOCK_MIN ) ? + LIST_BLOCK_MIN : reserve_amount ) ) ); } else { - groups.initialize( PLF_LIST_BLOCK_MAX ); + groups.initialize( LIST_BLOCK_MAX ); --number_of_full_groups; } } else if( reserve_amount != 0 ) { @@ -2089,13 +2092,13 @@ template ::value && + if LIST_CONSTEXPR( std::is_move_assignable::value && std::is_move_constructible::value ) { // move elements if possible, otherwise copy them temp.insert( temp.end_iterator, std::make_move_iterator( begin_iterator ), std::make_move_iterator( end_iterator ) ); @@ -2435,7 +2438,7 @@ template inline void swap( list &a, - list &b ) PLF_LIST_NOEXCEPT_SWAP( + list &b ) LIST_NOEXCEPT_SWAP( swap_element_allocator_type ) { a.swap( b ); } -} // plf namespace +} // cata namespace -#undef PLF_LIST_BLOCK_MAX -#undef PLF_LIST_BLOCK_MIN +#undef LIST_BLOCK_MAX +#undef LIST_BLOCK_MIN -#undef PLF_LIST_FORCE_INLINE +#undef LIST_FORCE_INLINE -#undef PLF_LIST_CONSTEXPR -#undef PLF_LIST_NOEXCEPT_SWAP -#undef PLF_LIST_NOEXCEPT_MOVE_ASSIGNMENT +#undef LIST_CONSTEXPR +#undef LIST_NOEXCEPT_SWAP +#undef LIST_NOEXCEPT_MOVE_ASSIGNMENT -#undef PLF_LIST_CONSTRUCT -#undef PLF_LIST_DESTROY -#undef PLF_LIST_ALLOCATE -#undef PLF_LIST_ALLOCATE_INITIALIZATION -#undef PLF_LIST_DEALLOCATE +#undef LIST_CONSTRUCT +#undef LIST_DESTROY +#undef LIST_ALLOCATE +#undef LIST_ALLOCATE_INITIALIZATION +#undef LIST_DEALLOCATE -#endif // PLF_LIST_H +#endif // LIST_H From a55535cad182624c13f21b8948b02c0b7466961d Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Jul 2019 18:45:02 +0200 Subject: [PATCH 06/10] Replace typedefs with using --- src/list.h | 171 +++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 85 deletions(-) diff --git a/src/list.h b/src/list.h index 5383a1e163a35..9f5d5b79c68a9 100644 --- a/src/list.h +++ b/src/list.h @@ -68,27 +68,27 @@ template ::size_type size_type; - typedef typename std::allocator_traits::difference_type difference_type; - typedef element_type &reference; - typedef const element_type &const_reference; - typedef typename std::allocator_traits::pointer pointer; - typedef typename std::allocator_traits::const_pointer const_pointer; + using size_type = typename std::allocator_traits::size_type; + using difference_type = typename std::allocator_traits::difference_type; + using reference = element_type&; + using const_reference = const element_type&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; // Iterator declarations: template class list_iterator; - typedef list_iterator iterator; - typedef list_iterator const_iterator; + using iterator = list_iterator; + using const_iterator = list_iterator; friend class list_iterator; // Using 'iterator' typedef name here is illegal under C++03 friend class list_iterator; template class list_reverse_iterator; - typedef list_reverse_iterator reverse_iterator; - typedef list_reverse_iterator const_reverse_iterator; + using reverse_iterator = list_reverse_iterator; + using const_reverse_iterator = list_reverse_iterator; friend class list_reverse_iterator; friend class list_reverse_iterator; @@ -96,16 +96,14 @@ template ::template rebind_alloc - group_allocator_type; - typedef typename std::allocator_traits::template rebind_alloc - node_allocator_type; - typedef typename std::allocator_traits::pointer - group_pointer_type; - typedef typename std::allocator_traits::pointer - node_pointer_type; - typedef typename std::allocator_traits::template - rebind_alloc node_pointer_allocator_type; + using group_allocator_type = typename std::allocator_traits::template + rebind_alloc; + using node_allocator_type = typename std::allocator_traits::template + rebind_alloc; + using group_pointer_type = typename std::allocator_traits::pointer; + using node_pointer_type = typename std::allocator_traits::pointer; + using node_pointer_allocator_type = typename std::allocator_traits::template + rebind_alloc; struct node_base { node_pointer_type next, previous; @@ -196,7 +194,7 @@ template ( beyond_end - nodes ) ); + static_cast( beyond_end - nodes ) ); } }; @@ -276,7 +274,7 @@ template ::value || - !std::is_trivially_destructible::value ) { + !std::is_trivially_destructible::value ) { clear( last_endpoint_node ); // If clear has already been called, last_endpoint_node will already be == block_pointer->nodes, so no work will occur } @@ -287,7 +285,7 @@ template ::value || - !std::is_trivially_destructible::value ) { + !std::is_trivially_destructible::value ) { const node_pointer_type end = current_group->beyond_end; if( ( end - current_group->nodes ) != current_group->number_of_elements ) { @@ -331,8 +329,9 @@ template ::value || - !std::is_trivially_destructible::value ) { - if( ( last_endpoint_node - last_endpoint_group->nodes ) != last_endpoint_group->number_of_elements ) { + !std::is_trivially_destructible::value ) { + if( ( last_endpoint_node - last_endpoint_group->nodes ) != + last_endpoint_group->number_of_elements ) { // If there are erased nodes present in the group for( node_pointer_type current_node = last_endpoint_group->nodes; current_node != last_endpoint_node; ++current_node ) { @@ -373,10 +372,11 @@ template ::value && - std::is_trivially_destructible::value ) { + std::is_trivially_destructible::value ) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer // reinterpret_cast necessary to deal with GCC 8 warnings - std::memcpy( static_cast( &*block_pointer ), static_cast( &*old_block ), sizeof( group ) * size ); + std::memcpy( static_cast( &*block_pointer ), static_cast( &*old_block ), + sizeof( group ) * size ); } else if LIST_CONSTEXPR( std::is_move_constructible::value ) { std::uninitialized_copy( std::make_move_iterator( old_block ), std::make_move_iterator( old_block + size ), block_pointer ); @@ -397,7 +397,7 @@ template nodes ); + last_endpoint_group->nodes ); ++last_endpoint_group; // Doing this here instead of pre-construct to avoid need for a try-catch block element_allocator_pair.capacity += group_size; @@ -439,7 +439,7 @@ template ::value && - std::is_trivially_destructible::value ) { + std::is_trivially_destructible::value ) { // Dereferencing here in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memmove( static_cast( &*group_to_erase ), static_cast( &*group_to_erase + 1 ), sizeof( group ) * ( --size - static_cast( &*group_to_erase - &*block_pointer ) ) ); @@ -463,7 +463,7 @@ template ::value && - std::is_trivially_destructible::value ) { + std::is_trivially_destructible::value ) { std::memcpy( static_cast( &*temp_group ), static_cast( &*group_to_erase ), sizeof( group ) ); std::memmove( static_cast( &*group_to_erase ), static_cast( &*group_to_erase + 1 ), @@ -472,7 +472,7 @@ template ( &*temp_group ), sizeof( group ) ); } else if LIST_CONSTEXPR( std::is_move_constructible::value ) { LIST_CONSTRUCT( group_allocator_type, group_allocator_pair, temp_group, - std::move( *group_to_erase ) ); + std::move( *group_to_erase ) ); std::move( group_to_erase + 1, block_pointer + size, group_to_erase ); *( block_pointer + size - 1 ) = std::move( *temp_group ); @@ -503,7 +503,8 @@ template = last_searched_group->nodes && location_node < last_searched_group->beyond_end ) { + if( location_node >= last_searched_group->nodes && + location_node < last_searched_group->beyond_end ) { // if last_searched_group has previously-erased nodes if( last_searched_group->free_list_head != NULL ) { return last_searched_group; @@ -697,7 +698,7 @@ template ::value && - std::is_trivially_destructible::value ) { + std::is_trivially_destructible::value ) { // &* in order to deal with smart pointer situations ie. obtaining the raw pointer from the smart pointer std::memcpy( static_cast( &*block_pointer + size ), static_cast( &*source.block_pointer ), sizeof( group ) * source.size ); @@ -719,7 +720,7 @@ template struct choose; template struct choose { - typedef IsTrue type; + using type = IsTrue; }; template struct choose { - typedef IsFalse type; + using type = IsFalse; }; public: @@ -746,13 +747,12 @@ template ::type - pointer; - typedef typename choose::type - reference; + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename list::value_type; + using difference_type = typename list::difference_type; + using pointer = typename choose::; + using reference = typename + choose::; friend class list; @@ -850,13 +850,12 @@ template ::type - pointer; - typedef typename choose::type - reference; + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename list::value_type; + using difference_type = typename list::difference_type; + using pointer = typename choose::; + using reference = typename + choose::; friend class list; @@ -954,7 +953,7 @@ template struct plf_enable_if_c { - typedef T type; + using type = T; }; template @@ -1211,12 +1210,13 @@ template beyond_end ) { // ie. there are no reusable groups available at the back of group vector - if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - 1 ) { + if( static_cast( groups.last_endpoint_group - groups.block_pointer ) == groups.size - + 1 ) { groups.add_new( ( node_pointer_allocator_pair.total_number_of_elements < LIST_BLOCK_MAX ) ? static_cast( node_pointer_allocator_pair.total_number_of_elements ) : LIST_BLOCK_MAX ); @@ -1228,7 +1228,7 @@ template previous, element ); + it.node_pointer->previous, element ); ++( groups.last_endpoint_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; @@ -1248,7 +1248,7 @@ template free_list_head->previous; LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, - it.node_pointer->previous, element ); + it.node_pointer->previous, element ); node_group->free_list_head = previous; ++( node_group->number_of_elements ); @@ -1278,11 +1278,11 @@ template ::value ) { // Avoid try-catch code generation LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, - end_iterator.node_pointer, end_iterator.node_pointer, element ); + end_iterator.node_pointer, end_iterator.node_pointer, element ); } else { try { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, - end_iterator.node_pointer, end_iterator.node_pointer, element ); + end_iterator.node_pointer, end_iterator.node_pointer, element ); } catch( ... ) { reset(); throw; @@ -1319,7 +1319,7 @@ template previous, std::move( element ) ); + it.node_pointer->previous, std::move( element ) ); ++( groups.last_endpoint_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; @@ -1339,7 +1339,7 @@ template free_list_head->previous; LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, - it.node_pointer->previous, std::move( element ) ); + it.node_pointer->previous, std::move( element ) ); node_group->free_list_head = previous; ++( node_group->number_of_elements ); @@ -1367,12 +1367,12 @@ template ::value ) { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, - end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); + end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); } else { try { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, - end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); + end_iterator.node_pointer, end_iterator.node_pointer, std::move( element ) ); } catch( ... ) { reset(); throw; @@ -1410,7 +1410,7 @@ template previous, std::forward( parameters )... ); + it.node_pointer->previous, std::forward( parameters )... ); ++( groups.last_endpoint_group->number_of_elements ); ++node_pointer_allocator_pair.total_number_of_elements; @@ -1430,7 +1430,7 @@ template free_list_head->previous; LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, selected_node, it.node_pointer, - it.node_pointer->previous, std::forward( parameters )... ); + it.node_pointer->previous, std::forward( parameters )... ); node_group->free_list_head = previous; ++( node_group->number_of_elements ); @@ -1458,11 +1458,11 @@ template ::value ) { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, - end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); + end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); } else { try { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint++, - end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); + end_iterator.node_pointer, end_iterator.node_pointer, std::forward( parameters )... ); } catch( ... ) { reset(); throw; @@ -1495,11 +1495,11 @@ template ::value ) { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, - previous, element ); + previous, element ); } else { try { LIST_CONSTRUCT( node_allocator_type, node_allocator_pair, last_endpoint, last_endpoint + 1, - previous, element ); + previous, element ); } catch( ... ) { previous->next = position; position->previous = --previous; @@ -1671,8 +1671,8 @@ template &element_list ) - { + inline iterator insert( const iterator it, + const std::initializer_list &element_list ) { // use range insert: return insert( it, element_list.begin(), element_list.end() ); } @@ -1684,9 +1684,9 @@ template nodes; current_node != beyond_end_node; ++current_node ) { LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, - &( current_node->next ) ); // Destruct element + &( current_node->next ) ); // Destruct element LIST_DESTROY( node_pointer_allocator_type, node_pointer_allocator_pair, - &( current_node->previous ) ); // Destruct element + &( current_node->previous ) ); // Destruct element } } @@ -1701,7 +1701,7 @@ template ::value ) ) { LIST_DESTROY( element_allocator_type, ( *this ), - &( it.node_pointer->element ) ); // Destruct element + &( it.node_pointer->element ) ); // Destruct element } --node_pointer_allocator_pair.total_number_of_elements; @@ -1750,7 +1750,7 @@ template next ); - // ie. group is not empty yet, add node to free list + // ie. group is not empty yet, add node to free list if( --( node_group->number_of_elements ) != 0 ) { // next == NULL so that destructor can detect the free list item as opposed to non-free-list item it.node_pointer->next = NULL; @@ -1939,13 +1939,13 @@ template nodes; current_node != end; ++current_node ) { if( current_node->next != NULL ) { // is not free list node LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, - current_node ); + current_node ); } } } else { for( node_pointer_type current_node = current_group->nodes; current_node != end; ++current_node ) { LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, - current_node ); + current_node ); } } } @@ -1956,14 +1956,14 @@ template next != NULL ) { LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, - current_node ); + current_node ); } } } else { for( node_pointer_type current_node = groups.last_endpoint_group->nodes; current_node != last_endpoint; ++current_node ) { LIST_CONSTRUCT( node_pointer_allocator_type, node_pointer_allocator_pair, node_pointer++, - current_node ); + current_node ); } } @@ -1977,7 +1977,8 @@ template next = end_iterator.node_pointer; - end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - 2]; + end_node.previous->previous = node_pointers[node_pointer_allocator_pair.total_number_of_elements - + 2]; node_pointer_type *const back = node_pointers + node_pointer_allocator_pair.total_number_of_elements - 1; @@ -1996,7 +1997,7 @@ template ::value && - std::is_move_constructible::value ) { // move elements if possible, otherwise copy them + std::is_move_constructible::value ) { // move elements if possible, otherwise copy them temp.insert( temp.end_iterator, std::make_move_iterator( begin_iterator ), std::make_move_iterator( end_iterator ) ); } else { From 776aee6f9fe973d9416ad8b25b1cb1bfee147457 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 6 Jul 2019 19:30:45 +0200 Subject: [PATCH 07/10] Fix a couple typos --- src/list.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/list.h b/src/list.h index 9f5d5b79c68a9..9470f162af3ed 100644 --- a/src/list.h +++ b/src/list.h @@ -750,9 +750,10 @@ template ::; + using pointer = typename + choose::type; using reference = typename - choose::; + choose::type; friend class list; @@ -853,9 +854,10 @@ template ::; + using pointer = typename + choose::type; using reference = typename - choose::; + choose::type; friend class list; @@ -964,8 +966,8 @@ template Date: Sun, 7 Jul 2019 00:01:07 +0200 Subject: [PATCH 08/10] Add list test cases --- tests/colony_test.cpp | 16 +- tests/list_test.cpp | 1218 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1226 insertions(+), 8 deletions(-) create mode 100644 tests/list_test.cpp diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index 54692288cd9ef..af1f5f87899d1 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -267,7 +267,7 @@ TEST_CASE( "colony basics", "[colony]" ) CHECK( test_colony_2.max_size() > test_colony_2.size() ); } -TEST_CASE( "insert and erase", "[colony]" ) +TEST_CASE( "colony insert and erase", "[colony]" ) { cata::colony test_colony; @@ -504,7 +504,7 @@ TEST_CASE( "insert and erase", "[colony]" ) CHECK( test_colony.size() == static_cast( count ) ); } -TEST_CASE( "range erase", "[colony]" ) +TEST_CASE( "colony range erase", "[colony]" ) { cata::colony test_colony; @@ -763,7 +763,7 @@ TEST_CASE( "range erase", "[colony]" ) CHECK( test_colony.size() == 10 ); } -TEST_CASE( "sort", "[colony]" ) +TEST_CASE( "colony sort", "[colony]" ) { cata::colony test_colony; @@ -805,7 +805,7 @@ TEST_CASE( "sort", "[colony]" ) CHECK( sorted ); } -TEST_CASE( "insertion methods", "[colony]" ) +TEST_CASE( "colony insertion methods", "[colony]" ) { cata::colony test_colony = {1, 2, 3}; @@ -900,7 +900,7 @@ struct perfect_forwarding_test { {} }; -TEST_CASE( "perfect forwarding", "[colony]" ) +TEST_CASE( "colony perfect forwarding", "[colony]" ) { cata::colony test_colony; @@ -925,7 +925,7 @@ struct small_struct { number( num ) {}; }; -TEST_CASE( "emplace", "[colony]" ) +TEST_CASE( "colony emplace", "[colony]" ) { cata::colony test_colony; int sum1 = 0, sum2 = 0; @@ -945,7 +945,7 @@ TEST_CASE( "emplace", "[colony]" ) CHECK( test_colony.size() == 100 ); } -TEST_CASE( "group size and capacity", "[colony]" ) +TEST_CASE( "colony group size and capacity", "[colony]" ) { cata::colony test_colony; test_colony.change_group_sizes( 50, 100 ); @@ -988,7 +988,7 @@ TEST_CASE( "group size and capacity", "[colony]" ) CHECK( test_colony.capacity() == 3400 ); } -TEST_CASE( "splice", "[colony]" ) +TEST_CASE( "colony splice", "[colony]" ) { cata::colony test_colony_1, test_colony_2; diff --git a/tests/list_test.cpp b/tests/list_test.cpp new file mode 100644 index 0000000000000..c64c2172377ab --- /dev/null +++ b/tests/list_test.cpp @@ -0,0 +1,1218 @@ +#include // std::find +#include // log redirection +#include // abort +#include // std::greater +#include // std::move +#include // range-insert testing + +#include "catch/catch.hpp" +#include "list.h" + +// Fast xorshift+128 random number generator function +// original: https://codingforspeed.com/using-faster-psudo-random-generator-xorshift/ +static unsigned int xor_rand() +{ + static unsigned int x = 123456789; + static unsigned int y = 362436069; + static unsigned int z = 521288629; + static unsigned int w = 88675123; + + const unsigned int t = x ^ ( x << 11 ); + + // Rotate the static values (w rotation in return statement): + x = y; + y = z; + z = w; + + return w = w ^ ( w >> 19 ) ^ ( t ^ ( t >> 8 ) ); +} + +struct small_struct { + double *empty_field_1; + double unused_number; + unsigned int empty_field2; + double *empty_field_3; + int number; + unsigned int empty_field4; + + small_struct( const int num ) noexcept: number( num ) {}; +}; + +struct perfect_forwarding_test { + const bool success; + + perfect_forwarding_test( int && /*perfect1*/, int &perfect2 ) : success( true ) { + perfect2 = 1; + } + + template + perfect_forwarding_test( T && /*imperfect1*/, U && /*imperfect2*/ ) : success( false ) + {} +}; + +TEST_CASE( "list basics", "[list]" ) +{ + { + cata::list test_list; + int ten = 10; + int twenty = 20; + + SECTION( "empty()" ) { + CHECK( test_list.empty() ); + + test_list.push_front( &ten ); + + CHECK( !test_list.empty() ); + } + + SECTION( "begin() and end()" ) { + test_list.push_front( &ten ); + + CHECK( **test_list.begin() == 10 ); + CHECK_FALSE( test_list.begin() == test_list.end() ); + + test_list.clear(); + + CHECK( test_list.begin() == test_list.end() ); + } + + for( int i = 0; i < 200; i++ ) { + test_list.push_back( &ten ); + test_list.push_back( &twenty ); + } + + SECTION( "iterator count/access" ) { + int count = 0; + int sum = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); + ++it ) { + ++count; + sum += **it; + } + + CHECK( count == 400 ); + CHECK( sum == 6000 ); + } + + SECTION( "iterator distance" ) { + cata::list::iterator plus_twenty = test_list.begin(); + std::advance( plus_twenty, 20 ); + + cata::list::iterator plus_two_hundred = test_list.begin(); + std::advance( plus_two_hundred, 200 ); + + CHECK( std::distance( test_list.begin(), plus_twenty ) == 20 ); + CHECK( std::distance( test_list.begin(), plus_two_hundred ) == 200 ); + } + + SECTION( "iterator next/prev" ) { + cata::list::iterator next_iterator = std::next( test_list.begin(), 5 ); + cata::list::const_iterator prev_iterator = std::prev( test_list.cend(), 300 ); + + CHECK( std::distance( test_list.begin(), next_iterator ) == 5 ); + CHECK( std::distance( prev_iterator, test_list.cend() ) == 300 ); + } + + SECTION( "iterator/const_iterator equality" ) { + cata::list::const_iterator prev_iterator = std::prev( test_list.cend(), 300 ); + cata::list::iterator prev_iterator2 = std::prev( test_list.end(), 300 ); + + CHECK( prev_iterator == prev_iterator2 ); + } + + SECTION( "copy, equality, and inequality" ) { + cata::list test_list_2; + test_list_2 = test_list; + cata::list test_list_3( test_list ); + cata::list test_list_4( test_list_2, test_list_2.get_allocator() ); + + cata::list::iterator it1 = test_list.begin(); + cata::list::const_iterator cit( it1 ); + + CHECK( test_list_2.size() == 400 ); + CHECK( test_list_3.size() == 400 ); + CHECK( test_list_4.size() == 400 ); + + CHECK( test_list == test_list_2 ); + CHECK( test_list_2 == test_list_3 ); + + test_list_2.push_back( &ten ); + + CHECK( test_list_2 != test_list_3 ); + } + + SECTION( "reverse iterator count/access" ) { + int count = 0; + int sum = 0; + for( cata::list::reverse_iterator it = test_list.rbegin(); + it != test_list.rend(); ++it ) { + ++count; + sum += **it; + } + + CHECK( count == 400 ); + CHECK( sum == 6000 ); + } + + SECTION( "reverse iterator advance, next, and distance" ) { + cata::list::reverse_iterator r_iterator = test_list.rbegin(); + std::advance( r_iterator, 50 ); + + CHECK( std::distance( test_list.rbegin(), r_iterator ) == 50 ); + + cata::list::reverse_iterator r_iterator2 = std::next( r_iterator, 2 ); + + CHECK( std::distance( test_list.rbegin(), r_iterator2 ) == 52 ); + } + + + SECTION( "multiple iteration" ) { + int count = 0; + int sum = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); + std::advance( it, 2 ) ) { + ++count; + sum += **it; + } + + CHECK( count == 200 ); + CHECK( sum == 2000 ); + } + + SECTION( "reverse iterator count/access" ) { + int count = 0; + int sum = 0; + for( cata::list::const_iterator it = test_list.cbegin(); + it != test_list.cend(); ++it ) { + ++count; + sum += **it; + } + + CHECK( count == 400 ); + CHECK( sum == 6000 ); + } + + SECTION( "reverse iterator count/access" ) { + int count = 0; + int sum = 0; + for( cata::list::const_reverse_iterator it = test_list.crbegin(); + it != test_list.crend(); ++it ) { + ++count; + sum += **it; + } + + CHECK( count == 400 ); + CHECK( sum == 6000 ); + } + + SECTION( "post erase iteration and shrink to fit" ) { + int count = 0; + for( cata::list::iterator it = std::next( test_list.begin() ); + it != test_list.end(); ++it ) { + ++count; + it = test_list.erase( it ); + + if( it == test_list.end() ) { + break; + } + } + + CHECK( count == 200 ); + CHECK( test_list.size() == 200 ); + + const size_t prev_capacity = test_list.capacity(); + test_list.shrink_to_fit(); + + CHECK( test_list.capacity() < prev_capacity ); + CHECK( test_list.capacity() == 200 ); + + count = 0; + for( cata::list::reverse_iterator it = test_list.rbegin(); + it != test_list.rend(); ) { + ++it; + cata::list::iterator it2 = it.base(); // grabs it--, essentially + test_list.erase( it2 ); + ++count; + } + + CHECK( count == 200 ); + CHECK( test_list.size() == 0 ); + } + + SECTION( "negative iteration" ) { + int count = 0; + for( cata::list::iterator it = std::prev( test_list.end() ); + it != test_list.begin(); --it ) { + ++count; + } + + CHECK( count == 399 ); + } + + SECTION( "negative multiple iteration" ) { + int count = 0; + for( cata::list::iterator it = std::prev( test_list.end() ); + it != test_list.begin() && + it != std::next( test_list.begin() ); std::advance( it, -2 ) ) { + ++count; + } + + CHECK( count == 199 ); + } + + SECTION( "move" ) { + cata::list test_list_2; + test_list_2 = std::move( test_list ); + + CHECK( test_list_2.size() == 400 ); + + cata::list test_list_3( test_list_2 ); + cata::list test_list_4( std::move( test_list_3 ), test_list_2.get_allocator() ); + + CHECK( test_list_4.size() == 400 ); + } + + SECTION( "swap() and max_size()" ) { + cata::list test_list_2; + test_list_2 = test_list; + + CHECK( test_list_2.size() == 400 ); + + test_list.push_back( &ten ); + + test_list.swap( test_list_2 ); + + CHECK( test_list.size() == test_list_2.size() - 1 ); + + swap( test_list, test_list_2 ); + + CHECK( test_list_2.size() == test_list.size() - 1 ); + + CHECK( test_list_2.max_size() > test_list_2.size() ); + } + } +} + +TEST_CASE( "list insert and erase" ) +{ + cata::list test_list; + + for( int i = 0; i < 500000; i++ ) { + test_list.push_back( i ); + } + + SECTION( "size after insert" ) { + CHECK( test_list.size() == 500000 ); + } + + SECTION( "find iterator" ) { + cata::list::iterator found_item = std::find( test_list.begin(), test_list.end(), 5000 ); + + CHECK( *found_item == 5000 ); + } + + SECTION( "find reverse iterator" ) { + cata::list::reverse_iterator found_item2 = std::find( test_list.rbegin(), test_list.rend(), + 5000 ); + + CHECK( *found_item2 == 5000 ); + } + + SECTION( "erase alternating/randomly" ) { + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); + ++it ) { + it = test_list.erase( it ); + } + + CHECK( test_list.size() == 250000 ); + + do { + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ) { + if( ( xor_rand() & 7 ) == 0 ) { + it = test_list.erase( it ); + } else { + ++it; + } + } + + } while( !test_list.empty() ); + + CHECK( test_list.size() == 0 ); + } + + SECTION( "erase randomly till half empty" ) { + int count = 0; + do { + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ) { + if( ( xor_rand() & 7 ) == 0 ) { + it = test_list.erase( it ); + ++count; + } else { + ++it; + } + } + + } while( count < 250000 ); + + CHECK( test_list.size() == 500000 - count ); + + for( int i = 0; i < count; i++ ) { + test_list.push_front( 1 ); + } + + CHECK( test_list.size() == 500000 ); + } + + SECTION( "alternating insert/erase" ) { + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ) { + if( ++count == 5 ) { + count = 0; + it = test_list.erase( it ); + } else { + test_list.insert( it, 1 ); + ++it; + } + } + + CHECK( test_list.size() == 800000 ); + } + + test_list.clear(); + for( int i = 0; i < 500000; i++ ) { + test_list.push_back( 1 ); + } + + SECTION( "large multi increment erasure" ) { + cata::list::iterator it = test_list.begin(); + std::advance( it, 250000 ); + + for( ; it != test_list.end(); ) { + it = test_list.erase( it ); + } + + CHECK( test_list.size() == 250000 ); + + SECTION( "re-insert post heavy erasure" ) { + for( int i = 0; i < 250000; i++ ) { + test_list.push_front( 1 ); + } + + int sum = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); + ++it ) { + sum += *it; + } + + CHECK( sum == 500000 ); + } + } + + SECTION( "large multi decrement erasure" ) { + cata::list::iterator end_iterator = test_list.end(); + std::advance( end_iterator, -250000 ); + + for( cata::list::iterator it = test_list.begin(); it != end_iterator; ) { + it = test_list.erase( it ); + } + + CHECK( test_list.size() == 250000 ); + + SECTION( "re-insert post heavy erasure" ) { + for( int i = 0; i < 250000; i++ ) { + test_list.push_front( 1 ); + } + + int sum = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); + ++it ) { + sum += *it; + } + + CHECK( sum == 500000 ); + } + } + + SECTION( "erase from middle" ) { + cata::list::iterator end_iterator = test_list.end(); + std::advance( end_iterator, -50001 ); + cata::list::iterator begin_iterator = test_list.begin(); + std::advance( begin_iterator, 300000 ); + + for( cata::list::iterator it = begin_iterator; it != end_iterator; ) { + it = test_list.erase( it ); + } + + CHECK( test_list.size() == 350001 ); + } + + SECTION( "total erase edge case" ) { + cata::list::iterator temp_iterator = test_list.begin(); + std::advance( temp_iterator, 2 ); // Advance test 1 + + test_list.erase( temp_iterator ); + // Check edge-case with advance when erasures present in initial group + temp_iterator = test_list.begin(); + std::advance( temp_iterator, 500 ); + + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ) { + it = test_list.erase( it ); + } + + CHECK( test_list.empty() ); + } + + SECTION( "multiple sequential small insert/erase" ) { + test_list.clear(); + test_list.shrink_to_fit(); + + const size_t prev_capacity = test_list.capacity(); + test_list.reserve( 1000 ); + + CHECK( prev_capacity != test_list.capacity() ); + CHECK( test_list.capacity() == 1000 ); + + int count = 0; + for( int loop1 = 0; loop1 < 50000; loop1++ ) { + for( int loop = 0; loop < 10; loop++ ) { + if( ( xor_rand() & 7 ) == 0 ) { + test_list.push_back( 1 ); + ++count; + } + } + + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ) { + if( ( xor_rand() & 7 ) == 0 ) { + it = test_list.erase( it ); + --count; + } else { + ++it; + } + } + } + + CHECK( count == test_list.size() ); + } +} + +TEST_CASE( "list merge", "[list]" ) +{ + cata::list test_list; + test_list.insert( test_list.end(), {1, 3, 5, 7, 9} ); + cata::list test_list_2 = {2, 4, 6, 8, 10}; + + test_list.merge( test_list_2 ); + + bool passed = true; + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( ++count != *it ) { + passed = false; + break; + } + } + + CHECK( passed ); +} + +TEST_CASE( "list splice", "[list]" ) +{ + cata::list test_list = {1, 2, 3, 4, 5}; + cata::list test_list_2 = {6, 7, 8, 9, 10}; + + SECTION( "splice at end" ) { + test_list.splice( test_list.end(), test_list_2 ); + + bool passed = true; + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( ++count != *it ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + SECTION( "splice at begin" ) { + test_list.splice( test_list.begin(), test_list_2 ); + + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + count += *it; + } + + CHECK( count == 55 ); + } + + SECTION( "splice past middle" ) { + cata::list::iterator it2 = test_list.begin(); + std::advance( it2, 3 ); + + test_list.splice( it2, test_list_2 ); + + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + count += *it; + } + + test_list.clear(); + test_list_2.clear(); + + for( int i = 1; i < 25; i++ ) { + test_list.push_back( i ); + test_list_2.push_back( i + 25 ); + } + + cata::list::iterator it3 = test_list.begin(); + std::advance( it3, 18 ); + + test_list.splice( it3, test_list_2 ); + + count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + count += *it; + } + + CHECK( count == 1200 ); + } + + SECTION( "large splice" ) { + test_list.clear(); + test_list_2.clear(); + + for( int i = 5; i < 36; i++ ) { + test_list.push_back( i ); + test_list_2.push_front( i ); + } + + + test_list.splice( test_list.begin(), test_list_2 ); + + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + count += *it; + } + + CHECK( count == 1240 ); + } +} + +TEST_CASE( "list sort and reverse", "[list]" ) +{ + cata::list test_list; + + for( int i = 0; i < 500; ++i ) { + test_list.push_back( xor_rand() & 65535 ); + } + + SECTION( "less than (default)" ) { + test_list.sort(); + + bool passed = true; + int previous = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it < previous ) { + passed = false; + break; + } + previous = *it; + } + + CHECK( passed ); + } + + SECTION( "greater than (predicate)" ) { + test_list.sort( std::greater() ); + + bool passed = true; + int previous = 65535; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it > previous ) { + passed = false; + break; + } + previous = *it; + } + + CHECK( passed ); + + SECTION( "reverse" ) { + test_list.reverse(); + + passed = true; + previous = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + + if( *it < previous ) { + passed = false; + break; + } + + previous = *it; + } + + CHECK( passed ); + } + } + + +} + +TEST_CASE( "list unique", "[list]" ) +{ + cata::list test_list = {1, 1, 2, 3, 3, 4, 5, 5}; + + SECTION( "control case" ) { + bool passed = true; + int previous = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it == previous ) { + passed = false; + } + + previous = *it; + } + + CHECK_FALSE( passed ); + } + + SECTION( "invoke unique" ) { + test_list.unique(); + + bool passed = true; + int previous = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it == previous ) { + passed = false; + break; + } + + previous = *it; + } + + CHECK( passed ); + } +} + +TEST_CASE( "list remove", "[list]" ) +{ + cata::list test_list = {1, 3, 1, 50, 16, 15, 2, 22}; + + SECTION( "remove_if()" ) { + test_list.remove_if( []( int value ) { + return value > 15; + } ); + + bool passed = true; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it > 15 ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + SECTION( "remove()" ) { + test_list.remove( 1 ); + + bool passed = true; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it == 1 ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + SECTION( "remove() till empty" ) { + test_list.remove( 1 ); + test_list.remove( 22 ); + test_list.remove( 15 ); + test_list.remove( 16 ); + test_list.remove( 3 ); + test_list.remove( 50 ); + test_list.remove( 2 ); + + CHECK( test_list.empty() ); + } +} + +TEST_CASE( "list reserve", "[list]" ) +{ + cata::list test_list; + + test_list.reserve( 4097 ); + + CHECK( test_list.capacity() >= 4097 ); + + test_list.push_back( 15 ); + + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + ++count; + } + + CHECK( test_list.size() == static_cast( count ) ); + + test_list.insert( test_list.end(), 10000, 15 ); + + count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + ++count; + } + + CHECK( test_list.size() == 10001 ); + CHECK( count == 10001 ); + CHECK( test_list.capacity() >= 10001 ); + + test_list.reserve( 15000 ); + + CHECK( test_list.capacity() >= 15000 ); +} + +TEST_CASE( "list resize", "[list]" ) +{ + cata::list test_list = { 1, 2, 3, 4, 5, 6, 7 }; + + test_list.resize( 2 ); + + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + ++count; + } + + CHECK( test_list.size() == 2 ); + CHECK( count == 2 ); +} + +TEST_CASE( "list assign", "[list]" ) +{ + cata::list test_list; + + SECTION( "range assign" ) { + std::vector test_vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + test_list.assign( test_vector.begin(), test_vector.end() ); + + bool passed = true; + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( ++count != *it ) { + passed = false; + break; + } + } + + CHECK( test_list.size() == 10 ); + CHECK( count == 10 ); + CHECK( passed ); + } + + SECTION( "fill assign" ) { + test_list.assign( 20, 1 ); + + bool passed = true; + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( *it != 1 ) { + passed = false; + break; + } + ++count; + } + + CHECK( test_list.size() == 20 ); + CHECK( count == 20 ); + CHECK( passed ); + } + + SECTION( "initializer list assign" ) { + std::initializer_list inlist = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + + test_list.assign( inlist ); + + bool passed = true; + int count = 11; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( --count != *it ) { + passed = false; + break; + } + } + + CHECK( test_list.size() == 10 ); + CHECK( count == 1 ); + CHECK( passed ); + } +} + +TEST_CASE( "list insert", "[list]" ) +{ + cata::list test_list; + + std::vector test_vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_list.insert( test_list.end(), test_vector.begin(), test_vector.end() ); + + SECTION( "range insert" ) { + + bool passed = true; + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( ++count != *it ) { + passed = false; + } + } + + CHECK( passed ); + } + + test_list.insert( test_list.begin(), 50, 50000 ); + + SECTION( "fill insert" ) { + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + ++count; + } + + CHECK( count == 60 ); + CHECK( test_list.size() == 60 ); + } + + SECTION( "erase/insert randomly til empty" ) { + while( !test_list.empty() ) { + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ) { + if( ( xor_rand() & 15 ) == 0 ) { + test_list.insert( it, 13 ); + } + + if( ( xor_rand() & 7 ) == 0 ) { + it = test_list.erase( it ); + } else { + ++it; + } + } + } + + CHECK( test_list.empty() ); + } +} + +TEST_CASE( "list emplace, move, copy, and reverse iterate", "[list]" ) +{ + cata::list test_list; + + for( int counter = 0; counter < 254; counter++ ) { + test_list.emplace_back( counter ); + } + + SECTION( "emplace_back() success" ) { + bool passed = true; + int count = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( count++ != it->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + SECTION( "emplace_back() return value" ) { + small_struct &temp = test_list.emplace_back( 254 ); + CHECK( temp.number == 254 ); + } + + SECTION( "reverse iteration" ) { + bool passed = true; + int count = 254; + for( cata::list::reverse_iterator rit = test_list.rbegin(); + rit != test_list.rend(); ++rit ) { + if( --count != rit->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + for( int counter = -1; counter != -255; --counter ) { + test_list.emplace_front( counter ); + } + + SECTION( "emplace_front()" ) { + bool passed = true; + int count = -255; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + if( ++count != it->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + SECTION( "emplace_front() return value" ) { + small_struct &temp = test_list.emplace_front( -255 ); + CHECK( temp.number == -255 ); + } + + SECTION( "reverse iteration 2" ) { + bool passed = true; + int count = 254; + for( cata::list::reverse_iterator rit = test_list.rbegin(); + rit != test_list.rend(); ++rit ) { + if( --count != rit->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + cata::list test_list_2( std::move( test_list ) ); + + SECTION( "move constructor" ) { + bool passed = true; + int count = 254; + for( cata::list::reverse_iterator rit = test_list_2.rbegin(); + rit != test_list_2.rend(); ++rit ) { + if( --count != rit->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + CHECK( test_list.empty() ); + } + + SECTION( "emplace post-moved list" ) { + // Reuse the moved list will cause segmentation fault + test_list.emplace_back( 3 ); + CHECK( test_list.size() == 1 ); + } + + test_list = std::move( test_list_2 ); + + SECTION( "move assignment" ) { + bool passed = true; + int count = 254; + for( cata::list::reverse_iterator rit = test_list.rbegin(); + rit != test_list.rend(); ++rit ) { + if( --count != rit->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + CHECK( test_list_2.empty() ); + } + + SECTION( "copy assignment" ) { + test_list_2 = test_list; + + bool passed = true; + int count = 254; + for( cata::list::reverse_iterator rit = test_list_2.rbegin(); + rit != test_list_2.rend(); + ++rit ) { + if( --count != rit->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + } + + SECTION( "copy constructor" ) { + cata::list list3( test_list ); + + bool passed = true; + int count = 254; + for( cata::list::reverse_iterator rit = list3.rbegin(); + rit != list3.rend(); ++rit ) { + if( --count != rit->number ) { + passed = false; + break; + } + } + + CHECK( passed ); + } +} + +TEST_CASE( "list reorder", "[list]" ) +{ + cata::list test_list; + + for( int i = 0; i < 255; ++i ) { + test_list.push_back( i ); + } + + // Used for the post reorder data consistency test + int original_sum = 0; + for( cata::list::iterator it = test_list.begin(); it != test_list.end(); ++it ) { + original_sum += *it; + } + + cata::list::iterator it1 = test_list.begin(); + cata::list::iterator it2 = test_list.begin(); + cata::list::iterator it3 = test_list.begin(); + + std::advance( it1, 25 ); + std::advance( it2, 5 ); + + test_list.reorder( it2, it1 ); + + it1 = test_list.begin(); + std::advance( it1, 5 ); + + SECTION( "single reorder" ) { + CHECK( *it1 == 25 ); + } + + + it1 = test_list.begin(); + std::advance( it1, 152 ); + + test_list.reorder( test_list.begin(), it1 ); + + SECTION( "single reorder to begin" ) { + CHECK( test_list.front() == 152 ); + } + + test_list.reorder( test_list.end(), it2 ); + + SECTION( "single reorder to end" ) { + it1 = std::prev( test_list.end() ); + CHECK( *it1 == 5 ); + } + + it1 = test_list.begin(); + it2 = test_list.begin(); + + std::advance( it1, 50 ); + std::advance( it2, 60 ); + std::advance( it3, 70 ); + + test_list.reorder( it3, it1, it2 ); + + SECTION( "range reorder" ) { + it3 = test_list.begin(); + std::advance( it3, 60 ); + + bool passed = true; + for( int test = 50; test < 60; test++ ) { + if( *it3 != test ) { + passed = false; + } + ++it3; + } + + CHECK( passed == true ); + } + + it1 = test_list.begin(); + it2 = test_list.begin(); + + std::advance( it1, 80 ); + std::advance( it2, 120 ); + + test_list.reorder( test_list.end(), it1, it2 ); + + SECTION( "range reorer to end" ) { + it3 = test_list.end(); + std::advance( it3, -41 ); + + bool passed = true; + for( int test = 80; test < 120; test++ ) { + if( *it3 != test ) { + passed = false; + } + ++it3; + } + + CHECK( passed == true ); + } + + it1 = test_list.begin(); + it2 = test_list.begin(); + + std::advance( it1, 40 ); + std::advance( it2, 45 ); + + test_list.reorder( test_list.begin(), it1, it2 ); + + SECTION( "range reorder to begin" ) { + it3 = test_list.begin(); + + bool passed = true; + for( int test = 40; test < 45; test++ ) { + if( *it3 != test ) { + passed = false; + } + ++it3; + } + + CHECK( passed == true ); + } + + SECTION( "post reorder data consistency" ) { + int sum = 0; + for( it1 = test_list.begin(); it1 != test_list.end(); ++it1 ) { + sum += *it1; + } + + CHECK( sum == original_sum ); + } +} + +TEST_CASE( "list insertion styles", "[list]" ) +{ + cata::list test_list = {1, 2, 3}; + + CHECK( test_list.size() == 3 ); + + cata::list test_list_2( test_list.begin(), test_list.end() ); + + CHECK( test_list_2.size() == 3 ); + + cata::list test_list_3( 5000, 2 ); + + CHECK( test_list_3.size() == 5000 ); + + test_list_2.insert( test_list_2.end(), 500000, 5 ); + + CHECK( test_list_2.size() == 500003 ); + + std::vector some_ints( 500, 2 ); + + test_list_2.insert( test_list_2.begin(), some_ints.begin(), some_ints.end() ); + + CHECK( test_list_2.size() == 500503 ); +} + +TEST_CASE( "list perfect forwarding", "[list]" ) +{ + cata::list test_list; + + int lvalue = 0; + int &lvalueref = lvalue; + + test_list.emplace( test_list.end(), 7, lvalueref ); + + CHECK( ( *test_list.begin() ).success ); + CHECK( lvalueref == 1 ); +} From faa5eb15b85a694c1baff51919de16be888cfed9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 7 Jul 2019 14:55:46 +0200 Subject: [PATCH 09/10] Move colony and list test helpers to new header --- tests/colony_list_test_helpers.h | 47 ++++++++++++++++++++++++++++++++ tests/colony_test.cpp | 44 +----------------------------- tests/list_test.cpp | 46 ++----------------------------- 3 files changed, 50 insertions(+), 87 deletions(-) create mode 100644 tests/colony_list_test_helpers.h diff --git a/tests/colony_list_test_helpers.h b/tests/colony_list_test_helpers.h new file mode 100644 index 0000000000000..47644b9a63049 --- /dev/null +++ b/tests/colony_list_test_helpers.h @@ -0,0 +1,47 @@ +#pragma once +#ifndef COLONY_LIST_TEST_HELPERS_H +#define COLONY_LIST_TEST_HELPERS_H + +// Fast xorshift+128 random number generator function +// original: https://codingforspeed.com/using-faster-psudo-random-generator-xorshift/ +static unsigned int xor_rand() +{ + static unsigned int x = 123456789; + static unsigned int y = 362436069; + static unsigned int z = 521288629; + static unsigned int w = 88675123; + + const unsigned int t = x ^ ( x << 11 ); + + // Rotate the static values (w rotation in return statement): + x = y; + y = z; + z = w; + + return w = w ^ ( w >> 19 ) ^ ( t ^ ( t >> 8 ) ); +} + +struct small_struct { + double *empty_field_1; + double unused_number; + unsigned int empty_field2; + double *empty_field_3; + int number; + unsigned int empty_field4; + + small_struct( const int num ) noexcept: number( num ) {}; +}; + +struct perfect_forwarding_test { + const bool success; + + perfect_forwarding_test( int && /*perfect1*/, int &perfect2 ) : success( true ) { + perfect2 = 1; + } + + template + perfect_forwarding_test( T && /*imperfect1*/, U && /*imperfect2*/ ) : success( false ) + {} +}; + +#endif // COLONY_LIST_TEST_HELPERS_H diff --git a/tests/colony_test.cpp b/tests/colony_test.cpp index af1f5f87899d1..30a96008bfba5 100644 --- a/tests/colony_test.cpp +++ b/tests/colony_test.cpp @@ -6,25 +6,7 @@ #include "catch/catch.hpp" #include "colony.h" - -// Fast xorshift+128 random number generator function -// original: https://codingforspeed.com/using-faster-psudo-random-generator-xorshift/ -static unsigned int xor_rand() -{ - static unsigned int x = 123456789; - static unsigned int y = 362436069; - static unsigned int z = 521288629; - static unsigned int w = 88675123; - - const unsigned int t = x ^ ( x << 11 ); - - // Rotate the static values (w rotation in return statement): - x = y; - y = z; - z = w; - - return w = w ^ ( w >> 19 ) ^ ( t ^ ( t >> 8 ) ); -} +#include "colony_list_test_helpers.h" TEST_CASE( "colony basics", "[colony]" ) { @@ -888,18 +870,6 @@ TEST_CASE( "colony insertion methods", "[colony]" ) CHECK( sum == 12060 ); } -struct perfect_forwarding_test { - const bool success; - - perfect_forwarding_test( int && /*perfect1*/, int &perfect2 ) : success( true ) { - perfect2 = 1; - } - - template - perfect_forwarding_test( T && /*imperfect1*/, U && /*imperfect2*/ ) : success( false ) - {} -}; - TEST_CASE( "colony perfect forwarding", "[colony]" ) { cata::colony test_colony; @@ -913,18 +883,6 @@ TEST_CASE( "colony perfect forwarding", "[colony]" ) CHECK( lvalueref == 1 ); } -struct small_struct { - double *empty_field_1; - double unused_number; - unsigned int empty_field2; - double *empty_field_3; - int number; - unsigned int empty_field4; - - small_struct( const int num ) noexcept: - number( num ) {}; -}; - TEST_CASE( "colony emplace", "[colony]" ) { cata::colony test_colony; diff --git a/tests/list_test.cpp b/tests/list_test.cpp index c64c2172377ab..4890ddda09579 100644 --- a/tests/list_test.cpp +++ b/tests/list_test.cpp @@ -6,49 +6,9 @@ #include // range-insert testing #include "catch/catch.hpp" +#include "colony_list_test_helpers.h" #include "list.h" -// Fast xorshift+128 random number generator function -// original: https://codingforspeed.com/using-faster-psudo-random-generator-xorshift/ -static unsigned int xor_rand() -{ - static unsigned int x = 123456789; - static unsigned int y = 362436069; - static unsigned int z = 521288629; - static unsigned int w = 88675123; - - const unsigned int t = x ^ ( x << 11 ); - - // Rotate the static values (w rotation in return statement): - x = y; - y = z; - z = w; - - return w = w ^ ( w >> 19 ) ^ ( t ^ ( t >> 8 ) ); -} - -struct small_struct { - double *empty_field_1; - double unused_number; - unsigned int empty_field2; - double *empty_field_3; - int number; - unsigned int empty_field4; - - small_struct( const int num ) noexcept: number( num ) {}; -}; - -struct perfect_forwarding_test { - const bool success; - - perfect_forwarding_test( int && /*perfect1*/, int &perfect2 ) : success( true ) { - perfect2 = 1; - } - - template - perfect_forwarding_test( T && /*imperfect1*/, U && /*imperfect2*/ ) : success( false ) - {} -}; TEST_CASE( "list basics", "[list]" ) { @@ -293,7 +253,7 @@ TEST_CASE( "list basics", "[list]" ) } } -TEST_CASE( "list insert and erase" ) +TEST_CASE( "list insert and erase", "[list]" ) { cata::list test_list; @@ -656,8 +616,6 @@ TEST_CASE( "list sort and reverse", "[list]" ) CHECK( passed ); } } - - } TEST_CASE( "list unique", "[list]" ) From 4def91c6e8e223c5b5eba744841613407040ea51 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 7 Jul 2019 17:54:50 +0200 Subject: [PATCH 10/10] Fix namespace comment --- src/list.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/list.h b/src/list.h index 9470f162af3ed..2f9ca8a068282 100644 --- a/src/list.h +++ b/src/list.h @@ -2456,7 +2456,7 @@ inline void swap( list &a, a.swap( b ); } -} // cata namespace +} // namespace cata #undef LIST_BLOCK_MAX #undef LIST_BLOCK_MIN